From fe76949f3cd163b86286152ef4acdea5ee5c00c4 Mon Sep 17 00:00:00 2001 From: Julien Michel <julien.michel@c-s.fr> Date: Tue, 9 Sep 2008 14:48:58 +0000 Subject: [PATCH] ENH; Final commit of the Mean Shift edge preserving smoothing filter. Including a base class, the Image version, the VectorImage version, and all the associated testings. --- Code/BasicFilters/otbMeanShiftImageFilter.h | 86 ++++++ Code/BasicFilters/otbMeanShiftImageFilter.txx | 60 ++++ .../otbMeanShiftImageFilterBase.h | 168 ++++++++++++ .../otbMeanShiftImageFilterBase.txx | 259 ++++++++++++++++++ .../otbMeanShiftVectorImageFilter.h | 134 ++++----- .../otbMeanShiftVectorImageFilter.txx | 235 ++-------------- Testing/Code/BasicFilters/CMakeLists.txt | 32 ++- .../BasicFilters/otbBasicFiltersTests9.cxx | 4 +- .../BasicFilters/otbMeanShiftImageFilter.cxx | 67 +++++ .../otbMeanShiftImageFilterNew.cxx | 32 +++ .../otbMeanShiftVectorImageFilter.cxx | 2 +- .../otbMeanShiftVectorImageFilterNew.cxx | 2 +- 12 files changed, 774 insertions(+), 307 deletions(-) create mode 100644 Code/BasicFilters/otbMeanShiftImageFilter.h create mode 100644 Code/BasicFilters/otbMeanShiftImageFilter.txx create mode 100644 Code/BasicFilters/otbMeanShiftImageFilterBase.h create mode 100644 Code/BasicFilters/otbMeanShiftImageFilterBase.txx create mode 100644 Testing/Code/BasicFilters/otbMeanShiftImageFilter.cxx create mode 100644 Testing/Code/BasicFilters/otbMeanShiftImageFilterNew.cxx diff --git a/Code/BasicFilters/otbMeanShiftImageFilter.h b/Code/BasicFilters/otbMeanShiftImageFilter.h new file mode 100644 index 0000000000..5bd5119726 --- /dev/null +++ b/Code/BasicFilters/otbMeanShiftImageFilter.h @@ -0,0 +1,86 @@ +/*========================================================================= + +Program: ORFEO Toolbox +Language: C++ +Date: $Date$ +Version: $Revision$ + + +Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. +See OTBCopyright.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 _otbMeanShiftImageFilter_h +#define _otbMeanShiftImageFilter_h + +#include "otbMeanShiftImageFilterBase.h" + +namespace otb +{ + /** \class MeanShiftImageFilter + * + * This is the implementation of the mean shift edge-preserving smoothing filter adapted to + * otb::Image or itk::Image. For the full documentation, please refer to the + * base class otb::MeanShiftImageFilterBase. + * + * \sa MeanShiftImageFilterBase + * \ingroup ImageEnhancement + * \ingroup Streamed + * \ingroup Threaded + */ +template <class TInputImage, class TOutputImage, class TPrecision = double> +class ITK_EXPORT MeanShiftImageFilter +: public MeanShiftImageFilterBase<TInputImage,TOutputImage,TPrecision> + { + public: + /** Standard class typedef */ + typedef MeanShiftImageFilter Self; + typedef MeanShiftImageFilterBase<TInputImage, + TOutputImage,TPrecision> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + // Precision pixel type + typedef typename Superclass::PrecisionPixelType PrecisionPixelType; + + /** New and Type macros */ + itkNewMacro(Self); + itkTypeMacro(MeanShiftImageFilter,MeanShiftImageFilterBase); + + protected: + /** Constructor */ + MeanShiftImageFilter(){}; + + /** destructor */ + ~MeanShiftImageFilter(){}; + + /**PrintSelf method */ + virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; + + /** Redefinition of the GetNumberOfComponentsPerPixel() adapted for Image */ + virtual unsigned int GetNumberOfComponentsPerPixel(); + + /** Redefinition of the InitValue() method adapted for Image + * Please be aware that this function modifies the reference to value + */ + virtual void InitValue(PrecisionPixelType & value, const unsigned int& nbComponents); + + /** Redefinition of the SquaredNorm() method adapted for Image */ + virtual double SquaredNorm(const PrecisionPixelType& value); + + private: + MeanShiftImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + }; +}// end namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbMeanShiftImageFilter.txx" +#endif + +#endif diff --git a/Code/BasicFilters/otbMeanShiftImageFilter.txx b/Code/BasicFilters/otbMeanShiftImageFilter.txx new file mode 100644 index 0000000000..7a6acfbfef --- /dev/null +++ b/Code/BasicFilters/otbMeanShiftImageFilter.txx @@ -0,0 +1,60 @@ +/*========================================================================= + +Program: ORFEO Toolbox +Language: C++ +Date: $Date$ +Version: $Revision$ + + +Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. +See OTBCopyright.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 _otbMeanShiftImageFilter_txx +#define _otbMeanShiftImageFilter_txx + +#include "otbMeanShiftImageFilter.h" + + +namespace otb +{ + template <class TInputImage,class TOutputImage,class TPrecision> + unsigned int + MeanShiftImageFilter<TInputImage,TOutputImage,TPrecision> + ::GetNumberOfComponentsPerPixel() + { + return 1; + } + + template <class TInputImage,class TOutputImage,class TPrecision> + void + MeanShiftImageFilter<TInputImage,TOutputImage,TPrecision> + ::InitValue(PrecisionPixelType & value, const unsigned int& nbComponents) + { + value = 0; + } + + template <class TInputImage,class TOutputImage,class TPrecision> + double + MeanShiftImageFilter<TInputImage,TOutputImage,TPrecision> + ::SquaredNorm(const PrecisionPixelType & value) + { + return value * value; + } + + template <class TInputImage,class TOutputImage,class TPrecision> + void + MeanShiftImageFilter<TInputImage,TOutputImage,TPrecision> + ::PrintSelf(std::ostream& os, itk::Indent indent) const + { + Superclass::PrintSelf(os,indent); + } + +} // end namespace otb + +#endif diff --git a/Code/BasicFilters/otbMeanShiftImageFilterBase.h b/Code/BasicFilters/otbMeanShiftImageFilterBase.h new file mode 100644 index 0000000000..e4c27baabe --- /dev/null +++ b/Code/BasicFilters/otbMeanShiftImageFilterBase.h @@ -0,0 +1,168 @@ +/*========================================================================= + +Program: ORFEO Toolbox +Language: C++ +Date: $Date$ +Version: $Revision$ + + +Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. +See OTBCopyright.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 _otbMeanShiftImageFilterBase_h +#define _otbMeanShiftImageFilterBase_h + +#include "itkInPlaceImageFilter.h" +#include "itkVariableLengthVector.h" + +namespace otb +{ + + /** \class MeanShiftImageFilterBase + * + * This class is the base class for a mean shift edge-preserving smoothing filter. You can not instantiate + * it directly, since it contains pure virtual method. Consider using the MeanShiftImageFilter to + * process otb::Image or itk::Image, or the MeanShiftVectorImageFilter to process otb::VectorImage. + * + * Mean shift is a data clustering algorithm ofthen used in image processing and segmentation. + * For a given pixel, the mean shift will build a set of neighboring pixels within a given spatial + * radius (can be set using SetSpatialRadius()) and a color range (can be set using SetRangeRadius()). + * The spatial and color center of this set is then computed and the algorithm iterates with this new spatial + * and color center. + * + * The algorithm ends when the maximum number of iteration has been reached (can be set using SetMaxNumberOfIterations()) + * or when the spatial center stops moving significantly according to a convegence distance threshold (can be set using + * SetDistanceConvergenceThreshold()). + * + * Pixel spatial distances are computed in pixels or physical coordinates, according to the flag UseImageSpacing (can be + * et or unset by using UseImageSpacingOn() or UseImageSpacingOff()). + * + * For more information about mean shift techniques, one might consider reading the following article: + * + * D. Comaniciu, P. Meer, "Mean Shift: A Robust Approach Toward Feature Space Analysis," IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 24, no. 5, pp. 603-619, May, 2002 + * D. Comaniciu, P. Meer, "Robust analysis of feature spaces: color image segmentation," cvpr, p. 750, 1997 IEEE Computer Society Conference on Computer Vision and Pattern Recognition (CVPR'97), 1997 + * D. Comaniciu, P. Meer, "Mean Shift Analysis and Applications," iccv, p. 1197, Seventh International Conference on Computer Vision (ICCV'99) - Volume 2, 1999 + * + * \sa MeanShiftImageFilter + * \sa MeanShiftVectorImageFilter + * + * \ingroup ImageEnhancement + * \ingroup Streamed + * \ingroup Threaded + */ + +template <class TInputImage, class TOutputImage, class TPrecision = double> +class ITK_EXPORT MeanShiftImageFilterBase + : public itk::InPlaceImageFilter<TInputImage,TOutputImage> + { + public: + /** Standard class typedef */ + typedef MeanShiftImageFilterBase Self; + typedef itk::InPlaceImageFilter<TInputImage,TOutputImage> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Type macro */ + itkTypeMacro(MeanShiftImageFilterBase,InPlaceImageFilter); + + /** Template parameters typedefs */ + typedef TInputImage InputImageType; + typedef typename InputImageType::Pointer InputImagePointerType; + typedef typename InputImageType::PixelType InputPixelType; + typedef typename InputImageType::PointType PointType; + typedef TOutputImage OutputImageType; + typedef typename OutputImageType::Pointer OutputImagePointerType; + typedef typename OutputImageType::PixelType OutputPixelType; + typedef typename OutputImageType::RegionType RegionType; + typedef typename RegionType::SizeType SizeType; + typedef typename RegionType::IndexType IndexType; + typedef typename InputImageType::SpacingType SpacingType; + typedef TPrecision PrecisionPixelType; + + /** Setters / Getters */ + itkSetMacro(SpatialRadius,double); + itkGetMacro(SpatialRadius,double); + itkSetMacro(RangeRadius,double); + itkGetMacro(RangeRadius,double); + itkSetMacro(MaxNumberOfIterations,unsigned int); + itkGetMacro(MaxNumberOfIterations,unsigned int); + itkGetMacro(ConvergenceDistanceThreshold,double); + itkSetMacro(ConvergenceDistanceThreshold,double); + itkSetMacro(UseImageSpacing,bool); + itkGetMacro(UseImageSpacing,bool); + itkBooleanMacro(UseImageSpacing); + + protected: + /** This filters use a neighborhood around the pixel, so it needs to redfine the + * input requested region */ + virtual void GenerateInputRequestedRegion(); + + /** Threaded generate data */ + virtual void ThreadedGenerateData(const RegionType & outputRegionForThread,int threadId); + + /** Constructor */ + MeanShiftImageFilterBase(); + + /** destructor */ + ~MeanShiftImageFilterBase(){}; + + /**PrintSelf method */ + virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; + + /** + * This method must be defined in order to handle VectorImage or Image. + * \return the number of components per pixel of the input image. + */ + virtual unsigned int GetNumberOfComponentsPerPixel() = 0; + + /** + * This method must be defined in order to handle VectorImage or Image. + * \param value The value to intialize (please note that the reference will be modified) + * \param nbComponents the number of components of the value to intialize. + */ + virtual void InitValue(PrecisionPixelType & value, const unsigned int& nbComponents) = 0; + + /** + * This method must be defined in order to handle VectorImage or Image. + * \return The sqaured norm of the given value + */ + virtual double SquaredNorm(const PrecisionPixelType& value) = 0; + + private: + MeanShiftImageFilterBase(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + /** Spatial radius for mean shift convergence */ + double m_SpatialRadius; + /** Range radius for mean shift convergence */ + double m_RangeRadius; + /** Max number of iterations for convergence */ + unsigned int m_MaxNumberOfIterations; + + /** Internal radius used by the iterator. The value depends on the spatial radius + * and the maximum number of iterations. This value is not intended to be accessed + * by users, thus no getter or setter is provided */ + SizeType m_InternalRadius; + + /** use image spacing */ + bool m_UseImageSpacing; + + /** Internal spacing is [1.,1.] if UseImageSpacing is off */ + SpacingType m_InternalSpacing; + + /** Distance threshold for convergence in the spatial domain */ + double m_ConvergenceDistanceThreshold; + }; +}// end namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbMeanShiftImageFilterBase.txx" +#endif + +#endif diff --git a/Code/BasicFilters/otbMeanShiftImageFilterBase.txx b/Code/BasicFilters/otbMeanShiftImageFilterBase.txx new file mode 100644 index 0000000000..7bee359db1 --- /dev/null +++ b/Code/BasicFilters/otbMeanShiftImageFilterBase.txx @@ -0,0 +1,259 @@ +/*========================================================================= + +Program: ORFEO Toolbox +Language: C++ +Date: $Date$ +Version: $Revision$ + + +Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. +See OTBCopyright.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 _otbMeanShiftImageFilterBase_txx +#define _otbMeanShiftImageFilterBase_txx + +#include "otbMeanShiftImageFilterBase.h" + +#include "itkImageRegionConstIteratorWithIndex.h" +#include "itkImageRegionIterator.h" +#include "itkOffset.h" +#include "itkProgressReporter.h" + +#include "otbMacro.h" + +namespace otb +{ + template <class TInputImage,class TOutputImage,class TPrecision> + MeanShiftImageFilterBase<TInputImage,TOutputImage,TPrecision> + ::MeanShiftImageFilterBase() + { + m_MaxNumberOfIterations = 20; + m_ConvergenceDistanceThreshold = 0.5; + m_SpatialRadius = 3; + m_RangeRadius = 10; + m_UseImageSpacing = false; + m_InternalRadius.Fill(0); + m_InternalSpacing.Fill(1.); + + // For debug purposes we set the number of threads to 1. + // this->SetNumberOfThreads(1); + } + + template <class TInputImage,class TOutputImage,class TPrecision> + void + MeanShiftImageFilterBase<TInputImage,TOutputImage,TPrecision> + ::GenerateInputRequestedRegion() + { + // call the superclass' implementation of this method + Superclass::GenerateInputRequestedRegion(); + + // get pointers to the input and output + typename Superclass::InputImagePointer inputPtr = + const_cast< TInputImage * >( this->GetInput() ); + typename Superclass::OutputImagePointer outputPtr = this->GetOutput(); + + if ( !inputPtr || !outputPtr ) + { + return; + } + + // get a copy of the input requested region (should equal the output + // requested region) + typename TInputImage::RegionType inputRequestedRegion; + inputRequestedRegion = inputPtr->GetRequestedRegion(); + + //Compute the radius we will need to execute the filter: + + if(m_UseImageSpacing) + { + for(unsigned int dimension = 0; dimension < InputImageType::ImageDimension;++dimension) + { + m_InternalSpacing[dimension] = vcl_abs(inputPtr->GetSpacing()[dimension]); + } + } + std::cout<<"MeanShiftImageFilterBase: Internal Spacing = "<<m_InternalSpacing<<std::endl; + + for(unsigned int dimension = 0; dimension < InputImageType::ImageDimension;++dimension) + { + m_InternalRadius[dimension] = static_cast<unsigned long>(vcl_floor(m_MaxNumberOfIterations * m_SpatialRadius + / m_InternalSpacing[dimension]+0.5)); + } + + std::cout<<"MeanShiftImageFilterBase: Internal radius = "<<m_InternalRadius<<std::endl; + + // pad the input requested region by the operator radius + inputRequestedRegion.PadByRadius( m_InternalRadius ); + + // crop the input requested region at the input's largest possible region + if ( inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion()) ) + { + inputPtr->SetRequestedRegion( inputRequestedRegion ); + return; + } + else + { + // Couldn't crop the region (requested region is outside the largest + // possible region). Throw an exception. + + // store what we tried to request (prior to trying to crop) + inputPtr->SetRequestedRegion( inputRequestedRegion ); + + // build an exception + itk::InvalidRequestedRegionError e(__FILE__, __LINE__); + e.SetLocation(ITK_LOCATION); + e.SetDescription("Requested region is (at least partially) outside the largest possible region."); + e.SetDataObject(inputPtr); + throw e; + } + } + + template <class TInputImage,class TOutputImage,class TPrecision> + void + MeanShiftImageFilterBase<TInputImage,TOutputImage,TPrecision> + ::ThreadedGenerateData(const RegionType & outputRegionForThread,int threadId) + { + // Set up the progress reporter + itk::ProgressReporter progress(this,threadId,outputRegionForThread.GetNumberOfPixels()); + + // Input and output pointers + typename OutputImageType::Pointer outputPtr = this->GetOutput(); + typename InputImageType::ConstPointer inputPtr = this->GetInput(); + + // Iterators + itk::ImageRegionConstIteratorWithIndex<InputImageType> inputIt(inputPtr,outputRegionForThread); + itk::ImageRegionIterator<OutputImageType> outputIt(outputPtr,outputRegionForThread); + + //TODO: Work with a floating point pixel type + + // local declarations + unsigned int nbIterations; + IndexType offset; + PointType maxDensityPoint,convergencePoint; + PrecisionPixelType maxDensityValue, convergenceValue,diff,current; + unsigned int nbPixelsIntoAccount; + bool goesOn = true; + long startx,stopx,starty,stopy,i,j; + double squaredSpatialDistance, squaredUpdateDistance; + + // Const values computed here to reduce complexity + const unsigned int nbComponentsPerPixel = this->GetNumberOfComponentsPerPixel(); + const double spatialThreshold = vcl_pow(m_SpatialRadius,2); + const double spatialAndRangeThreshold = nbComponentsPerPixel * vcl_pow(m_RangeRadius,2) + spatialThreshold; + const double spatialConvergenceThreshold = vcl_pow(m_ConvergenceDistanceThreshold,2); + + + // intialize iterators + inputIt.GoToBegin(); + outputIt.GoToBegin(); + + // Walk the images + while(!inputIt.IsAtEnd() && !outputIt.IsAtEnd()) + { + nbIterations = 0; + goesOn = true; + convergencePoint[0]=static_cast<double>(inputIt.GetIndex()[0])*m_InternalSpacing[0]; + convergencePoint[1]=static_cast<double>(inputIt.GetIndex()[1])*m_InternalSpacing[1]; + convergenceValue = inputIt.Get(); + // While the max number of iterations has not been reached and the convergence index is still moving + while(nbIterations < m_MaxNumberOfIterations && goesOn) + { + maxDensityPoint.Fill(0); + this->InitValue(maxDensityValue,nbComponentsPerPixel); + nbPixelsIntoAccount = 0; + + startx = vcl_floor((convergencePoint[0]-m_SpatialRadius)/m_InternalSpacing[0]); + stopx = vcl_ceil ((convergencePoint[0]+m_SpatialRadius)/m_InternalSpacing[0]); + starty = vcl_floor((convergencePoint[1]-m_SpatialRadius)/m_InternalSpacing[1]); + stopy = vcl_ceil ((convergencePoint[1]+m_SpatialRadius)/m_InternalSpacing[1]); + + // loop on the neighborhood + for(i = startx;i<=stopx;++i) + { + for(j =starty;j<=stopy;++j) + { + // Setting the offset + offset[0]=i; + offset[1]=j; + squaredSpatialDistance = vcl_pow(static_cast<double>(convergencePoint[0]-offset[0]*m_InternalSpacing[0]),2) + + vcl_pow(static_cast<double>(convergencePoint[1]-offset[1]*m_InternalSpacing[1]),2); + // verify that the current offset is inside or spatial circle + if(inputPtr->GetBufferedRegion().IsInside(offset) + && squaredSpatialDistance <spatialThreshold) + { + current = inputPtr->GetPixel(offset); + diff = convergenceValue - current;; + // Check if we are inside the spectral - spatial circle + if(this->SquaredNorm(diff)+squaredSpatialDistance<spatialAndRangeThreshold) + { + maxDensityPoint[0]+=offset[0]*m_InternalSpacing[0]; + maxDensityPoint[1]+=offset[1]*m_InternalSpacing[1]; + maxDensityValue+=current; + ++nbPixelsIntoAccount; + } + } + } + } + // If no inside pixels + if(nbPixelsIntoAccount == 0) + { + maxDensityPoint.Fill(0); + maxDensityValue = inputIt.Get(); + } + else + { + // Mean density location and value + maxDensityPoint[0]/=nbPixelsIntoAccount; + maxDensityPoint[1]/=nbPixelsIntoAccount; + maxDensityValue/=nbPixelsIntoAccount; + } + convergenceValue = maxDensityValue; + // Check if we are still significantly moving + squaredUpdateDistance = vcl_pow(static_cast<double>(maxDensityPoint[0]-convergencePoint[0]),2) + +vcl_pow(static_cast<double>(maxDensityPoint[1]-convergencePoint[1]),2); + if(squaredUpdateDistance <spatialConvergenceThreshold) + { + // we reached the maximum density point, exit + goesOn = false; + } + else + { + // Update the convergence point and loop again + convergencePoint = maxDensityPoint; + } + ++nbIterations; + } + // Set the output value + outputIt.Set(convergenceValue); + // Update progress + progress.CompletedPixel(); + // Increment iterators + ++inputIt; + ++outputIt; + } + } + + template <class TInputImage,class TOutputImage,class TPrecision> + void + MeanShiftImageFilterBase<TInputImage,TOutputImage,TPrecision> + ::PrintSelf(std::ostream& os, itk::Indent indent) const + { + Superclass::PrintSelf(os,indent); + os<<indent<<"Spatial radius: " <<m_SpatialRadius <<std::endl; + os<<indent<<"Range radius: " <<m_RangeRadius <<std::endl; + os<<indent<<"Maximum number of iterations: " <<m_MaxNumberOfIterations <<std::endl; + os<<indent<<"Internal radius: " <<m_InternalRadius <<std::endl; + os<<indent<<"Use image spacing: " <<m_UseImageSpacing <<std::endl; + os<<indent<<"Internal spacing: " <<m_InternalSpacing <<std::endl; + os<<indent<<"Convergence distance threshold: "<<m_ConvergenceDistanceThreshold<<std::endl; + + } + +} // end namespace otb + +#endif diff --git a/Code/BasicFilters/otbMeanShiftVectorImageFilter.h b/Code/BasicFilters/otbMeanShiftVectorImageFilter.h index cbf621c67a..1cbfaba35e 100644 --- a/Code/BasicFilters/otbMeanShiftVectorImageFilter.h +++ b/Code/BasicFilters/otbMeanShiftVectorImageFilter.h @@ -18,100 +18,66 @@ PURPOSE. See the above copyright notices for more information. #ifndef _otbMeanShiftVectorImageFilter_h #define _otbMeanShiftVectorImageFilter_h -#include "itkInPlaceImageFilter.h" +#include "otbMeanShiftImageFilterBase.h" namespace otb { /** \class MeanShiftVectorImageFilter - * - * - * + * + * This is the implementation of the mean shift edge-preserving smoothing filter adapted to + * otb::VectorImage or itk::VectorImage. For the full documentation, please refer to the + * base class otb::MeanShiftImageFilterBase. * + * \sa MeanShiftImageFilterBase + * \ingroup ImageEnhancement * \ingroup Streamed * \ingroup Threaded */ - -template <class TInputImage, class TOutputImage> -class ITK_EXPORT MeanShiftVectorImageFilter - : public itk::InPlaceImageFilter<TInputImage,TOutputImage> - { - public: - /** Standard class typedef */ - typedef MeanShiftVectorImageFilter Self; - typedef itk::InPlaceImageFilter<TInputImage,TOutputImage> Superclass; - typedef itk::SmartPointer<Self> Pointer; - typedef itk::SmartPointer<const Self> ConstPointer; - - /** New and Type macros */ - itkNewMacro(Self); - itkTypeMacro(MeanShiftVectorImageFilter,InPlaceImageFilter); + template <class TInputImage, class TOutputImage, class TPrecision = double> + class ITK_EXPORT MeanShiftVectorImageFilter + : public MeanShiftImageFilterBase<TInputImage,TOutputImage,itk::VariableLengthVector<TPrecision> > + { + public: + /** Standard class typedef */ + typedef MeanShiftVectorImageFilter Self; + typedef MeanShiftImageFilterBase<TInputImage,TOutputImage, + itk::VariableLengthVector<TPrecision> > Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** New and Type macros */ + itkNewMacro(Self); + itkTypeMacro(MeanShiftVectorImageFilter,MeanShiftImageFilterBase); - /** Template parameters typedefs */ - typedef TInputImage InputImageType; - typedef typename InputImageType::Pointer InputImagePointerType; - typedef typename InputImageType::PixelType InputPixelType; - typedef typename InputImageType::InternalPixelType InputInternalPixelType; - typedef typename InputImageType::PointType PointType; - typedef TOutputImage OutputImageType; - typedef typename OutputImageType::Pointer OutputImagePointerType; - typedef typename OutputImageType::PixelType OutputPixelType; - typedef typename OutputImageType::InternalPixelType OutputInternalPixelType; - typedef typename OutputImageType::RegionType RegionType; - typedef typename RegionType::SizeType SizeType; - - /** Setters / Getters */ - itkSetMacro(SpatialRadius,double); - itkGetMacro(SpatialRadius,double); - itkSetMacro(RangeRadius,double); - itkGetMacro(RangeRadius,double); - itkSetMacro(MaxNumberOfIterations,unsigned int); - itkGetMacro(MaxNumberOfIterations,unsigned int); - itkGetMacro(ConvergenceDistanceThreshold,double); - itkSetMacro(ConvergenceDistanceThreshold,double); - itkSetMacro(UseImageSpacing,bool); - itkGetMacro(UseImageSpacing,bool); - itkBooleanMacro(UseImageSpacing); - - protected: - /** This filters use a neighborhood around the pixel, so it needs to redfine the - * input requested region */ - virtual void GenerateInputRequestedRegion(); - - /** Threaded generate data */ - virtual void ThreadedGenerateData(const RegionType & outputRegionForThread,int threadId); - - /** Constructor */ - MeanShiftVectorImageFilter(); - - /** destructor */ - ~MeanShiftVectorImageFilter(){}; - - /**PrintSelf method */ - virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; - - private: - MeanShiftVectorImageFilter(const Self&); //purposely not implemented - void operator=(const Self&); //purposely not implemented - - /** Spatial radius for mean shift convergence */ - double m_SpatialRadius; - /** Range radius for mean shift convergence */ - double m_RangeRadius; - /** Max number of iterations for convergence */ - unsigned int m_MaxNumberOfIterations; - - /** Internal radius used by the iterator. The value depends on the spatial radius - * and the maximum number of iterations. This value is not intended to be accessed - * by users, thus no getter or setter is provided */ - SizeType m_InternalRadius; - - /** use image spacing */ - bool m_UseImageSpacing; - - /** Distance threshold for convergence in the spatial domain */ - double m_ConvergenceDistanceThreshold; - }; + /** Template parameters typedefs */ + typedef typename Superclass::PrecisionPixelType PrecisionPixelType; + + protected: + /** Constructor */ + MeanShiftVectorImageFilter(){}; + + /** destructor */ + ~MeanShiftVectorImageFilter(){}; + + /**PrintSelf method */ + virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; + + /** Redefinition of the GetNumberOfComponentsPerPixel() adapted for VectorImages */ + virtual unsigned int GetNumberOfComponentsPerPixel(); + + /** Redefinition of the InitValue() method adapted for vector images + * Please be aware that this function modifies the reference to value + */ + virtual void InitValue(PrecisionPixelType & value, const unsigned int& nbComponents); + + /** Redefinition of the SquaredNorm() method adapted for vector images */ + virtual double SquaredNorm(const PrecisionPixelType & value); + + private: + MeanShiftVectorImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + }; }// end namespace otb #ifndef OTB_MANUAL_INSTANTIATION diff --git a/Code/BasicFilters/otbMeanShiftVectorImageFilter.txx b/Code/BasicFilters/otbMeanShiftVectorImageFilter.txx index 3f124649bb..30f7a40626 100644 --- a/Code/BasicFilters/otbMeanShiftVectorImageFilter.txx +++ b/Code/BasicFilters/otbMeanShiftVectorImageFilter.txx @@ -20,10 +20,8 @@ PURPOSE. See the above copyright notices for more information. #include "otbMeanShiftVectorImageFilter.h" -#include "itkConstNeighborhoodIterator.h" +#include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" -#include "itkNeighborhoodAlgorithm.h" -#include "itkZeroFluxNeumannBoundaryCondition.h" #include "itkOffset.h" #include "itkProgressReporter.h" @@ -31,233 +29,38 @@ PURPOSE. See the above copyright notices for more information. namespace otb { - template <class TInputImage,class TOutputImage> - MeanShiftVectorImageFilter<TInputImage,TOutputImage> - ::MeanShiftVectorImageFilter() + template <class TInputImage,class TOutputImage,class TPrecision> + unsigned int + MeanShiftVectorImageFilter<TInputImage,TOutputImage,TPrecision> + ::GetNumberOfComponentsPerPixel() { - m_MaxNumberOfIterations = 20; - m_ConvergenceDistanceThreshold = 0.5; - m_SpatialRadius = 3; - m_RangeRadius = 10; - m_UseImageSpacing = false; - m_InternalRadius.Fill(0); + return this->GetInput()->GetNumberOfComponentsPerPixel(); } - - template <class TInputImage,class TOutputImage> + template <class TInputImage,class TOutputImage,class TPrecision> void - MeanShiftVectorImageFilter<TInputImage,TOutputImage> - ::GenerateInputRequestedRegion() + MeanShiftVectorImageFilter<TInputImage,TOutputImage,TPrecision> + ::InitValue(PrecisionPixelType & value, const unsigned int& nbComponents) { - // call the superclass' implementation of this method - Superclass::GenerateInputRequestedRegion(); - - // get pointers to the input and output - typename Superclass::InputImagePointer inputPtr = - const_cast< TInputImage * >( this->GetInput() ); - typename Superclass::OutputImagePointer outputPtr = this->GetOutput(); - - if ( !inputPtr || !outputPtr ) - { - return; - } - - // get a copy of the input requested region (should equal the output - // requested region) - typename TInputImage::RegionType inputRequestedRegion; - inputRequestedRegion = inputPtr->GetRequestedRegion(); - - //Compute the radius we will need to execute the filter: - if(m_UseImageSpacing) - { - for(unsigned int dimension = 0; dimension < InputImageType::ImageDimension;++dimension) - { - m_InternalRadius[dimension] = static_cast<unsigned long>(vcl_floor(m_MaxNumberOfIterations * m_SpatialRadius / inputPtr->GetSpacing()[0]+0.5)); - } - } - else - { - m_InternalRadius.Fill(static_cast<unsigned long>(vcl_floor(m_MaxNumberOfIterations * m_SpatialRadius+0.5))); - } - std::cout<<"MeanShiftVectorImageFilter: Internal radius = "<<m_InternalRadius<<std::endl; - - - // pad the input requested region by the operator radius - inputRequestedRegion.PadByRadius( m_InternalRadius ); - - // crop the input requested region at the input's largest possible region - if ( inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion()) ) - { - inputPtr->SetRequestedRegion( inputRequestedRegion ); - return; - } - else - { - // Couldn't crop the region (requested region is outside the largest - // possible region). Throw an exception. - - // store what we tried to request (prior to trying to crop) - inputPtr->SetRequestedRegion( inputRequestedRegion ); - - // build an exception - itk::InvalidRequestedRegionError e(__FILE__, __LINE__); - e.SetLocation(ITK_LOCATION); - e.SetDescription("Requested region is (at least partially) outside the largest possible region."); - e.SetDataObject(inputPtr); - throw e; - } + value.SetSize(nbComponents); + value.Fill(0); } - - template <class TInputImage,class TOutputImage> - void - MeanShiftVectorImageFilter<TInputImage,TOutputImage> - ::ThreadedGenerateData(const RegionType & outputRegionForThread,int threadId) - { - std::cout<<"Call to threaded generate data, threadId: "<<threadId<<", region: "<<outputRegionForThread<<std::endl; - // TODO: update this to handle the UseImageSpacing option. - - // Set up the progress reporter - itk::ProgressReporter progress(this,threadId,outputRegionForThread.GetNumberOfPixels()); - - // Input and output pointers - typename OutputImageType::Pointer outputPtr = this->GetOutput(); - typename InputImageType::ConstPointer inputPtr = this->GetInput(); - - // Iterators - itk::ConstNeighborhoodIterator<InputImageType> inputIt(m_InternalRadius,inputPtr,outputRegionForThread); - itk::ConstNeighborhoodIterator<InputImageType> internalIt; - itk::ImageRegionIterator<OutputImageType> outputIt(outputPtr,outputRegionForThread); - - // Boundary conditions - itk::ZeroFluxNeumannBoundaryCondition<InputImageType> nbc; - inputIt.OverrideBoundaryCondition(&nbc); - - //TODO: Work with a floating point pixel type - // local declarations - unsigned int nbIterations; - typedef typename itk::ConstNeighborhoodIterator<InputImageType>::OffsetType OffsetType; - - OffsetType offset; - PointType maxDensityPoint,convergencePoint; - InputPixelType maxDensityValue, convergenceValue,diff,current; - unsigned int nbPixelsIntoAccount; - - unsigned int nbComponentsPerPixel = inputPtr->GetNumberOfComponentsPerPixel(); - bool goesOn = true; - long startx,stopx,starty,stopy; - - // intialize iterators - inputIt.GoToBegin(); - outputIt.GoToBegin(); - - // Walk the images - while(!inputIt.IsAtEnd() && !outputIt.IsAtEnd()) - { - nbIterations = 0; - goesOn = true; - convergencePoint.Fill(0); - convergenceValue = inputIt.GetCenterPixel(); - //std::cout<<"Processing pixel: "<<inputIt.GetIndex()<<", value: "<<convergenceValue<<std::endl; - - - // While the max number of iterations has not been reached and the convergence index is still moving - while(nbIterations < m_MaxNumberOfIterations && goesOn) - { - //std::cout<<"Loop: "<<nbIterations<<", goesOn: "<<goesOn<<std::endl; - maxDensityPoint.Fill(0); - maxDensityValue.SetSize(nbComponentsPerPixel); - maxDensityValue.Fill(0); - nbPixelsIntoAccount = 0; - - startx = vcl_floor(convergencePoint[0]-m_SpatialRadius); - stopx = vcl_ceil(convergencePoint[0]+m_SpatialRadius); - starty = vcl_floor(convergencePoint[1]-m_SpatialRadius); - stopy = vcl_ceil(convergencePoint[1]+m_SpatialRadius); - - // loop on the neighborhood - for(long i = startx;i<=stopx;++i) - { - for(long j =starty;j<=stopy;++j) - { - // Setting the offset - offset[0]=i; - offset[1]=j; - - // verify that the current offset is inside or spatial circle - if(vcl_sqrt(vcl_pow(static_cast<double>(convergencePoint[0]-offset[0]),2)+vcl_pow(static_cast<double>(convergencePoint[1]-offset[1]),2))<m_SpatialRadius) - { - //std::cout<<"Point: "<<offset<<" is inside spatial circle"<<std::endl; - current = inputIt.GetPixel(offset); - diff = convergenceValue - current; - //std::cout<<"Difference with current pixel: "<<diff<<std::endl; - // Check if we are inside the spectral - spatial circle - if(diff.GetSquaredNorm()+vcl_pow(static_cast<double>(offset[0]),2)+vcl_pow(static_cast<double>(offset[1]),2)<nbComponentsPerPixel * vcl_pow(m_RangeRadius,2) + vcl_pow(m_SpatialRadius,2)) - { - //std::cout<<"Point: "<<offset<<" is inside the spatial/spectral disk"<<std::endl; - maxDensityPoint[0]+=offset[0]; - maxDensityPoint[1]+=offset[1]; - maxDensityValue+=current; - ++nbPixelsIntoAccount; - } - } - } - } - // If no inside pixels - if(nbPixelsIntoAccount == 0) - { - maxDensityPoint.Fill(0); - maxDensityValue = inputIt.GetCenterPixel(); - } - else - { - maxDensityPoint[0]/=nbPixelsIntoAccount; - maxDensityPoint[1]/=nbPixelsIntoAccount; - maxDensityValue/=nbPixelsIntoAccount; - } - //std::cout<<"MaxDensityValue: "<<maxDensityValue<<std::endl; - convergenceValue = maxDensityValue; - - //std::cout<<"Nb pixels into account: "<<nbPixelsIntoAccount<<", convergence point: "<<convergencePoint<<", maxDensityPoint: "<<maxDensityPoint<<", convergenceValue: "<<convergenceValue<<std::endl; - - // Check if we are still significantly moving - double updatedDistance = vcl_sqrt(vcl_pow(static_cast<double>(maxDensityPoint[0]-convergencePoint[0]),2)+vcl_pow(static_cast<double>(maxDensityPoint[1]-convergencePoint[1]),2)); - if(updatedDistance < m_ConvergenceDistanceThreshold) - { - goesOn = false; - } - else - { - convergencePoint = maxDensityPoint; - } - ++nbIterations; - } - // Set the output value - // TODO: missing value cast here - outputIt.Set(convergenceValue); - // Update progress - progress.CompletedPixel(); - // Increment iterators - ++inputIt; - ++outputIt; - } + template <class TInputImage,class TOutputImage,class TPrecision> + double + MeanShiftVectorImageFilter<TInputImage,TOutputImage,TPrecision> + ::SquaredNorm(const PrecisionPixelType & value) + { + return value.GetSquaredNorm(); } - template <class TInputImage,class TOutputImage> + template <class TInputImage,class TOutputImage,class TPrecision> void - MeanShiftVectorImageFilter<TInputImage,TOutputImage> + MeanShiftVectorImageFilter<TInputImage,TOutputImage,TPrecision> ::PrintSelf(std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf(os,indent); - os<<indent<<"Spatial radius: "<<m_SpatialRadius<<std::endl; - os<<indent<<"Range radius: "<<m_RangeRadius<<std::endl; - os<<indent<<"Maximum number of iterations: "<<m_MaxNumberOfIterations<<std::endl; - os<<indent<<"Internal radius: "<<m_InternalRadius<<std::endl; - os<<indent<<"Use image spacing: "<<m_UseImageSpacing<<std::endl; - os<<indent<<"Convergence distance threshold: "<<m_ConvergenceDistanceThreshold<<std::endl; - } - } // end namespace otb #endif diff --git a/Testing/Code/BasicFilters/CMakeLists.txt b/Testing/Code/BasicFilters/CMakeLists.txt index 1d261725ae..1ed41957b2 100755 --- a/Testing/Code/BasicFilters/CMakeLists.txt +++ b/Testing/Code/BasicFilters/CMakeLists.txt @@ -883,16 +883,42 @@ ADD_TEST(bfTvContinuousMinimumMaximumImageCalculatorTest ${BASICFILTERS_TESTS9} # 2 2 # ) +ADD_TEST(bfTuMeanShiftImageFilterNew ${BASICFILTERS_TESTS9} + otbMeanShiftImageFilterNew ) + +ADD_TEST(bfTvMeanShiftImageFilter ${BASICFILTERS_TESTS9} +--compare-image ${EPSILON} + ${BASELINE}/bfMeanShiftImageFilterOutput.tif + ${TEMP}/bfMeanShiftImageFilterOutput.tif + otbMeanShiftImageFilter + ${INPUTDATA}/QB_Suburb.png + ${TEMP}/bfMeanShiftImageFilterOutput.tif + 3 15 20 0 0.0001 + ) + ADD_TEST(bfTuMeanShiftVectorImageFilterNew ${BASICFILTERS_TESTS9} otbMeanShiftVectorImageFilterNew ) ADD_TEST(bfTvMeanShiftVectorImageFilter ${BASICFILTERS_TESTS9} +--compare-image ${EPSILON} + ${BASELINE}/bfMeanShiftVectorImageFilterOutput.tif + ${TEMP}/bfMeanShiftVectorImageFilterOutput.tif otbMeanShiftVectorImageFilter ${INPUTDATA}/qb_RoadExtract2sub200x200.tif - ${TEMP}/bfTvvMeanShiftVectorImageFilterOutput.tif + ${TEMP}/bfMeanShiftVectorImageFilterOutput.tif 3 15 20 0 0.0001 ) +ADD_TEST(bfTvMeanShiftVectorImageFilterUsingImageSpacing ${BASICFILTERS_TESTS9} +--compare-image ${EPSILON} + ${BASELINE}/bfMeanShiftVectorImageFilterOutputUsingImageSpacing.tif + ${TEMP}/bfMeanShiftVectorImageFilterOutputUsingImageSpacing.tif + otbMeanShiftVectorImageFilter + ${INPUTDATA}/qb_RoadExtract2sub200x200.tif + ${TEMP}/bfMeanShiftVectorImageFilterOutputUsingImageSpacing.tif + 3 15 20 1 0.0001 + ) + ADD_TEST(bfTvFunctionToImageFilterNew ${BASICFILTERS_TESTS9} otbFunctionToImageFilterNew ) @@ -1054,8 +1080,8 @@ otbChangeLabelImageFilterNew.cxx otbChangeLabelImageFilter.cxx otbContinuousMinimumMaximumImageCalculatorNew.cxx otbContinuousMinimumMaximumImageCalculatorTest.cxx -#MeanShift.cxx -#MeanShiftVectorImage.cxx +otbMeanShiftImageFilterNew.cxx +otbMeanShiftImageFilter.cxx otbMeanShiftVectorImageFilterNew.cxx otbMeanShiftVectorImageFilter.cxx otbFunctionToImageFilterNew.cxx diff --git a/Testing/Code/BasicFilters/otbBasicFiltersTests9.cxx b/Testing/Code/BasicFilters/otbBasicFiltersTests9.cxx index b68119fcf2..be0880b63c 100644 --- a/Testing/Code/BasicFilters/otbBasicFiltersTests9.cxx +++ b/Testing/Code/BasicFilters/otbBasicFiltersTests9.cxx @@ -31,10 +31,10 @@ REGISTER_TEST(otbChangeLabelImageFilterNew); REGISTER_TEST(otbChangeLabelImageFilterTest); REGISTER_TEST(otbContinuousMinimumMaximumImageCalculatorNew); REGISTER_TEST(otbContinuousMinimumMaximumImageCalculatorTest); +REGISTER_TEST(otbMeanShiftImageFilterNew); +REGISTER_TEST(otbMeanShiftImageFilter); REGISTER_TEST(otbMeanShiftVectorImageFilterNew); REGISTER_TEST(otbMeanShiftVectorImageFilter); -//REGISTER_TEST(MeanShiftRef); -//REGISTER_TEST(MeanShiftVectorImageRef); REGISTER_TEST(otbFunctionToImageFilterNew); REGISTER_TEST(otbFunctionToImageFilter); REGISTER_TEST(otbScalarImageTextureFunctorNew); diff --git a/Testing/Code/BasicFilters/otbMeanShiftImageFilter.cxx b/Testing/Code/BasicFilters/otbMeanShiftImageFilter.cxx new file mode 100644 index 0000000000..657cba7de1 --- /dev/null +++ b/Testing/Code/BasicFilters/otbMeanShiftImageFilter.cxx @@ -0,0 +1,67 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.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 "itkExceptionObject.h" +#include "otbImage.h" +#include "otbImage.h" +#include "otbImageFileReader.h" +#include "otbImageFileWriter.h" +#include "otbMeanShiftImageFilter.h" + +int otbMeanShiftImageFilter(int argc, char * argv[]) +{ + if(argc != 8) + { + std::cerr<<"Usage: "<<argv[0]<<" infname outfname spatialRadius rangeRadius maxNbIterations useImageSpacing convergenceDistanceThreshold"<<std::endl; + return EXIT_FAILURE; + } + + const char * infname = argv[1]; + const char * outfname = argv[2]; + const double spatialRadius = atof(argv[3]); + const double rangeRadius = atof(argv[4]); + const unsigned int maxNbIterations = atoi(argv[5]); + const bool useImageSpacing = atoi(argv[6]); + const double convergenceTol = atof(argv[7]); + + const unsigned int Dimension = 2; + typedef short PixelType; + typedef otb::Image<PixelType,Dimension> ImageType; + typedef otb::ImageFileReader<ImageType> ReaderType; + typedef otb::ImageFileWriter<ImageType> WriterType; + typedef otb::MeanShiftImageFilter<ImageType,ImageType> FilterType; + + // Instantiating object + FilterType::Pointer filter = FilterType::New(); + ReaderType::Pointer reader = ReaderType::New(); + WriterType::Pointer writer = WriterType::New(); + + reader->SetFileName(infname); + writer->SetFileName(outfname); + + filter->SetSpatialRadius(spatialRadius); + filter->SetRangeRadius(rangeRadius); + filter->SetMaxNumberOfIterations(maxNbIterations); + filter->SetUseImageSpacing(useImageSpacing); + filter->SetConvergenceDistanceThreshold(convergenceTol); + + filter->SetInput(reader->GetOutput()); + writer->SetInput(filter->GetOutput()); + + writer->Update(); + return EXIT_SUCCESS; +} diff --git a/Testing/Code/BasicFilters/otbMeanShiftImageFilterNew.cxx b/Testing/Code/BasicFilters/otbMeanShiftImageFilterNew.cxx new file mode 100644 index 0000000000..b00c171ab1 --- /dev/null +++ b/Testing/Code/BasicFilters/otbMeanShiftImageFilterNew.cxx @@ -0,0 +1,32 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.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 "itkExceptionObject.h" +#include "otbImage.h" +#include "otbMeanShiftImageFilter.h" + +int otbMeanShiftImageFilterNew(int argc, char * argv[]) +{ + const unsigned int Dimension = 2; + typedef short PixelType; + typedef otb::Image<PixelType,Dimension> ImageType; + typedef otb::MeanShiftImageFilter<ImageType,ImageType> FilterType; + + // Instantiating object + FilterType::Pointer object = FilterType::New(); + return EXIT_SUCCESS; +} diff --git a/Testing/Code/BasicFilters/otbMeanShiftVectorImageFilter.cxx b/Testing/Code/BasicFilters/otbMeanShiftVectorImageFilter.cxx index 14ac41a5c6..4a163ffdfc 100644 --- a/Testing/Code/BasicFilters/otbMeanShiftVectorImageFilter.cxx +++ b/Testing/Code/BasicFilters/otbMeanShiftVectorImageFilter.cxx @@ -39,7 +39,7 @@ int otbMeanShiftVectorImageFilter(int argc, char * argv[]) const double convergenceTol = atof(argv[7]); const unsigned int Dimension = 2; - typedef double PixelType; + typedef short PixelType; typedef otb::VectorImage<PixelType,Dimension> ImageType; typedef otb::ImageFileReader<ImageType> ReaderType; typedef otb::ImageFileWriter<ImageType> WriterType; diff --git a/Testing/Code/BasicFilters/otbMeanShiftVectorImageFilterNew.cxx b/Testing/Code/BasicFilters/otbMeanShiftVectorImageFilterNew.cxx index 8cb9aa85d7..92e150a294 100644 --- a/Testing/Code/BasicFilters/otbMeanShiftVectorImageFilterNew.cxx +++ b/Testing/Code/BasicFilters/otbMeanShiftVectorImageFilterNew.cxx @@ -22,7 +22,7 @@ int otbMeanShiftVectorImageFilterNew(int argc, char * argv[]) { const unsigned int Dimension = 2; - typedef double PixelType; + typedef short PixelType; typedef otb::VectorImage<PixelType,Dimension> ImageType; typedef otb::MeanShiftVectorImageFilter<ImageType,ImageType> FilterType; -- GitLab