From ed64f52bff5e0b1c423e82b9f2f0d280307911ab Mon Sep 17 00:00:00 2001 From: Julien Michel <julien.michel@c-s.fr> Date: Wed, 7 May 2008 13:58:22 +0000 Subject: [PATCH] Code Formation --- .../otbKMeansImageClassificationFilter.h | 132 ++++++++++++++ .../otbKMeansImageClassificationFilter.txx | 168 +++++++++++++++++ .../otbSOMImageClassificationFilter.h | 128 +++++++++++++ .../otbSOMImageClassificationFilter.txx | 171 ++++++++++++++++++ .../otbSVMImageClassificationFilter.h | 35 +++- .../otbSVMImageClassificationFilter.txx | 129 +++++++++---- Testing/Code/Learning/CMakeLists.txt | 37 ++++ .../otbKMeansImageClassificationFilter.cxx | 71 ++++++++ .../otbKMeansImageClassificationFilterNew.cxx | 37 ++++ Testing/Code/Learning/otbLearningTests3.cxx | 4 + .../otbSOMImageClassificationFilter.cxx | 63 +++++++ .../otbSOMImageClassificationFilterNew.cxx | 38 ++++ 12 files changed, 971 insertions(+), 42 deletions(-) create mode 100644 Code/Learning/otbKMeansImageClassificationFilter.h create mode 100644 Code/Learning/otbKMeansImageClassificationFilter.txx create mode 100644 Code/Learning/otbSOMImageClassificationFilter.h create mode 100644 Code/Learning/otbSOMImageClassificationFilter.txx create mode 100644 Testing/Code/Learning/otbKMeansImageClassificationFilter.cxx create mode 100644 Testing/Code/Learning/otbKMeansImageClassificationFilterNew.cxx create mode 100644 Testing/Code/Learning/otbSOMImageClassificationFilter.cxx create mode 100644 Testing/Code/Learning/otbSOMImageClassificationFilterNew.cxx diff --git a/Code/Learning/otbKMeansImageClassificationFilter.h b/Code/Learning/otbKMeansImageClassificationFilter.h new file mode 100644 index 0000000000..46215652ae --- /dev/null +++ b/Code/Learning/otbKMeansImageClassificationFilter.h @@ -0,0 +1,132 @@ +/*========================================================================= + +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 _otbKMeansImageClassificationFilter_h +#define _otbKMeansImageClassificationFilter_h + +#include "itkInPlaceImageFilter.h" +#include "itkFixedArray.h" +#include "itkListSample.h" +#include "itkFixedArray.h" +#include "itkEuclideanDistance.h" + +namespace otb +{ + /** \class KMeansImageClassificationFilter + * \brief This filter performs the classification of a VectorImage using a KMeans estimation result. + * + * This filter is streamed and threaded, allowing to classify huge images. Because the + * internal sample type has to be an itk::FixedArray, one must specify at compilation time + * the maximum sample dimension. It is up to the user to specify a MaxSampleDimension sufficiently + * high to integrate all its features. This filter internally use one SVMClassifier per thread. + * + * \sa SVMClassifier + * \ingroup Streamed + * \ingroup Threaded + */ + template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension = 10, class TMaskImage = TOutputImage> + class ITK_EXPORT KMeansImageClassificationFilter + : public itk::InPlaceImageFilter<TInputImage,TOutputImage> + { + public: + /** Standard typedefs */ + typedef KMeansImageClassificationFilter Self; + typedef itk::InPlaceImageFilter<TInputImage,TOutputImage> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Type macro */ + itkNewMacro(Self); + + /** Creation through object factory macro */ + itkTypeMacro(KMeansImageClassificationFilter,InPlaceImageFilter); + + /** The max dimension of the sample to classify. + * This filter internally uses itk::FixedArray as input for the classifier, + * so the max sample size has to be fixed at compilation time. + */ + itkStaticConstMacro(MaxSampleDimension,unsigned int,VMaxSampleDimension); + + typedef TInputImage InputImageType; + typedef typename InputImageType::ConstPointer InputImageConstPointerType; + typedef typename InputImageType::InternalPixelType ValueType; + + typedef TMaskImage MaskImageType; + typedef typename MaskImageType::ConstPointer MaskImageConstPointerType; + typedef typename MaskImageType::Pointer MaskImagePointerType; + + typedef TOutputImage OutputImageType; + typedef typename OutputImageType::Pointer OutputImagePointerType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + typedef typename OutputImageType::PixelType LabelType; + + + typedef itk::FixedArray<ValueType,MaxSampleDimension> SampleType; + typedef itk::Array<double> KMeansParametersType; + typedef std::map<LabelType,SampleType> CentroidsMapType; + typedef itk::Statistics::EuclideanDistance<SampleType> DistanceType; + + /** Set/Get the centroids */ + itkSetMacro(Centroids,KMeansParametersType); + itkGetConstReferenceMacro(Centroids,KMeansParametersType); + + /** Set/Get the default label */ + itkSetMacro(DefaultLabel,LabelType); + itkGetMacro(DefaultLabel,LabelType); + + /** + * If set, only pixels within the mask will be classified. + * \param mask The input mask. + */ + void SetInputMask(const MaskImageType * mask); + + /** + * Get the input mask. + * \return The mask. + */ + const MaskImageType * GetInputMask(void); + + protected: + /** Constructor */ + KMeansImageClassificationFilter(); + /** Destructor */ + virtual ~KMeansImageClassificationFilter() {}; + + /** Threaded generate data */ + virtual void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread,int threadId); + /** Before threaded generate data */ + virtual void BeforeThreadedGenerateData(); + /**PrintSelf method */ + virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; + + private: + KMeansImageClassificationFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + /** Centroids used for classification */ + KMeansParametersType m_Centroids; + /** Default label for invalid pixels (when using a mask) */ + LabelType m_DefaultLabel; + /** Centroids - labels map */ + CentroidsMapType m_CentroidsMap; + }; +}// End namespace otb +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbKMeansImageClassificationFilter.txx" +#endif + +#endif diff --git a/Code/Learning/otbKMeansImageClassificationFilter.txx b/Code/Learning/otbKMeansImageClassificationFilter.txx new file mode 100644 index 0000000000..94afd618cb --- /dev/null +++ b/Code/Learning/otbKMeansImageClassificationFilter.txx @@ -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 _otbKMeansImageClassificationFilter_txx +#define _otbKMeansImageClassificationFilter_txx + +#include "otbKMeansImageClassificationFilter.h" +#include "itkImageRegionIterator.h" +#include "itkNumericTraits.h" + +namespace otb +{ +/** + * Constructor + */ +template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension, class TMaskImage> +KMeansImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension,TMaskImage> +::KMeansImageClassificationFilter() +{ + this->SetNumberOfInputs(2); + this->SetNumberOfRequiredInputs(1); + m_DefaultLabel = itk::NumericTraits<LabelType>::ZeroValue(); +} + +template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension, class TMaskImage> +void +KMeansImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension,TMaskImage> +::SetInputMask(const MaskImageType * mask) +{ + this->itk::ProcessObject::SetNthInput(1,const_cast<MaskImageType *>(mask)); +} + +template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension, class TMaskImage> +const typename KMeansImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension,TMaskImage> +::MaskImageType * +KMeansImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension,TMaskImage> +::GetInputMask() +{ + if(this->GetNumberOfInputs()<2) + { + return 0; + } + return static_cast<const MaskImageType *>(this->itk::ProcessObject::GetInput(1)); +} + +template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension, class TMaskImage> +void +KMeansImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension,TMaskImage> +::BeforeThreadedGenerateData() +{ + unsigned int sample_size = MaxSampleDimension; + unsigned int nb_classes = m_Centroids.Size()/sample_size; + + for(LabelType label = 1;label<=static_cast<LabelType>(nb_classes);++label) + { + SampleType new_centroid; + new_centroid.Fill(0); + m_CentroidsMap[label]=new_centroid; + + for(unsigned int i=0;i<MaxSampleDimension;++i) + { + m_CentroidsMap[label][i]=m_Centroids[MaxSampleDimension*(label-1)+i]; + } + } +} + +template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension, class TMaskImage> +void +KMeansImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension,TMaskImage> +::ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, int threadId) +{ + InputImageConstPointerType inputPtr = this->GetInput(); + MaskImageConstPointerType inputMaskPtr = this->GetInputMask(); + OutputImagePointerType outputPtr = this->GetOutput(); + + typedef itk::ImageRegionConstIterator<InputImageType> InputIteratorType; + typedef itk::ImageRegionConstIterator<MaskImageType> MaskIteratorType; + typedef itk::ImageRegionIterator<OutputImageType> OutputIteratorType; + + InputIteratorType inIt(inputPtr,outputRegionForThread); + OutputIteratorType outIt(outputPtr,outputRegionForThread); + + MaskIteratorType maskIt; + if(inputMaskPtr) + { + maskIt = MaskIteratorType(inputMaskPtr,outputRegionForThread); + maskIt.GoToBegin(); + } + unsigned int maxDimension = SampleType::Dimension; + unsigned int sampleSize = std::min(inputPtr->GetNumberOfComponentsPerPixel(), + maxDimension); + + bool validPoint = true; + + while(!outIt.IsAtEnd()) + { + outIt.Set(m_DefaultLabel); + ++outIt; + } + + outIt.GoToBegin(); + + validPoint = true; + + typename DistanceType::Pointer distance = DistanceType::New(); + + while(!outIt.IsAtEnd()&&(!inIt.IsAtEnd())) + { + if(inputMaskPtr) + { + validPoint = maskIt.Get()>0; + ++maskIt; + } + if(validPoint) + { + LabelType label =1; + LabelType current_label =1; + SampleType pixel; + pixel.Fill(0); + for(unsigned int i=0;i<sampleSize;++i) + { + pixel[i]=inIt.Get()[i]; + } + + double current_distance = distance->Evaluate(pixel,m_CentroidsMap[label]); + + for(label=2;label<=static_cast<LabelType>(m_CentroidsMap.size());++label) + { + double tmp_dist = distance->Evaluate(pixel,m_CentroidsMap[label]); + if(tmp_dist<current_distance) + { + current_label = label; + current_distance = tmp_dist; + } + } + std::cout<<"Pixel: "<<pixel<<" label: "<<current_label<<" centroid: "<<m_CentroidsMap[current_label]<<std::endl; + outIt.Set(current_label); + } + ++outIt; + ++inIt; + } +} +/** + * PrintSelf Method + */ +template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension, class TMaskImage> +void +KMeansImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension,TMaskImage> +::PrintSelf(std::ostream& os, itk::Indent indent) const +{ + Superclass::PrintSelf(os, indent); +} +} // End namespace otb +#endif diff --git a/Code/Learning/otbSOMImageClassificationFilter.h b/Code/Learning/otbSOMImageClassificationFilter.h new file mode 100644 index 0000000000..db9cb1d074 --- /dev/null +++ b/Code/Learning/otbSOMImageClassificationFilter.h @@ -0,0 +1,128 @@ +/*========================================================================= + +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 _otbSOMImageClassificationFilter_h +#define _otbSOMImageClassificationFilter_h + +#include "otbSOMClassifier.h" +#include "itkInPlaceImageFilter.h" +#include "itkFixedArray.h" +#include "itkListSample.h" + +namespace otb +{ + /** \class SOMImageClassificationFilter + * \brief This filter performs the classification of a VectorImage using a given SOM map. + * + * This filter is streamed and threaded, allowing to classify huge images. Because the + * internal sample type has to be an itk::FixedArray, one must specify at compilation time + * the maximum sample dimension. It is up to the user to specify a MaxSampleDimension sufficiently + * high to integrate all its features. This filter internally use one SVMClassifier per thread. + * + * \sa SVMClassifier + * \ingroup Streamed + * \ingroup Threaded + */ + template <class TInputImage, class TOutputImage,class TSOMMap, class TMaskImage = TOutputImage> + class ITK_EXPORT SOMImageClassificationFilter + : public itk::InPlaceImageFilter<TInputImage,TOutputImage> + { + public: + /** Standard typedefs */ + typedef SOMImageClassificationFilter Self; + typedef itk::InPlaceImageFilter<TInputImage,TOutputImage> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Type macro */ + itkNewMacro(Self); + + /** Creation through object factory macro */ + itkTypeMacro(SOMImageClassificationFilter,InPlaceImageFilter); + + typedef TInputImage InputImageType; + typedef typename InputImageType::ConstPointer InputImageConstPointerType; + typedef typename InputImageType::InternalPixelType ValueType; + + typedef TMaskImage MaskImageType; + typedef typename MaskImageType::ConstPointer MaskImageConstPointerType; + typedef typename MaskImageType::Pointer MaskImagePointerType; + + typedef TOutputImage OutputImageType; + typedef typename OutputImageType::Pointer OutputImagePointerType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + typedef typename OutputImageType::PixelType LabelType; + + typedef TSOMMap SOMMapType; + typedef typename SOMMapType::Pointer SOMMapPointerType; + typedef typename SOMMapType::PixelType SampleType; + + typedef itk::Statistics::ListSample<SampleType> ListSampleType; + typedef typename ListSampleType::Pointer ListSamplePointerType; + typedef otb::SOMClassifier<ListSampleType,SOMMapType,LabelType> ClassifierType; + typedef typename ClassifierType::Pointer ClassifierPointerType; + + /** Set/Get the svm model */ + itkSetObjectMacro(Map,SOMMapType); + itkGetObjectMacro(Map,SOMMapType); + + /** Set/Get the default label */ + itkSetMacro(DefaultLabel,LabelType); + itkGetMacro(DefaultLabel,LabelType); + + /** + * If set, only pixels within the mask will be classified. + * \param mask The input mask. + */ + void SetInputMask(const MaskImageType * mask); + + /** + * Get the input mask. + * \return The mask. + */ + const MaskImageType * GetInputMask(void); + + protected: + /** Constructor */ + SOMImageClassificationFilter(); + /** Destructor */ + virtual ~SOMImageClassificationFilter() {}; + + /** Threaded generate data */ + virtual void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread,int threadId); + /** Before threaded generate data */ + virtual void BeforeThreadedGenerateData(); + /**PrintSelf method */ + virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; + + private: + SOMImageClassificationFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + /** The SOM model used for classification */ + SOMMapPointerType m_Map; + /** Default label for invalid pixels (when using a mask) */ + LabelType m_DefaultLabel; + + + }; +}// End namespace otb +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbSOMImageClassificationFilter.txx" +#endif + +#endif diff --git a/Code/Learning/otbSOMImageClassificationFilter.txx b/Code/Learning/otbSOMImageClassificationFilter.txx new file mode 100644 index 0000000000..cc43b02fe5 --- /dev/null +++ b/Code/Learning/otbSOMImageClassificationFilter.txx @@ -0,0 +1,171 @@ +/*========================================================================= + +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 _otbSOMImageClassificationFilter_txx +#define _otbSOMImageClassificationFilter_txx + +#include "otbSOMImageClassificationFilter.h" +#include "itkImageRegionIterator.h" +#include "itkNumericTraits.h" + +namespace otb +{ +/** + * Constructor + */ +template <class TInputImage, class TOutputImage, class TSOMMap, class TMaskImage> +SOMImageClassificationFilter<TInputImage,TOutputImage,TSOMMap,TMaskImage> +::SOMImageClassificationFilter() +{ + this->SetNumberOfInputs(2); + this->SetNumberOfRequiredInputs(1); + m_DefaultLabel = itk::NumericTraits<LabelType>::ZeroValue(); +} + +template <class TInputImage, class TOutputImage, class TSOMMap, class TMaskImage> +void +SOMImageClassificationFilter<TInputImage,TOutputImage,TSOMMap,TMaskImage> +::SetInputMask(const MaskImageType * mask) +{ + this->itk::ProcessObject::SetNthInput(1,const_cast<MaskImageType *>(mask)); +} + +template <class TInputImage, class TOutputImage, class TSOMMap, class TMaskImage> +const typename SOMImageClassificationFilter<TInputImage,TOutputImage,TSOMMap,TMaskImage> +::MaskImageType * +SOMImageClassificationFilter<TInputImage,TOutputImage,TSOMMap,TMaskImage> +::GetInputMask() +{ + if(this->GetNumberOfInputs()<2) + { + return 0; + } + return static_cast<const MaskImageType *>(this->itk::ProcessObject::GetInput(1)); +} + +template <class TInputImage, class TOutputImage, class TSOMMap, class TMaskImage> +void +SOMImageClassificationFilter<TInputImage,TOutputImage,TSOMMap,TMaskImage> +::BeforeThreadedGenerateData() +{ + if(!m_Map) + { + itkGenericExceptionMacro(<<"No model for classification"); + } +} + +template <class TInputImage, class TOutputImage, class TSOMMap, class TMaskImage> +void +SOMImageClassificationFilter<TInputImage,TOutputImage,TSOMMap,TMaskImage> +::ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, int threadId) +{ + InputImageConstPointerType inputPtr = this->GetInput(); + MaskImageConstPointerType inputMaskPtr = this->GetInputMask(); + OutputImagePointerType outputPtr = this->GetOutput(); + + typedef itk::ImageRegionConstIterator<InputImageType> InputIteratorType; + typedef itk::ImageRegionConstIterator<MaskImageType> MaskIteratorType; + typedef itk::ImageRegionIterator<OutputImageType> OutputIteratorType; + + ListSamplePointerType listSample = ListSampleType::New(); + + InputIteratorType inIt(inputPtr,outputRegionForThread); + + MaskIteratorType maskIt; + if(inputMaskPtr) + { + maskIt = MaskIteratorType(inputMaskPtr,outputRegionForThread); + maskIt.GoToBegin(); + } + unsigned int maxDimension = m_Map->GetNumberOfComponentsPerPixel(); + unsigned int sampleSize = std::min(inputPtr->GetNumberOfComponentsPerPixel(), + maxDimension); + bool validPoint = true; + + for(inIt.GoToBegin();!inIt.IsAtEnd();++inIt) + { + if(inputMaskPtr) + { + validPoint = maskIt.Get()>0; + ++maskIt; + } + if(validPoint) + { + SampleType sample; + sample.SetSize(sampleSize); + sample.Fill(itk::NumericTraits<ValueType>::ZeroValue()); + for(unsigned int i=0;i<sampleSize;i++) + { + sample[i]=inIt.Get()[i]; + } + listSample->PushBack(sample); + } + } + ClassifierPointerType classifier =ClassifierType::New(); + classifier->SetMap(m_Map); + classifier->SetSample(listSample); + classifier->Update(); + + typename ClassifierType::OutputType::Pointer membershipSample = classifier->GetOutput(); + typename ClassifierType::OutputType::ConstIterator sampleIter = membershipSample->Begin(); + typename ClassifierType::OutputType::ConstIterator sampleLast = membershipSample->End(); + + OutputIteratorType outIt(outputPtr,outputRegionForThread); + + outIt.GoToBegin(); + + while(!outIt.IsAtEnd()&&(sampleIter!=sampleLast)) + { + outIt.Set(m_DefaultLabel); + ++outIt; + } + + outIt.GoToBegin(); + + if(inputMaskPtr) + { + maskIt.GoToBegin(); + } + validPoint = true; + + while(!outIt.IsAtEnd()&&(sampleIter!=sampleLast)) + { + if(inputMaskPtr) + { + validPoint = maskIt.Get()>0; + ++maskIt; + } + if(validPoint) + { + outIt.Set(sampleIter.GetClassLabel()); + ++sampleIter; + } + ++outIt; + } +} +/** + * PrintSelf Method + */ +template <class TInputImage, class TOutputImage, class TSOMMap, class TMaskImage> +void +SOMImageClassificationFilter<TInputImage,TOutputImage,TSOMMap,TMaskImage> +::PrintSelf(std::ostream& os, itk::Indent indent) const +{ + Superclass::PrintSelf(os, indent); +} +} // End namespace otb +#endif diff --git a/Code/Learning/otbSVMImageClassificationFilter.h b/Code/Learning/otbSVMImageClassificationFilter.h index f5e1d0ca59..db1cdfb919 100644 --- a/Code/Learning/otbSVMImageClassificationFilter.h +++ b/Code/Learning/otbSVMImageClassificationFilter.h @@ -15,8 +15,8 @@ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ -#ifndef _otbImageClassificationFilter_h -#define _otbImageClassificationFilter_h +#ifndef _otbSVMImageClassificationFilter_h +#define _otbSVMImageClassificationFilter_h #include "otbSVMClassifier.h" #include "itkInPlaceImageFilter.h" @@ -26,7 +26,7 @@ PURPOSE. See the above copyright notices for more information. namespace otb { - /** \class ImageClassificationFilter + /** \class SVMImageClassificationFilter * \brief This filter performs the classification of a VectorImage using a SVM Model. * * This filter is streamed and threaded, allowing to classify huge images. Because the @@ -38,7 +38,7 @@ namespace otb * \ingroup Streamed * \ingroup Threaded */ -template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension = 10> + template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension = 10, class TMaskImage = TOutputImage> class ITK_EXPORT SVMImageClassificationFilter : public itk::InPlaceImageFilter<TInputImage,TOutputImage> { @@ -65,6 +65,10 @@ template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimensio typedef typename InputImageType::ConstPointer InputImageConstPointerType; typedef typename InputImageType::InternalPixelType ValueType; + typedef TMaskImage MaskImageType; + typedef typename MaskImageType::ConstPointer MaskImageConstPointerType; + typedef typename MaskImageType::Pointer MaskImagePointerType; + typedef TOutputImage OutputImageType; typedef typename OutputImageType::Pointer OutputImagePointerType; typedef typename OutputImageType::RegionType OutputImageRegionType; @@ -77,12 +81,27 @@ template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimensio typedef typename ClassifierType::Pointer ClassifierPointerType; typedef SVMModel< ValueType, LabelType > ModelType; typedef typename ModelType::Pointer ModelPointerType; - typedef std::vector<ClassifierPointerType> ClassifierPointerVectorType; /** Set/Get the svm model */ itkSetObjectMacro(Model,ModelType); itkGetObjectMacro(Model,ModelType); + /** Set/Get the default label */ + itkSetMacro(DefaultLabel,LabelType); + itkGetMacro(DefaultLabel,LabelType); + + /** + * If set, only pixels within the mask will be classified. + * \param mask The input mask. + */ + void SetInputMask(const MaskImageType * mask); + + /** + * Get the input mask. + * \return The mask. + */ + const MaskImageType * GetInputMask(void); + protected: /** Constructor */ SVMImageClassificationFilter(); @@ -102,8 +121,10 @@ template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimensio /** The SVM model used for classification */ ModelPointerType m_Model; - /** Vector of classifier (one classifier per thread) */ - ClassifierPointerVectorType m_ClassifierVector; + /** Default label for invalid pixels (when using a mask) */ + LabelType m_DefaultLabel; + + }; }// End namespace otb #ifndef OTB_MANUAL_INSTANTIATION diff --git a/Code/Learning/otbSVMImageClassificationFilter.txx b/Code/Learning/otbSVMImageClassificationFilter.txx index 55d8cb0057..ac5ecb98e1 100644 --- a/Code/Learning/otbSVMImageClassificationFilter.txx +++ b/Code/Learning/otbSVMImageClassificationFilter.txx @@ -27,84 +27,143 @@ namespace otb /** * Constructor */ -template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension> -SVMImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension> +template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension, class TMaskImage> +SVMImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension,TMaskImage> ::SVMImageClassificationFilter() { - for(unsigned int i = 0;i<static_cast<unsigned int>(this->GetNumberOfThreads());++i) + this->SetNumberOfInputs(2); + this->SetNumberOfRequiredInputs(1); + m_DefaultLabel = itk::NumericTraits<LabelType>::ZeroValue(); +} + +template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension, class TMaskImage> +void +SVMImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension,TMaskImage> +::SetInputMask(const MaskImageType * mask) +{ + this->itk::ProcessObject::SetNthInput(1,const_cast<MaskImageType *>(mask)); +} + +template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension, class TMaskImage> +const typename SVMImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension,TMaskImage> +::MaskImageType * +SVMImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension,TMaskImage> +::GetInputMask() +{ + if(this->GetNumberOfInputs()<2) { - m_ClassifierVector.push_back(ClassifierType::New()); + return 0; } + return static_cast<const MaskImageType *>(this->itk::ProcessObject::GetInput(1)); } -template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension> +template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension, class TMaskImage> void -SVMImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension> +SVMImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension,TMaskImage> ::BeforeThreadedGenerateData() { if(!m_Model) { itkGenericExceptionMacro(<<"No model for classification"); } - for(unsigned int i = 0;i<static_cast<unsigned int>(this->GetNumberOfThreads());++i) - { - m_ClassifierVector[i]->SetModel(m_Model); - m_ClassifierVector[i]->SetNumberOfClasses(m_Model->GetNumberOfClasses()); - } } -template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension> +template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension, class TMaskImage> void -SVMImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension> +SVMImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension,TMaskImage> ::ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, int threadId) { - InputImageConstPointerType inputPtr = this->GetInput(); - OutputImagePointerType outputPtr = this->GetOutput(); + InputImageConstPointerType inputPtr = this->GetInput(); + MaskImageConstPointerType inputMaskPtr = this->GetInputMask(); + OutputImagePointerType outputPtr = this->GetOutput(); typedef itk::ImageRegionConstIterator<InputImageType> InputIteratorType; + typedef itk::ImageRegionConstIterator<MaskImageType> MaskIteratorType; typedef itk::ImageRegionIterator<OutputImageType> OutputIteratorType; ListSamplePointerType listSample = ListSampleType::New(); InputIteratorType inIt(inputPtr,outputRegionForThread); + + MaskIteratorType maskIt; + if(inputMaskPtr) + { + maskIt = MaskIteratorType(inputMaskPtr,outputRegionForThread); + maskIt.GoToBegin(); + } unsigned int sampleSize = std::min(inputPtr->GetNumberOfComponentsPerPixel(), VMaxSampleDimension); + + bool validPoint = true; + for(inIt.GoToBegin();!inIt.IsAtEnd();++inIt) { - MeasurementVectorType sample; - sample.Fill(itk::NumericTraits<ValueType>::ZeroValue()); - for(unsigned int i=0;i<sampleSize;i++) + if(inputMaskPtr) { - sample[i]=inIt.Get()[i]; + validPoint = maskIt.Get()>0; + ++maskIt; + } + if(validPoint) + { + MeasurementVectorType sample; + sample.Fill(itk::NumericTraits<ValueType>::ZeroValue()); + for(unsigned int i=0;i<sampleSize;i++) + { + sample[i]=inIt.Get()[i]; + } + listSample->PushBack(sample); } - listSample->PushBack(sample); } + ClassifierPointerType classifier =ClassifierType::New(); + classifier->SetModel(m_Model); + classifier->SetNumberOfClasses(m_Model->GetNumberOfClasses()); + classifier->SetSample(listSample); + classifier->Update(); + + typename ClassifierType::OutputType::Pointer membershipSample = classifier->GetOutput(); + typename ClassifierType::OutputType::ConstIterator sampleIter = membershipSample->Begin(); + typename ClassifierType::OutputType::ConstIterator sampleLast = membershipSample->End(); - m_ClassifierVector[threadId]->SetSample(listSample); - m_ClassifierVector[threadId]->Update(); - - typename ClassifierType::OutputType::Pointer membershipSample = m_ClassifierVector[threadId]->GetOutput() ; - typename ClassifierType::OutputType::ConstIterator sampleIter = membershipSample->Begin() ; - typename ClassifierType::OutputType::ConstIterator sampleLast = membershipSample->End() ; - OutputIteratorType outIt(outputPtr,outputRegionForThread); - + outIt.GoToBegin(); while(!outIt.IsAtEnd()&&(sampleIter!=sampleLast)) - { - outIt.Set(sampleIter.GetClassLabel()); - ++outIt; - ++sampleIter; - } + { + outIt.Set(m_DefaultLabel); + ++outIt; + } + + outIt.GoToBegin(); + + if(inputMaskPtr) + { + maskIt.GoToBegin(); + } + validPoint = true; + + while(!outIt.IsAtEnd()&&(sampleIter!=sampleLast)) + { + if(inputMaskPtr) + { + validPoint = maskIt.Get()>0; + ++maskIt; + } + if(validPoint) + { + outIt.Set(sampleIter.GetClassLabel()); + ++sampleIter; + } + ++outIt; + } } /** * PrintSelf Method */ -template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension> +template <class TInputImage, class TOutputImage, unsigned int VMaxSampleDimension, class TMaskImage> void -SVMImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension> +SVMImageClassificationFilter<TInputImage,TOutputImage,VMaxSampleDimension,TMaskImage> ::PrintSelf(std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); diff --git a/Testing/Code/Learning/CMakeLists.txt b/Testing/Code/Learning/CMakeLists.txt index 1730b07384..0af51f5029 100644 --- a/Testing/Code/Learning/CMakeLists.txt +++ b/Testing/Code/Learning/CMakeLists.txt @@ -209,6 +209,39 @@ ADD_TEST(leTvSOMClassifier ${LEARNING_TESTS3} ${TEMP}/leSOMPoupeesClassified.hdr ) +# ------- otb::SOMImageClassificationFilter ----------------------------- + +ADD_TEST(leTuSOMImageClassificationFilterNew ${LEARNING_TESTS3} + otbSOMImageClassificationFilterNew) + +ADD_TEST(leTvSOMImageClassificationFilter ${LEARNING_TESTS3} + --compare-image ${TOL} + ${BASELINE}/leSOMPoupeesClassified.hdr + ${TEMP}/leSOMImageClassificationFilterOuptut.hdr + otbSOMImageClassificationFilter + ${INPUTDATA}/poupees_sub.png + ${BASELINE}/leSOMPoupeesSubOutputMap1.hdr + ${TEMP}/leSOMImageClassificationFilterOuptut.hdr + ) + + +# ------- otb::KMeansImageClassificationFilter ----------------------------- + +ADD_TEST(leTuKMeansImageClassificationFilterNew ${LEARNING_TESTS3} + otbKMeansImageClassificationFilterNew) + +ADD_TEST(leTvKMeansImageClassificationFilter ${LEARNING_TESTS3} + --compare-image ${TOL} + ${BASELINE}/leKMeansImageClassificationFilterOuptut.hdr + ${TEMP}/leKMeansImageClassificationFilterOuptut.hdr + otbKMeansImageClassificationFilter + ${INPUTDATA}/poupees_sub.png + ${TEMP}/leKMeansImageClassificationFilterOuptut.hdr + 2 + 0 0 0 0 + 255 255 255 255 + ) + # ------- otb::SEMClassifier ----------------------------- ADD_TEST(leTuSEMClassifierNew ${LEARNING_TESTS3} @@ -289,6 +322,10 @@ otbSOMActivationBuilder.cxx SET(BasicLearning_SRCS3 otbSOMClassifierNew.cxx otbSOMClassifier.cxx +otbSOMImageClassificationFilterNew.cxx +otbSOMImageClassificationFilter.cxx +otbKMeansImageClassificationFilterNew.cxx +otbKMeansImageClassificationFilter.cxx otbSEMClassifierNew.cxx otbSVMImageClassificationFilterNew.cxx otbSVMImageClassificationFilter.cxx diff --git a/Testing/Code/Learning/otbKMeansImageClassificationFilter.cxx b/Testing/Code/Learning/otbKMeansImageClassificationFilter.cxx new file mode 100644 index 0000000000..ccd6707709 --- /dev/null +++ b/Testing/Code/Learning/otbKMeansImageClassificationFilter.cxx @@ -0,0 +1,71 @@ +/*========================================================================= + +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 "otbKMeansImageClassificationFilter.h" +#include "otbVectorImage.h" +#include "otbImage.h" +#include "otbImageFileReader.h" +#include "otbStreamingImageFileWriter.h" + +int otbKMeansImageClassificationFilter(int argc, char * argv[]) +{ + const char * infname = argv[1]; + const char * outfname = argv[2]; + const unsigned int nbClasses = atoi(argv[3]); + + const unsigned int Dimension = 2; + typedef double PixelType; + typedef unsigned short LabeledPixelType; + + typedef otb::VectorImage<PixelType,Dimension> ImageType; + typedef otb::Image<LabeledPixelType,Dimension> LabeledImageType; + typedef otb::KMeansImageClassificationFilter<ImageType,LabeledImageType> ClassificationFilterType; + typedef ClassificationFilterType::KMeansParametersType KMeansParametersType; + typedef otb::ImageFileReader<ImageType> ReaderType; + typedef otb::StreamingImageFileWriter<LabeledImageType> WriterType; + + + // Instantiating object + ClassificationFilterType::Pointer filter = ClassificationFilterType::New(); + + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(infname); + reader->GenerateOutputInformation(); + + unsigned int parameterSize = nbClasses * reader->GetOutput()->GetNumberOfComponentsPerPixel(); + KMeansParametersType parameters; + + parameters.SetSize(parameterSize); + parameters.Fill(0); + + for(unsigned int i = 0; i < parameterSize;++i) + { + parameters[i]=atof(argv[4+i]); + } + + std::cout<<"Parameters: "<<parameters<<std::endl; + + filter->SetCentroids(parameters); + filter->SetInput(reader->GetOutput()); + + WriterType::Pointer writer = WriterType::New(); + writer->SetInput(filter->GetOutput()); + writer->SetFileName(outfname); + writer->Update(); + + return EXIT_SUCCESS; +} diff --git a/Testing/Code/Learning/otbKMeansImageClassificationFilterNew.cxx b/Testing/Code/Learning/otbKMeansImageClassificationFilterNew.cxx new file mode 100644 index 0000000000..8c4a4d9cae --- /dev/null +++ b/Testing/Code/Learning/otbKMeansImageClassificationFilterNew.cxx @@ -0,0 +1,37 @@ +/*========================================================================= + +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 "otbKMeansImageClassificationFilter.h" +#include "otbVectorImage.h" +#include "otbImage.h" + +int otbKMeansImageClassificationFilterNew(int argc, char * argv[]) +{ + const unsigned int Dimension = 2; + typedef double PixelType; + typedef unsigned short LabeledPixelType; + + typedef otb::VectorImage<PixelType,Dimension> ImageType; + typedef otb::Image<LabeledPixelType,Dimension> LabeledImageType; + + typedef otb::KMeansImageClassificationFilter<ImageType,LabeledImageType> ClassificationFilterType; + + // Instantiating object + ClassificationFilterType::Pointer object = ClassificationFilterType::New(); + + return EXIT_SUCCESS; +} diff --git a/Testing/Code/Learning/otbLearningTests3.cxx b/Testing/Code/Learning/otbLearningTests3.cxx index 5ad0ccba58..20f5506ed3 100644 --- a/Testing/Code/Learning/otbLearningTests3.cxx +++ b/Testing/Code/Learning/otbLearningTests3.cxx @@ -30,6 +30,8 @@ void RegisterTests() { REGISTER_TEST(otbSOMClassifierNew); REGISTER_TEST(otbSOMClassifier); +REGISTER_TEST(otbSOMImageClassificationFilterNew); +REGISTER_TEST(otbSOMImageClassificationFilter); REGISTER_TEST(otbSEMClassifierNew); REGISTER_TEST(otbSVMImageClassificationFilterNew); REGISTER_TEST(otbSVMImageClassificationFilter); @@ -37,4 +39,6 @@ REGISTER_TEST(otbSVMModelGenericKernelsTest); REGISTER_TEST(otbSVMModelCopyTest); REGISTER_TEST(otbSVMModelCopyGenericKernelTest); REGISTER_TEST(otbSVMModelCopyComposedKernelTest); +REGISTER_TEST(otbKMeansImageClassificationFilterNew); +REGISTER_TEST(otbKMeansImageClassificationFilter); } diff --git a/Testing/Code/Learning/otbSOMImageClassificationFilter.cxx b/Testing/Code/Learning/otbSOMImageClassificationFilter.cxx new file mode 100644 index 0000000000..6aa4aa2eaa --- /dev/null +++ b/Testing/Code/Learning/otbSOMImageClassificationFilter.cxx @@ -0,0 +1,63 @@ +/*========================================================================= + +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 "otbSOMImageClassificationFilter.h" +#include "otbVectorImage.h" +#include "otbImage.h" +#include "otbSOMMap.h" +#include "otbImageFileReader.h" +#include "otbStreamingImageFileWriter.h" + +int otbSOMImageClassificationFilter(int argc, char * argv[]) +{ + const char * infname = argv[1]; + const char * somfname = argv[2]; + const char * outfname = argv[3]; + + const unsigned int Dimension = 2; + typedef double PixelType; + typedef unsigned short LabeledPixelType; + + typedef otb::VectorImage<PixelType,Dimension> ImageType; + typedef otb::Image<LabeledPixelType,Dimension> LabeledImageType; + typedef otb::SOMMap<ImageType::PixelType> SOMMapType; + typedef otb::SOMImageClassificationFilter<ImageType,LabeledImageType,SOMMapType> ClassificationFilterType; + typedef otb::ImageFileReader<ImageType> ReaderType; + typedef otb::ImageFileReader<SOMMapType> SOMReaderType; + typedef otb::StreamingImageFileWriter<LabeledImageType> WriterType; + + + // Instantiating object + ClassificationFilterType::Pointer filter = ClassificationFilterType::New(); + + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(infname); + + SOMReaderType::Pointer somreader = SOMReaderType::New(); + somreader->SetFileName(somfname); + somreader->Update(); + + filter->SetMap(somreader->GetOutput()); + filter->SetInput(reader->GetOutput()); + + WriterType::Pointer writer = WriterType::New(); + writer->SetInput(filter->GetOutput()); + writer->SetFileName(outfname); + writer->Update(); + + return EXIT_SUCCESS; +} diff --git a/Testing/Code/Learning/otbSOMImageClassificationFilterNew.cxx b/Testing/Code/Learning/otbSOMImageClassificationFilterNew.cxx new file mode 100644 index 0000000000..da5d6031f4 --- /dev/null +++ b/Testing/Code/Learning/otbSOMImageClassificationFilterNew.cxx @@ -0,0 +1,38 @@ +/*========================================================================= + +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 "otbSOMImageClassificationFilter.h" +#include "otbVectorImage.h" +#include "otbImage.h" +#include "otbSOMMap.h" + +int otbSOMImageClassificationFilterNew(int argc, char * argv[]) +{ + const unsigned int Dimension = 2; + typedef double PixelType; + typedef unsigned short LabeledPixelType; + + typedef otb::VectorImage<PixelType,Dimension> ImageType; + typedef otb::Image<LabeledPixelType,Dimension> LabeledImageType; + typedef otb::SOMMap<ImageType::PixelType> SOMMapType; + typedef otb::SOMImageClassificationFilter<ImageType,LabeledImageType,SOMMapType> ClassificationFilterType; + + // Instantiating object + ClassificationFilterType::Pointer filter = ClassificationFilterType::New(); + + return EXIT_SUCCESS; +} -- GitLab