diff --git a/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilter.h b/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..c0a5750a9ff705f4cac23c4d757bb97159b594de --- /dev/null +++ b/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilter.h @@ -0,0 +1,228 @@ +/*========================================================================= + +Program: ORFEO Toolbox +Language: C++ +Date: $Date$ +Version: $Revision$ + + +Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. +See OTBCopyright.txt for details. + +Copyright (c) CS Systemes d'information. All rights reserved. +See CSCopyright.txt for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef _otbImageToSURFKeyPointSetFilter_h +#define _otbImageToSURFKeyPointSetFilter_h + +#include "itkProcessObject.h" +#include "itkConstNeighborhoodIterator.h" +#include "otbImageToHessianDeterminantImageFilter.h" +#include "itkPointSet.h" +#include <itkRescaleIntensityImageFilter.h> +#include <otbImageList.h> +#include "itkResampleImageFilter.h" +#include "otbImageToPointSetFilter.h" + +#include "otbMath.h" + +/** \class ImageToSURFKeyPointSetFilter + * \brief This class extracts key points from an image through a pyramidal gaussian based decomposition + * + * This class implements the SURF Key point detector proposed by Tuytelaars and Vangool from the university + * of Leuven, 2005 + * + * \li Gaussian Second order derivative Hessian images are computed in each + * level and each octave for the input image. + * \li For each octave, an extremum search is launched on each 3 adjacent scales. + * \li The Key points detected are the ones extremum in the current , previous and + * next scale of reserach. 3 scales are needed for the computation (NumberOfScales >=3). + * \li Orientation and descriptors are computed for each key point detected. + * + * Selected Key Points are stored in an itk::PointSet structure. + * Points contains the coordinate of the detected point. + * DataPoints contain the values of the 64 element descriptor for each key point + * detected through the pyramidal analysis. + * + * Orientation is expressed in degree in the range of [0,360] + * + * \sa otb::ImageToDeterminantHessianImage + */ + +namespace otb +{ + template <class TInputImage , class TOutputPointSet> + class ITK_EXPORT ImageToSURFKeyPointSetFilter + : public ImageToPointSetFilter<TInputImage, TOutputPointSet> + { + + public: + + /** Standard class typedefs. */ + typedef ImageToSURFKeyPointSetFilter Self; + typedef ImageToPointSetFilter<TInputImage,TOutputPointSet> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(ImageToSURFKeyPointSetFilter,ImageToPointSetFilter); + + + /** Template parameters typedefs*/ + typedef TInputImage InputImageType; + typedef typename InputImageType::Pointer InputImagePointerType; + typedef typename InputImageType::IndexType PixelIndex ; + typedef typename InputImageType::IndexType IndexType; + typedef typename InputImageType::PixelType PixelValue; + typedef typename InputImageType::SpacingType SpacingType; + typedef typename InputImageType::SizeType SizeType; + typedef typename InputImageType::PointType PointImageType; + + typedef TOutputPointSet OutputPointSetType; + typedef typename TOutputPointSet::Pointer OutputPointSetPointerType; + typedef typename TOutputPointSet::PixelType OutputPixelType; + typedef typename TOutputPointSet::PointType OutputPointType; + typedef typename TOutputPointSet::PointIdentifier OutputPointIdentifierType; + + /** Set/Get the number of Octaves */ + itkSetMacro(OctavesNumber,int); + itkGetMacro(OctavesNumber,int); + + /** Set/Get the number of scales*/ + itkSetMacro(ScalesNumber,int); + itkGetMacro(ScalesNumber,int); + + /** Get the number of KeyPoints detected*/ + itkGetMacro(NumberOfPoints,int); + + /** Internal filters typedefs */ + typedef itk::ConstNeighborhoodIterator<InputImageType> NeighborhoodIteratorType; + typedef typename NeighborhoodIteratorType::NeighborhoodType NeighborhoodType; + + typedef otb::ImageToHessianDeterminantImageFilter<InputImageType ,InputImageType > ImageToDetHessianImageType; + typedef typename ImageToDetHessianImageType::Pointer DetHessianPointerFilter; + + /** Filter for resampling images for the multi-scale analysis */ + typedef itk::ResampleImageFilter<InputImageType,InputImageType> ResampleFilterType; + typedef typename ResampleFilterType::Pointer ResampleFilterPointerType; + + /** ImageList to store the Hessian determinant image at each scale (sigma width)*/ + typedef otb::ImageList< InputImageType > ImageListType; + typedef typename ImageListType::Pointer ImageListTypePointer; + + /** */ + typedef std::vector<double> VectorType; + + protected: + + /** + * Constructor. + */ + ImageToSURFKeyPointSetFilter(); + /** + * Destructor. + */ + virtual ~ImageToSURFKeyPointSetFilter(); + /** + * Standard PrintSelf method. + */ + virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; + /** + * Main computation method. + */ + virtual void GenerateData(); + + + + /** Check local extremum for 8 neighbors (current) + * + * \param currentScale + * + * \return true if the Central pixel is extremum + */ + virtual bool IsLocalExtremum(const NeighborhoodType& neigh); + + + + /** Check local extremum for 8 neighbors (Previous or Scale) + * + * \param neigh + * \paramCenterValue + * + * \return true if the Central pixel is extremum + */ + virtual bool IsLocalExtremumAround(const NeighborhoodType& neigh, + double CenterValue); + + + /** AssignOrientation + * + * \param currentScale neighborhood + * \param scale affected to the keypoint + * + * \return key point orientation + */ + virtual double AssignOrientation(const NeighborhoodType& neigh, + double S); + + /** ComputeDescriptor + * + * \param currentScale Neighboorhood + * \param orientation assigned to the key point + * \param scale + * + * \return hsitogram descriptor + */ + virtual VectorType ComputeDescriptor(const NeighborhoodType& neigh, + double O, + double S); + /** + * Compute min a b c + */ + virtual int GetMin( int a , int b , int c); + + private: + + ImageToSURFKeyPointSetFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + /** Number of octaves */ + int m_OctavesNumber; + + /** Number of scale for each octave */ + int m_ScalesNumber; + + /** Number of key points detected */ + int m_NumberOfPoints; + + /** Those images */ + InputImagePointerType m_determinantImage; + InputImagePointerType m_ImageCurrent; + InputImagePointerType m_ImageMovedPrev; + InputImagePointerType m_ImageMovedNext; + + /** ImageToDeterminantHessianFilter filter */ + DetHessianPointerFilter m_DetHessianFilter; + + /*Resample Filter*/ + ResampleFilterPointerType m_ResampleFilter; + + /** ImageList*/ + ImageListTypePointer m_ImageList; + }; +} +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbImageToSURFKeyPointSetFilter.txx" +#endif + +#endif + + diff --git a/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilter.txx b/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilter.txx new file mode 100644 index 0000000000000000000000000000000000000000..4d58522d7a9f052411fd4ec1461b677ac247af03 --- /dev/null +++ b/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilter.txx @@ -0,0 +1,527 @@ +/*========================================================================= + +Program: ORFEO Toolbox +Language: C++ +Date: $Date$ +Version: $Revision$ + + +Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. +See OTBCopyright.txt for details. + +Copyright (c) CS Systemes d'information. All rights reserved. +See CSCopyright.txt for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "otbImageToSURFKeyPointSetFilter.h" +#include "itkCenteredRigid2DTransform.h" + +namespace otb +{ + /**--------------------------------------------------------- + * Constructor + ----------------------------------------------------------*/ + template < class TInputImage, class TOutputPointSet > + ImageToSURFKeyPointSetFilter< TInputImage, TOutputPointSet > + ::ImageToSURFKeyPointSetFilter() + { + m_OctavesNumber = 1; + m_ScalesNumber = 3; + m_NumberOfPoints = 0; + m_DetHessianFilter = ImageToDetHessianImageType::New(); + } + + + /*--------------------------------------------------------- + * Destructor.c + ----------------------------------------------------------*/ + + template <class TInputImage, class TOutputPointSet> + ImageToSURFKeyPointSetFilter< TInputImage, TOutputPointSet> + ::~ImageToSURFKeyPointSetFilter() + {} + + /*------------------------------------------------------- + * Generate Data + --------------------------------------------------------*/ + template <class TInputImage, class TOutputPointSet> + void + ImageToSURFKeyPointSetFilter< TInputImage, TOutputPointSet> + ::GenerateData(void) + { + + + double k; + double sigma_in = 2.; + SizeType radius; + + /*Output*/ + OutputPointSetPointerType outputPointSet = this->GetOutput(); + + /** Computing the multiplicative factor for scales iteration + * scalar used for the wifth of the gaussian + */ + if(m_ScalesNumber > 1 ) + k = (double)std::pow(2.0,(double)(1/(double)(m_ScalesNumber-1))) ; + else + k = 3; + + + /* Computation loop over octaves*/ + for (int i = 0; i < m_OctavesNumber ; i++ ){ + + sigma_in = 2.; + m_ImageList = ImageListType::New(); + + /*-------------------------------------------------------- + Octave per octave + --------------------------------------------------------*/ + if(i>0) { + + m_ResampleFilter = ResampleFilterType::New(); + m_ResampleFilter ->SetInput(this->GetInput(0)); + + SizeType size = this->GetInput(0)->GetLargestPossibleRegion().GetSize(); + for (int k = 0; k < 2; ++k) + size[k] = (unsigned int) floor(size[k]/std::pow(2.0,i) ); + m_ResampleFilter->SetSize( size ); + + SpacingType spacing = this->GetInput(0)->GetSpacing(); + for (int k = 0; k < 2; ++k) + spacing[k] = (spacing[k] * std::pow(2.0,i)); + m_ResampleFilter->SetOutputSpacing( spacing ); + + m_ResampleFilter->SetDefaultPixelValue( 0 ); + m_ResampleFilter->Update(); + m_determinantImage = m_ResampleFilter->GetOutput(); + + otbGenericMsgDebugMacro( <<"ImageToSURFKeyPointSetFilter:: Size of the image at the octave : " \ + << i << " is " \ + <<m_determinantImage->GetLargestPossibleRegion().GetSize() ); + + } + + for (int j = 0 ; j < m_ScalesNumber; j++ ) + { + /** Incrementation of the gaussian width + * the width of the gaussian have to be doubled for + * each iteration over octaves + */ + + if ((i != 0 && j !=0 ) || (i == 0 && (i+j !=0) ) || ( m_ScalesNumber == 1 && i!=0 )) + sigma_in *= k; + + /** + * For each octave, we serach for the key points + */ + + /** Hessian Determinant Image */ + m_DetHessianFilter = ImageToDetHessianImageType::New(); + + if ( i == 0 )m_DetHessianFilter->SetInput(this->GetInput(0)); + else m_DetHessianFilter->SetInput(m_determinantImage ); + + m_DetHessianFilter->SetSigma(sigma_in); + m_DetHessianFilter->Update(); + m_determinantImage = m_DetHessianFilter->GetOutput() ; + + if(i+j==0) + otbGenericMsgDebugMacro( <<"ImageToSURFKeyPointSetFilter:: Size of the image at the octave : " \ + << i << " is " \ + <<m_determinantImage->GetLargestPossibleRegion().GetSize() ); + + + /** For each octave, we fill the imageList for the extremum search*/ + m_ImageList->PushBack(m_determinantImage); + } + + /*----------------------------------------------------*/ + /* extremum Search over octave's scales */ + /*----------------------------------------------------*/ + + for (int jj = 1 ; jj < (int)(m_ImageList->Size() - 1 ) ; jj++) + { + m_ImageCurrent = m_ImageList->GetNthElement(jj); + m_ImageMovedPrev = m_ImageList->GetNthElement(jj-1); + m_ImageMovedNext = m_ImageList->GetNthElement(jj+1); + + + /** NeighboorhoodIterator parameters*/ + radius.Fill(1); + NeighborhoodIteratorType it(radius, m_ImageCurrent,m_ImageCurrent->GetLargestPossibleRegion()); + it.GoToBegin(); + + + /* NeighboorhoodIterator Adjacents parameters*/ + NeighborhoodIteratorType itNeighPrev(radius, m_ImageMovedPrev,m_ImageMovedPrev->GetLargestPossibleRegion()); + itNeighPrev.GoToBegin(); + + NeighborhoodIteratorType itNeighNext(radius, m_ImageMovedNext,m_ImageMovedNext->GetLargestPossibleRegion()); + itNeighNext.GoToBegin(); + + while(!it.IsAtEnd()) + { + + if(IsLocalExtremum(it.GetNeighborhood()) + && IsLocalExtremumAround(itNeighPrev.GetNeighborhood(),m_ImageCurrent->GetPixel(it.GetIndex())) + && IsLocalExtremumAround(itNeighNext.GetNeighborhood(),m_ImageCurrent->GetPixel(it.GetIndex())) ) + { + OutputPointType keyPoint; + itNeighPrev.SetLocation(it.GetIndex()); + itNeighNext.SetLocation(it.GetIndex()); + + keyPoint[0] = it.GetIndex()[0]; + keyPoint[1] = it.GetIndex()[1]; + + //keyPoint[2] = sigma_in/pow(k,(double)jj)*pow(2.,(double)i); + double sigmaDetected = sigma_in/pow(k,(double)jj)*pow(2.,(double)i); + + radius.Fill(GetMin((int)(this->GetInput(0)->GetLargestPossibleRegion().GetSize()[0] - keyPoint[0]), + (int)(this->GetInput(0)->GetLargestPossibleRegion().GetSize()[1] - keyPoint[1]), + (int)(6*keyPoint[2]) ) ) ; + + + + /* + Computing the orientation of the key point detected + */ + NeighborhoodIteratorType itNeighOrientation(radius,this->GetInput(0) , + this->GetInput(0)->GetLargestPossibleRegion()); + + itNeighOrientation.SetLocation(it.GetIndex()); + + /** TO DO*/ + //keyPoint[3] = AssignOrientation( itNeighOrientation.GetNeighborhood() ,keyPoint[2] ); + double orientationDetected = AssignOrientation( itNeighOrientation.GetNeighborhood() , sigmaDetected ); + + /*Filling the Point pointSet Part*/ + outputPointSet->SetPoint(m_NumberOfPoints, keyPoint); + + + /*----------------------------------------*/ + /* Descriptor Computation */ + /*----------------------------------------*/ + + radius.Fill(GetMin((int)(this->GetInput(0)->GetLargestPossibleRegion().GetSize()[0] - keyPoint[0]), + (int)(this->GetInput(0)->GetLargestPossibleRegion().GetSize()[1] - keyPoint[1]), + (int)(10*sigmaDetected))); // TODO a changer sigmaDetected par Keypoint[2] + + NeighborhoodIteratorType itNeighDescriptor(radius,this->GetInput(0), + this->GetInput(0)->GetLargestPossibleRegion()); + itNeighDescriptor.SetLocation(it.GetIndex()); + VectorType descriptor; + //descriptor = ComputeDescriptor(itNeighDescriptor.GetNeighborhood(),keyPoint[3],keyPoint[2]); + descriptor = ComputeDescriptor(itNeighDescriptor.GetNeighborhood(),orientationDetected,sigmaDetected); + + + + /*Updating the pointset data with values of the descriptor*/ + OutputPixelType data; + data.SetSize(64); + + unsigned int IndDescriptor = 0; + + typename std::vector<double>::const_iterator itDescriptor = + descriptor.begin(); + + while(itDescriptor != descriptor.end()) + { + data.SetElement(IndDescriptor, *itDescriptor); + IndDescriptor++; + itDescriptor++; + } + outputPointSet->SetPointData(m_NumberOfPoints, data); + + m_NumberOfPoints++; + } + ++it; + ++itNeighPrev; + ++itNeighNext; + + }/*End while for extremum search*/ + + } /*End Iteration over scales */ + + m_ImageList->Clear(); + + } /* End Key Points search*/ + + otbGenericMsgDebugMacro( <<"ImageToSURFKeyPointSetFilter:: Total Number of Key points "\ + << m_NumberOfPoints ); + + }/** End of GenerateData()*/ + + template <class TInputImage, class TOutputPointSet> + int + ImageToSURFKeyPointSetFilter< TInputImage, TOutputPointSet> + ::GetMin( int a , int b , int c) + { + return std::min(a,std::min(b,c)); + } + + /*----------------------------------------------------------- + * Find Local Extremum + -----------------------------------------------------------*/ + template <class TInputImage, class TOutputPointSet> + bool + ImageToSURFKeyPointSetFilter< TInputImage, TOutputPointSet> + ::IsLocalExtremum(const NeighborhoodType& neigh) + { + int centerIndex = neigh.GetCenterNeighborhoodIndex(), i = 0; + double centerValue = neigh[centerIndex]; + bool max = false, min = false; + int flag_min = 0, flag_max = 0; + + while (i!=(int)neigh.Size()){ + if(i != centerIndex ){ + if( centerValue> neigh[i] & flag_max == 0) max = true; + else { max = false; flag_max = 1; } + + if(centerValue < neigh[i] & flag_min == 0 & centerValue <0) min = true; + else { min = false; flag_min = 1; } + } + ++i; + } + + return max || min ; + } + + /*----------------------------------------------------------- + *Find Local Extremum Around + -----------------------------------------------------------*/ + template <class TInputImage, class TOutputPointSet> + bool + ImageToSURFKeyPointSetFilter< TInputImage, TOutputPointSet> + ::IsLocalExtremumAround(const NeighborhoodType& neigh , double CenterValue) + { + + int i = 0; + bool max = false, min = false; + int flag_min = 0, flag_max = 0; + + while (i!=(int)neigh.Size()){ + + if( CenterValue> neigh[i] & flag_max == 0) max = true; + else { max = false; flag_max = 1; } + + if(CenterValue < neigh[i] & flag_min == 0) min = true; + else { min = false; flag_min = 1; } + + ++i; + } + + return max || min ; + } + + /*----------------------------------------------------------- + * Compute the orientation of The KeyPoint + -----------------------------------------------------------*/ + + template <class TInputImage, class TOutputPointSet> + double + ImageToSURFKeyPointSetFilter< TInputImage, TOutputPointSet> + ::AssignOrientation(const NeighborhoodType& neigh , double S) + { + + int i= 0 ; + int pas =( (i+S)-(int)(i+S) > 0.5 )?((int)S+1):(int)S ; + int Largeur = 2*neigh.GetRadius()[0]+1; // Width & length of a neighborhood + int rayon = neigh.GetRadius()[0]; // radius of the neigh + int col, raw ; + double dist ; + double w; // weight of the circular gaussian + + OutputPointType pt ; + + // Gradient orientation histogram + double angle; + int bin = 0 , Pi = 180; + int LengthBin = 60; + int NbBins = (2*Pi/LengthBin); + double tab[NbBins*2]; + + + while (i < (int)neigh.Size()) + { + col = i%Largeur - rayon ; + raw = i/Largeur - rayon ; + dist = sqrt(col *col + raw * raw ); + col +=rayon; + raw +=rayon; // Backup to the image coordinate axes + + if(dist < 6*S) + { + // Haar Wavelets responses accumulated in an histogram with Pi/3 precison + if (( col > pas && col < Largeur - pas ) && ( raw > pas && raw < Largeur - pas) ) + { + w = vcl_exp(-((col-rayon)*(col-rayon) + (raw-rayon)*(raw-rayon))/(2*2.5*2.5*S*S) ); + pt[0] = (neigh[(col+pas) + raw * Largeur] - neigh[(col-pas) + raw *Largeur ]) * w ; + pt[1] = (neigh[col + (raw+pas)* Largeur ] - neigh[col + (raw-pas)*Largeur]) * w; + + if (pt[0] + pt[1] != 0) + { + angle = atan( pt[0]/pt[1] )*( Pi/3.1415); + if(angle < 0 ) + angle += 2*Pi; + + bin = (int)(angle/LengthBin); + + if( bin <= NbBins-1 || bin >= 0 ) + { + tab[2*bin] += pt[0]; + tab[2*bin+1] += pt[1]; + } + } + } + } + i+= pas; + } + + //Find Orientation + double indice = 0; + double max = 0; + double length = 0; + + //Detection de l'orientation du point courant + for (int i = 0 ; i < NbBins*2 ; i = i+2){ + length = sqrt( tab[i]*tab[i] + tab[i+1]*tab[i+1] ); + if( length > max){ + max = length ; + indice = i/2; + } + } + + return (indice+0.5)*LengthBin; + } + + /*----------------------------------------------------------- + * Compute the descriptor of The KeyPoint + -----------------------------------------------------------*/ + + template <class TInputImage, class TOutputPointSet> + typename ImageToSURFKeyPointSetFilter< TInputImage, TOutputPointSet> + ::VectorType + ImageToSURFKeyPointSetFilter< TInputImage, TOutputPointSet> + ::ComputeDescriptor(const NeighborhoodType& neigh , double O , double S ) + { + + typedef itk::CenteredRigid2DTransform<double> TransformType; + TransformType::Pointer eulerTransform = TransformType::New(); + TransformType::ParametersType ParamVec(5); + PointImageType pSrc , pDst; + double angle = O * M_PI / 180; + + + + int i = 0, col, raw , Nbin, pas = 1 ; + double xx = 0, yy = 0; + double dx, dy , w ; + int Largeur = 2*neigh.GetRadius()[0]+1; + double rayon = static_cast<double>(Largeur)/4. ; + double r = neigh.GetRadius()[0]; + double dist = 0; + double x0 = neigh.GetCenterNeighborhoodIndex()% Largeur ; + double y0 = neigh.GetCenterNeighborhoodIndex()/ Largeur ; + + //std::cout << " x0 " << x0 << " y0 " << y0 << angle << std::endl; + + VectorType descriptorVector; + descriptorVector.resize(64); + + /** Parameters of the transformation*/ + ParamVec[0] = angle; + ParamVec[1] = x0; + ParamVec[2] = y0; + ParamVec[3] = 0; + ParamVec[4] = 0; + eulerTransform->SetParameters(ParamVec); + + int accumulator = 0; + while (i < (int)neigh.Size()) + { + col = i % Largeur ; + raw = i / Largeur ; + + if (( col > pas && col < Largeur - pas ) && ( raw > pas && raw < Largeur - pas) ) + { + double distanceX = (raw-r); + double distanceY = (col-r); + dist = vcl_sqrt(distanceX*distanceX + distanceY*distanceY); + + if(dist <= r ) + { + /* Transform point to compensate the rotation the orientation */ + pDst[0] = col; + pDst[1] = raw; + pSrc = eulerTransform->TransformPoint(pDst); + + /** New Coordinates (rotated) */ + col = static_cast<int>(vcl_floor(pSrc[0])); + raw = static_cast<int>(vcl_floor(pSrc[1])); + + if(raw==0) raw =+1; + if(col ==0) col +=1; + + xx = static_cast<int> (pSrc[1]/rayon); + yy = static_cast<int> (pSrc[0]/rayon); + + //Nbin = static_cast<int> ( vcl_floor(xx + 4 * yy) ) ; + Nbin = xx + 4*yy ; + + if( Nbin < 16) //because 64 descriptor length + { + double distanceXcompensee_2 = (pSrc[0] - r)*(pSrc[0] - r); + double distanceYcompensee_2 = (pSrc[1] - r)*(pSrc[1] - r); + + w = vcl_exp(-( distanceXcompensee_2 + distanceYcompensee_2 ) / (2*3.3*3.3*S*S) ); + //w = vcl_exp(-( (pSrc[0] - r)*(pSrc[0] -r) + (pSrc[1] - r)*(pSrc[1] - r) )/(2*3.3*3.3/**S*S*/)); + + dx = 0.5 * (neigh[(col+pas) + raw * Largeur] - neigh[(col-pas) + raw *Largeur]) * w ; + dy = 0.5 * (neigh[col + (raw+ pas)* Largeur] - neigh[col + (raw-pas)*Largeur]) * w; + + descriptorVector[4*Nbin ] += dx ; + descriptorVector[4*Nbin+1] += dy ; + descriptorVector[4*Nbin+2] += vcl_abs(dx) ; + descriptorVector[4*Nbin+3] += vcl_abs(dy) ; + } + else + { + accumulator++; + //std::cout << " xx "<< xx << " yy " << yy << " Nbin " << Nbin << " rayon "<< rayon << " pSrc[1] " << pSrc[1] << " pSrc[0] " <<pSrc[0] << " pDst[0] " << pDst[0] <<" pDst[1] " << pDst[1] << " Largeur "<< Largeur << std::endl; + } + } + } + i++; + } + + if(accumulator > 0 ) std::cout << " accumulator "<< accumulator << " / "<< i << std::endl; + + + double accu = 0; + for (int i = 0 ; i < 64 ; i++) + accu += descriptorVector[i]*descriptorVector[i]; + + for (int j = 0 ; j < 64 ; j++) + descriptorVector[j] /= vcl_sqrt(accu) ; + + return descriptorVector; + + } + + /*---------------------------------------------------------------- + PrintSelf + -----------------------------------------------------------------*/ + template <class TInputImage, class TOutputPointSet > + void + ImageToSURFKeyPointSetFilter< TInputImage, TOutputPointSet> + ::PrintSelf(std::ostream& os, itk::Indent indent) const + { + Superclass::PrintSelf(os, indent); + os << indent << "Number of Key Points " << m_NumberOfPoints << std::endl; + } +} diff --git a/Testing/Code/FeatureExtraction/CMakeLists.txt b/Testing/Code/FeatureExtraction/CMakeLists.txt index 16147db51985b2cac75d32dd63de899be25edaba..f3ff009c402da4ef6f240a5750ed5c7762f9d046 100644 --- a/Testing/Code/FeatureExtraction/CMakeLists.txt +++ b/Testing/Code/FeatureExtraction/CMakeLists.txt @@ -839,10 +839,36 @@ ADD_TEST(feTvImageToHessianDeterminantImageFilter ${FEATUREEXTRACTION_TESTS9} ${TEMP}/feTvImageToHessianDeterminantImageFilterOutput.tif 1.5 ) - -# ------- otb::ImageFittingPolygonListFilter ------------- -ADD_TEST(feTuImageFittingPolygonListFilterNew ${FEATUREEXTRACTION_TESTS9} - otbImageFittingPolygonListFilterNew) + +# ------- otb::ImageToSURFKeyPointSetFilterNew ------------- + +ADD_TEST(feTuImageToSURFKeyPointSetFilterNew ${FEATUREEXTRACTION_TESTS9} + otbImageToSURFKeyPointSetFilterNew) + + +ADD_TEST(feTvImageToSURFKeyPointSetFilterSceneOutputImage ${FEATUREEXTRACTION_TESTS9} +--compare-image ${EPSILON} + ${BASELINE}/feTvImageToSURFKeyPointSetFilterSceneImageOutput.png + ${TEMP}/feTvImageToSURFKeyPointSetFilterSceneImageOutput.png + otbImageToSURFKeyPointSetFilterOutputImage + ${INPUTDATA}/scene.png + ${TEMP}/feTvImageToSURFKeyPointSetFilterSceneImageOutput.png + 1 3 +) + +ADD_TEST(feTvImageToSURFKeyPointSetFilterSceneOutputAscii ${FEATUREEXTRACTION_TESTS9} +--compare-ascii ${EPS} + ${BASELINE_FILES}/feTvImageToSURFKeyPointSetFilterSceneKeysOutput.txt + ${TEMP}/feTvImageToSURFKeyPointSetFilterSceneKeysOutput.txt + otbImageToSURFKeyPointSetFilterOutputAscii + ${INPUTDATA}/scene.png + ${TEMP}/feTvImageToSURFKeyPointSetFilterSceneKeysOutput.txt + 1 3 +) + + + + # A enrichir SET(BasicFeatureExtraction_SRCS1 @@ -948,7 +974,10 @@ otbImageToSIFTKeyPointSetFilterOutputImage.cxx otbImageToSIFTKeyPointSetFilterOutputAscii.cxx otbImageToHessianDeterminantImageFilterNew.cxx otbImageToHessianDeterminantImageFilter.cxx -otbImageFittingPolygonListFilterNew.cxx +otbImageToSURFKeyPointSetFilterNew.cxx +otbImageToSURFKeyPointSetFilterOutputImage.cxx +otbImageToSURFKeyPointSetFilterOutputAscii.cxx +#otbImageToSURFKeyPointSetFilterDistanceMap.cxx ) INCLUDE_DIRECTORIES("${OTBTesting_BINARY_DIR}") diff --git a/Testing/Code/FeatureExtraction/otbFeatureExtractionTests9.cxx b/Testing/Code/FeatureExtraction/otbFeatureExtractionTests9.cxx index 9b4221b808cf1c489e92c082fbe1be9076307aeb..359428b9e59a911acbde11ab3faba4cebb9a84f7 100644 --- a/Testing/Code/FeatureExtraction/otbFeatureExtractionTests9.cxx +++ b/Testing/Code/FeatureExtraction/otbFeatureExtractionTests9.cxx @@ -35,6 +35,8 @@ REGISTER_TEST(otbImageToSIFTKeyPointSetFilterOutputAscii); //REGISTER_TEST(otbImageToSIFTKeyPointSetFilterValid); REGISTER_TEST(otbImageToHessianDeterminantImageFilterNew); REGISTER_TEST(otbImageToHessianDeterminantImageFilter); -REGISTER_TEST(otbImageFittingPolygonListFilterNew); - +REGISTER_TEST(otbImageToSURFKeyPointSetFilterNew); +REGISTER_TEST(otbImageToSURFKeyPointSetFilterOutputImage); +REGISTER_TEST(otbImageToSURFKeyPointSetFilterOutputAscii); +//REGISTER_TEST(otbImageToSURFKeyPointSetFilterDistanceMap); } diff --git a/Testing/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilterDistanceMap.cxx b/Testing/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilterDistanceMap.cxx new file mode 100644 index 0000000000000000000000000000000000000000..7f39a02e92389ae529b5599456f3af491342ec46 --- /dev/null +++ b/Testing/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilterDistanceMap.cxx @@ -0,0 +1,346 @@ +/*========================================================================= + +Program: ORFEO Toolbox +Language: C++ +Date: $Date$ +Version: $Revision$ + + +Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. +See OTBCopyright.txt for details. + +Copyright (c) CS Systemes d'information. All rights reserved. +See CSCopyright.txt for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include <iostream> +#include <fstream> + +#include "itkPointSet.h" +#include "itkImageRegionIterator.h" +#include "itkVariableLengthVector.h" +#include "itkResampleImageFilter.h" +#include "itkDanielssonDistanceMapImageFilter.h" +#include "itkSubtractImageFilter.h" +#include "itkMinimumMaximumImageCalculator.h" +#include "itkShrinkImageFilter.h" +#include "itkExpandImageFilter.h" +#include "itkPointSetToImageFilter.h" +#include "itkRescaleIntensityImageFilter.h" + +#include "otbImageToSURFKeyPointSetFilter.h" +#include "otbImage.h" +#include "otbImageFileReader.h" +#include "otbImageFileWriter.h" + +typedef itk::VariableLengthVector<float> RealVectorType; +typedef itk::PointSet<RealVectorType,2> PointSetType; +typedef otb::Image<float,2> ImageType; +typedef otb::Image<unsigned char, 2> OutputImageType; + +// PointSet iterator types +typedef PointSetType::PointsContainer PointsContainerType; +typedef PointsContainerType::Iterator PointsIteratorType; +typedef PointSetType::PointDataContainer PointDataContainerType; +typedef PointDataContainerType::Iterator PointDataIteratorType; + +// Filter +typedef otb::ImageFileReader<ImageType> ReaderType; +typedef otb::ImageFileWriter<OutputImageType> WriterType; +typedef otb::ImageFileWriter<ImageType> WriterInputType; + +OutputImageType::Pointer surf(ImageType::Pointer input, + const unsigned int octaves, + const unsigned int scales, + const char* surfFileName) +{ + typedef otb::ImageToSURFKeyPointSetFilter<ImageType,PointSetType> SurfFilterType; + typedef itk::PointSetToImageFilter<PointSetType, OutputImageType> PointSetFilterType; + + SurfFilterType::Pointer surf = SurfFilterType::New(); + PointSetFilterType::Pointer pointSetFilter = PointSetFilterType::New(); + + surf->SetInput(0,input); + surf->SetOctavesNumber(octaves); + surf->SetScalesNumber(scales); + + + pointSetFilter->SetInput(surf->GetOutput()); + pointSetFilter->SetOutsideValue(0); + pointSetFilter->SetInsideValue(255); + pointSetFilter->SetSize(input->GetLargestPossibleRegion().GetSize()); + pointSetFilter->SetSpacing(input->GetSpacing()); + pointSetFilter->SetOrigin(input->GetOrigin()); + pointSetFilter->Update(); + + WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(surfFileName); + writer->SetInput(pointSetFilter->GetOutput()); + writer->Update(); + + return pointSetFilter->GetOutput(); +} + +OutputImageType::Pointer ddm( OutputImageType::Pointer input, + const char* ddmFileName) +{ + typedef itk::DanielssonDistanceMapImageFilter <OutputImageType, OutputImageType> DDMFilterType; + DDMFilterType::Pointer ddmFilter = DDMFilterType::New(); + + ddmFilter->SetInput(input); + ddmFilter->InputIsBinaryOn(); + ddmFilter->Update(); + + WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(ddmFileName); + writer->SetInput(ddmFilter->GetOutput()); + writer->Update(); + + return ddmFilter->GetOutput(); +} + +ImageType::Pointer rotate( ImageType::Pointer input, + const unsigned int rotation) +{ + typedef itk::AffineTransform<double, 2> TransformType; + typedef itk::ResampleImageFilter<ImageType, ImageType> + ResampleFilterType; + ResampleFilterType::Pointer resampler = ResampleFilterType::New(); + + TransformType::Pointer transform = TransformType::New(); + TransformType::OutputVectorType translation1; + TransformType::OutputVectorType translation2; + + const ImageType::SpacingType& spacing = input->GetSpacing(); + const ImageType::PointType& origin = input->GetOrigin(); + ImageType::SizeType size = input->GetLargestPossibleRegion().GetSize(); + + const double imageCenterX = origin[0] + spacing[0] * size[0] / 2.0; + const double imageCenterY = origin[1] + spacing[1] * size[1] / 2.0; + const double degreesToRadians = atan(1.0) / 45.0; + const double angle = rotation * degreesToRadians; + + translation1[0] = -imageCenterX; + translation1[1] = -imageCenterY; + translation2[0] = imageCenterX; + translation2[1] = imageCenterY; + + transform->Translate( translation1 ); + transform->Rotate2D( -angle, false ); + transform->Translate( translation2 ); + + resampler->SetOutputOrigin( origin ); + resampler->SetOutputSpacing( spacing ); + resampler->SetSize( size ); + resampler->SetTransform(transform); + resampler->SetInput(input); + resampler->Update(); + return resampler->GetOutput(); +} + +OutputImageType::Pointer invRotate(OutputImageType::Pointer input, + const unsigned int rotation) +{ + typedef itk::AffineTransform<double, 2> TransformType; + typedef itk::ResampleImageFilter<OutputImageType, OutputImageType> + ResampleFilterType; + ResampleFilterType::Pointer resampler = ResampleFilterType::New(); + + TransformType::Pointer transform = TransformType::New(); + TransformType::OutputVectorType translation1; + TransformType::OutputVectorType translation2; + + const ImageType::SpacingType& spacing = input->GetSpacing(); + const ImageType::PointType& origin = input->GetOrigin(); + ImageType::SizeType size = input->GetLargestPossibleRegion().GetSize(); + + const double imageCenterX = origin[0] + spacing[0] * size[0] / 2.0; + const double imageCenterY = origin[1] + spacing[1] * size[1] / 2.0; + + const double degreesToRadians = atan(1.0) / 45.0; + const double angle = rotation * degreesToRadians; + + translation1[0] = -imageCenterX; + translation1[1] = -imageCenterY; + translation2[0] = imageCenterX; + translation2[1] = imageCenterY; + + transform->Translate( translation1 ); + transform->Rotate2D( angle, false ); + transform->Translate( translation2 ); + + resampler->SetOutputOrigin( origin ); + resampler->SetOutputSpacing( spacing ); + resampler->SetSize( size ); + resampler->SetTransform(transform); + resampler->SetInput(input); + resampler->Update(); + return resampler->GetOutput(); +} + +ImageType::Pointer zoom( ImageType::Pointer input, + const unsigned int zoomFactor) +{ + typedef itk::ShrinkImageFilter<ImageType, ImageType> ShrinkFilterType; + ShrinkFilterType::Pointer shrink = ShrinkFilterType::New(); + + shrink->SetInput(input); + shrink->SetShrinkFactors(zoomFactor); + shrink->Update(); + + return shrink->GetOutput(); +} + +OutputImageType::Pointer invZoom( OutputImageType::Pointer input, + const unsigned int zoomFactor) +{ + typedef itk::ExpandImageFilter<OutputImageType, OutputImageType> ExpandFilterType; + ExpandFilterType::Pointer expand = ExpandFilterType::New(); + + expand->SetInput(input); + expand->SetExpandFactors(zoomFactor); + expand->Update(); + + return expand->GetOutput(); +} + +ImageType::Pointer contrast(ImageType::Pointer input, + const unsigned int contrastMin, + const unsigned int contrastMax) +{ + typedef itk::RescaleIntensityImageFilter<ImageType, ImageType> RescaleFilterType; + RescaleFilterType::Pointer rescaler= RescaleFilterType::New(); + + rescaler->SetInput(input); + rescaler->SetOutputMinimum(static_cast<RescaleFilterType::OutputPixelType>(contrastMin)); + rescaler->SetOutputMaximum(static_cast<RescaleFilterType::OutputPixelType>(contrastMax)); + rescaler->Update(); + return rescaler->GetOutput(); +} + +OutputImageType::Pointer invContrast( OutputImageType::Pointer input, + const unsigned int contrastMin, + const unsigned int contrastMax) +{ + return input; +} + +void subtract(OutputImageType::Pointer image1, + OutputImageType::Pointer image2, + const char* subtractFileName) +{ + typedef itk::SubtractImageFilter<OutputImageType, OutputImageType, ImageType> SubtractFilterType; + typedef itk::MinimumMaximumImageCalculator<ImageType> MaximumCalculatorType; + typedef itk::RescaleIntensityImageFilter<ImageType, OutputImageType> OutputRescaleFilterType; + + SubtractFilterType::Pointer subtract = SubtractFilterType::New(); + MaximumCalculatorType::Pointer maximumCalculator = MaximumCalculatorType::New(); + + subtract->SetInput1(image1); + subtract->SetInput2(image2); + subtract->Update(); + + OutputRescaleFilterType::Pointer rescaler = OutputRescaleFilterType::New(); + rescaler->SetInput(subtract->GetOutput()); + rescaler->SetOutputMinimum(0); + rescaler->SetOutputMaximum(255); + + WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(subtractFileName); + writer->SetInput(rescaler->GetOutput()); + writer->Update(); + + maximumCalculator->SetImage(subtract->GetOutput()); + maximumCalculator->Compute(); + + std::cout << "Mix(sub)= " << maximumCalculator->GetMinimum() << " "; + std::cout << "Max(sub)= " << maximumCalculator->GetMaximum() << std::endl; +} + +int otbImageToSURFKeyPointSetFilterDistanceMap(int argc, char * argv[]) +{ + // Input Image file name + const char * infname = argv[1]; + + const unsigned int octaves = atoi(argv[2]); + const unsigned int scales = atoi(argv[3]); + + // Rotation angle [0,360[ + const unsigned int rotation = atoi(argv[6]); + + // Zoom factor + const unsigned int zoomFactor = atoi(argv[7]); + + // contrast factor + const unsigned int contrastMin = atoi(argv[8]); + const unsigned int contrastMax = atoi(argv[9]); + + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(infname); + reader->Update(); + + ImageType::Pointer _rotated = + rotate(reader->GetOutput(), rotation); + ImageType::Pointer _zoomed = + zoom(reader->GetOutput(), zoomFactor); + ImageType::Pointer _contrasted = + contrast(reader->GetOutput(), contrastMin, contrastMax); + + ImageType::Pointer _combined1 = zoom(_rotated, zoomFactor); + ImageType::Pointer _combined2 = contrast(_combined1, contrastMin, contrastMax); + + OutputImageType::Pointer surf_base = + surf(reader->GetOutput(), octaves, scales, "surf_base.png"); + + OutputImageType::Pointer _surf_rotated = + surf(_rotated, octaves, scales ,"surf_rotated.png"); + + OutputImageType::Pointer _surf_zoomed = + surf(_zoomed, octaves, scales, "surf_zoomed.png"); + + OutputImageType::Pointer _surf_contrasted = + surf(_contrasted, octaves, scales, "surf_contrasted.png"); + + OutputImageType::Pointer _surf_combined = + surf(_combined2, octaves, scales, "surf_combined.png"); + + OutputImageType::Pointer surf_rotated = + invRotate(_surf_rotated, rotation); + + OutputImageType::Pointer surf_zoomed = + invZoom(_surf_zoomed, zoomFactor); + + OutputImageType::Pointer surf_contrasted = + invContrast(_surf_contrasted, contrastMin, contrastMax); + + OutputImageType::Pointer _surf_combined1 = + invContrast(_surf_combined, contrastMin, contrastMax); + OutputImageType::Pointer _surf_combined2 = + invRotate(_surf_combined1, rotation); + OutputImageType::Pointer surf_combined = + invZoom(_surf_combined2, zoomFactor); + + OutputImageType::Pointer ddm_base = ddm(surf_base, "ddm_base.png"); + OutputImageType::Pointer ddm_rotated = ddm(surf_rotated, "ddm_rotated.png"); + OutputImageType::Pointer ddm_contrasted = ddm(surf_contrasted, "ddm_contrasted.png"); + OutputImageType::Pointer ddm_zoomed = ddm(surf_zoomed, "ddm_zoomed.png"); + OutputImageType::Pointer ddm_combined = ddm(surf_combined, "ddm_combined.png"); + + subtract(ddm_base, ddm_rotated, + "subtract_rotated.png"); + + subtract(ddm_base, ddm_zoomed, + "subtract_zoomed.png"); + + subtract(ddm_base, ddm_contrasted, + "subtract_contrasted.png"); + + subtract(ddm_base, ddm_combined, + "subtract_combined.png"); + + return EXIT_SUCCESS; +} diff --git a/Testing/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilterNew.cxx b/Testing/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilterNew.cxx new file mode 100644 index 0000000000000000000000000000000000000000..17907339e5c1b16d72e59378465dd9622c6b8c87 --- /dev/null +++ b/Testing/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilterNew.cxx @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.txt for details. + + Copyright (c) CS Systemes d'information. All rights reserved. + See CSCopyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "otbImageToSURFKeyPointSetFilter.h" +#include "otbImage.h" +#include "itkPointSet.h" +#include "itkVariableLengthVector.h" + + +int otbImageToSURFKeyPointSetFilterNew(int argc, char * argv[]) +{ + const unsigned int Dimension = 2; + typedef double PixelType; + + typedef otb::Image<PixelType,Dimension> ImageType; + typedef itk::VariableLengthVector<PixelType> RealVectorType; + typedef itk::PointSet<RealVectorType,Dimension> PointSetType; + typedef otb::ImageToSURFKeyPointSetFilter<ImageType,PointSetType> FilterType; + + // Instantiating object + FilterType::Pointer object = FilterType::New(); + + + return EXIT_SUCCESS; +} diff --git a/Testing/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilterOutputAscii.cxx b/Testing/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilterOutputAscii.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1397137f01b4c026a3c82ed2aa5a91821acf6db0 --- /dev/null +++ b/Testing/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilterOutputAscii.cxx @@ -0,0 +1,102 @@ +/*========================================================================= + +Program: ORFEO Toolbox +Language: C++ +Date: $Date$ +Version: $Revision$ + + +Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. +See OTBCopyright.txt for details. + +Copyright (c) CS Systemes d'information. All rights reserved. +See CSCopyright.txt for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "otbImageToSURFKeyPointSetFilter.h" +#include "otbImage.h" +#include "otbImageFileReader.h" +#include "otbImageFileWriter.h" +#include "itkPointSet.h" +#include "itkVariableLengthVector.h" +#include "otbRationalQuotientResampleImageFilter.h" +#include "itkRGBPixel.h" +#include "itkImageRegionIterator.h" + +#include <iostream> +#include <fstream> + +int otbImageToSURFKeyPointSetFilterOutputAscii(int argc, char * argv[]) +{ + + if(argc < 5 ) + { + std::cout << " Usage : otbSURFTest imageName FileOutName Octave[int] Level[int]" << std::endl; + return EXIT_FAILURE; + } + + const char * infname = argv[1]; + const char * outfname = argv[2]; + + const unsigned int octaves = atoi(argv[3]); + const unsigned int scales = atoi(argv[4]); + + + typedef float RealType; + const unsigned int Dimension =2; + + typedef otb::Image<RealType,Dimension> ImageType; + typedef itk::VariableLengthVector<RealType> RealVectorType; + typedef otb::ImageFileReader<ImageType> ReaderType; + typedef itk::PointSet<RealVectorType,Dimension> PointSetType; + typedef otb::ImageToSURFKeyPointSetFilter<ImageType,PointSetType> ImageToSURFKeyPointSetFilterType; + + // PointSet iterator types + typedef PointSetType::PointsContainer PointsContainerType; + typedef PointsContainerType::Iterator PointsIteratorType; + typedef PointSetType::PointDataContainer PointDataContainerType; + typedef PointDataContainerType::Iterator PointDataIteratorType; + + // Instantiating object + ReaderType::Pointer reader = ReaderType::New(); + ImageToSURFKeyPointSetFilterType::Pointer filter = ImageToSURFKeyPointSetFilterType::New(); + + reader->SetFileName(infname); + filter->SetInput(0,reader->GetOutput()); + filter->SetOctavesNumber(octaves); + filter->SetScalesNumber(scales); + filter->Update(); + + PointsIteratorType pIt = filter->GetOutput()->GetPoints()->Begin(); + PointDataIteratorType pDataIt = filter->GetOutput()->GetPointData()->Begin(); + + std::ofstream outfile(outfname); + + outfile << "Number of octaves: "<<octaves << std::endl; + outfile << "Number of scales: "<<scales << std::endl; + outfile << "Number of SURF key points: " << filter->GetNumberOfPoints() << std::endl; + + while( pIt!=filter->GetOutput()->GetPoints()->End() ) + { + outfile << "[" << std::fixed << std::setprecision(2) << pIt.Value()[0] << ", " << std::setprecision(2) << pIt.Value()[1] << "]["; + + unsigned int lIterDesc=0; + + while (lIterDesc < pDataIt.Value().Size()) + { + outfile << std::setprecision(3) << pDataIt.Value()[lIterDesc] << " "; + lIterDesc++; + } + outfile << "]" << std::endl; + ++pIt; + ++pDataIt; + } + + outfile.close(); + + return EXIT_SUCCESS; +} diff --git a/Testing/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilterOutputImage.cxx b/Testing/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilterOutputImage.cxx new file mode 100644 index 0000000000000000000000000000000000000000..7cb1117af47e1a2313214760c93f1b6c812bd66e --- /dev/null +++ b/Testing/Code/FeatureExtraction/otbImageToSURFKeyPointSetFilterOutputImage.cxx @@ -0,0 +1,167 @@ +/*========================================================================= + +Program: ORFEO Toolbox +Language: C++ +Date: $Date$ +Version: $Revision$ + + +Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. +See OTBCopyright.txt for details. + +Copyright (c) CS Systemes d'information. All rights reserved. +See CSCopyright.txt for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "otbImageToSURFKeyPointSetFilter.h" +#include "otbImage.h" +#include "otbImageFileReader.h" +#include "otbImageFileWriter.h" +#include "itkPointSet.h" +#include "itkVariableLengthVector.h" +#include "otbRationalQuotientResampleImageFilter.h" +#include "itkRGBPixel.h" +#include "itkImageRegionIterator.h" + +#include <iostream> +#include <fstream> + +int otbImageToSURFKeyPointSetFilterOutputImage(int argc, char * argv[]) +{ + const char * infname = argv[1]; + const char * outputImageFilename = argv[2]; + + const unsigned int octaves = atoi(argv[3]); + const unsigned int scales = atoi(argv[4]); + + typedef float RealType; + const unsigned int Dimension =2; + + typedef otb::Image<RealType,Dimension> ImageType; + typedef itk::VariableLengthVector<RealType> RealVectorType; + typedef otb::ImageFileReader<ImageType> ReaderType; + typedef itk::PointSet<RealVectorType,Dimension> PointSetType; + typedef otb::ImageToSURFKeyPointSetFilter<ImageType,PointSetType> ImageToSURFKeyPointSetFilterType; + + // PointSet iterator types + typedef PointSetType::PointsContainer PointsContainerType; + typedef PointsContainerType::Iterator PointsIteratorType; + + // Instantiating object + ReaderType::Pointer reader = ReaderType::New(); + ImageToSURFKeyPointSetFilterType::Pointer filter = ImageToSURFKeyPointSetFilterType::New(); + + reader->SetFileName(infname); + filter->SetInput(0,reader->GetOutput()); + filter->SetOctavesNumber(octaves); + filter->SetScalesNumber(scales); + + filter->Update(); + + ImageType::OffsetType t = {{ 0, 1}}; + ImageType::OffsetType b = {{ 0,-1}}; + ImageType::OffsetType l = {{ 1, 0}}; + ImageType::OffsetType r = {{-1, 0}}; + + typedef unsigned char PixelType; + typedef otb::Image<PixelType,2> UCharImageType; + + typedef itk::RGBPixel<PixelType> RGBPixelType; + typedef otb::Image<RGBPixelType, 2> OutputImageType; + + typedef otb::ImageFileWriter<OutputImageType> WriterType; + OutputImageType::Pointer outputImage = OutputImageType::New(); + OutputImageType::RegionType region; + + OutputImageType::SizeType outputSize; + outputSize[0] = reader->GetOutput()->GetLargestPossibleRegion().GetSize()[0]; + outputSize[1] = reader->GetOutput()->GetLargestPossibleRegion().GetSize()[1]; + region.SetSize(outputSize); + + OutputImageType::IndexType indexStart; + indexStart[0] = 0; + indexStart[1] = 0; + region.SetIndex(indexStart); + + outputImage->SetRegions(region); + outputImage->Allocate(); + + itk::ImageRegionIterator<OutputImageType> iterOutput(outputImage, + outputImage->GetLargestPossibleRegion()); + itk::ImageRegionIterator<ImageType> iterInput(reader->GetOutput(), + reader->GetOutput()->GetLargestPossibleRegion()); + + for (iterOutput.GoToBegin(), iterInput.GoToBegin(); + !iterOutput.IsAtEnd(); + ++iterOutput, ++iterInput) + { + OutputImageType::PixelType rgbPixel; + rgbPixel.SetRed( static_cast<PixelType>(iterInput.Get()) ); + rgbPixel.SetGreen( static_cast<PixelType>(iterInput.Get()) ); + rgbPixel.SetBlue( static_cast<PixelType>(iterInput.Get()) ); + + iterOutput.Set(rgbPixel); + } + + WriterType::Pointer writerTmp = WriterType::New(); + writerTmp->SetFileName(outputImageFilename); + writerTmp->SetInput(outputImage); + writerTmp->Update(); + + std::cout << "Copy Input image in Output image" << std::endl; + + PointsIteratorType pIt = filter->GetOutput()->GetPoints()->Begin(); + ImageType::SpacingType spacing = reader->GetOutput()->GetSpacing(); + ImageType::PointType origin = reader->GetOutput()->GetOrigin(); + OutputImageType::SizeType size = outputImage->GetLargestPossibleRegion().GetSize(); + + while( pIt != filter->GetOutput()->GetPoints()->End() ) + { + ImageType::IndexType index; + + index[0] = (unsigned int) + (vcl_floor + ((double)((pIt.Value()[0]-origin[0])/spacing[0]+0.5))); + + index[1] = (unsigned int) + (vcl_floor + ((double)((pIt.Value()[1]-origin[1])/spacing[1]+0.5))); + + OutputImageType::PixelType keyPixel; + keyPixel.SetRed(0); + keyPixel.SetGreen(255); + keyPixel.SetBlue(0); + + if (outputImage->GetLargestPossibleRegion().IsInside(index)) + { + outputImage->SetPixel(index,keyPixel); + + if (outputImage->GetLargestPossibleRegion().IsInside(index+t)) + outputImage->SetPixel(index+t,keyPixel); + + if (outputImage->GetLargestPossibleRegion().IsInside(index+b)) + outputImage->SetPixel(index+b,keyPixel); + + if (outputImage->GetLargestPossibleRegion().IsInside(index+l)) + outputImage->SetPixel(index+l,keyPixel); + + if (outputImage->GetLargestPossibleRegion().IsInside(index+r)) + outputImage->SetPixel(index+r,keyPixel); + } + ++pIt; + } + + std::cout << "Copy sift key" << std::endl; + + WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(outputImageFilename); + writer->SetInput(outputImage); + writer->Update(); + + std::cout << "Write image" << std::endl; + return EXIT_SUCCESS; +}