From 96a664b06108918f2a154cb776b55dc32a6e3aea Mon Sep 17 00:00:00 2001 From: Julien Malik <julien.malik@c-s.fr> Date: Thu, 15 Nov 2012 13:37:27 +0100 Subject: [PATCH] ENH: add class StreamingStatisticsMapFromLabelImageFilter --- ...reamingStatisticsMapFromLabelImageFilter.h | 256 ++++++++++++++++++ ...amingStatisticsMapFromLabelImageFilter.txx | 208 ++++++++++++++ 2 files changed, 464 insertions(+) create mode 100644 Code/BasicFilters/otbStreamingStatisticsMapFromLabelImageFilter.h create mode 100644 Code/BasicFilters/otbStreamingStatisticsMapFromLabelImageFilter.txx diff --git a/Code/BasicFilters/otbStreamingStatisticsMapFromLabelImageFilter.h b/Code/BasicFilters/otbStreamingStatisticsMapFromLabelImageFilter.h new file mode 100644 index 0000000000..6a4bb4693f --- /dev/null +++ b/Code/BasicFilters/otbStreamingStatisticsMapFromLabelImageFilter.h @@ -0,0 +1,256 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.txt for details. + +Some parts of this code are derived from ITK. See ITKCopyright.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 __otbStreamingStatisticsMapFromLabelImageFilter_h +#define __otbStreamingStatisticsMapFromLabelImageFilter_h + +#include "otbPersistentImageFilter.h" +#include "itkNumericTraits.h" +#include "itkArray.h" +#include "itkSimpleDataObjectDecorator.h" +#include "otbPersistentFilterStreamingDecorator.h" + + +namespace otb +{ + +/** \class PersistentStreamingStatisticsMapFromLabelImageFilter + * \brief Computes mean radiometric value for each label of a label image, based on a support VectorImage + * + * This filter persists its temporary data. It means that if you Update it n times on n different + * requested regions, the output statistics will be the statitics of the whole set of n regions. + * + * To reset the temporary data, one should call the Reset() function. + * + * To get the statistics once the regions have been processed via the pipeline, use the Synthetize() method. + * + * \todo Implement other statistics (min, max, stddev...) + * + * \sa StreamingStatisticsMapFromLabelImageFilter + * \ingroup Streamed + * \ingroup Multithreaded + * \ingroup MathematicalStatisticsImageFilters + */ +template<class TInputVectorImage, class TLabelImage> +class ITK_EXPORT PersistentStreamingStatisticsMapFromLabelImageFilter : + public PersistentImageFilter<TInputVectorImage, TInputVectorImage> +{ +public: + /** Standard Self typedef */ + typedef PersistentStreamingStatisticsMapFromLabelImageFilter Self; + typedef PersistentImageFilter<TInputVectorImage, TInputVectorImage> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Runtime information support. */ + itkTypeMacro(PersistentStreamingStatisticsMapFromLabelImageFilter, PersistentImageFilter); + + /** Image related typedefs. */ + typedef TInputVectorImage VectorImageType; + typedef typename TInputVectorImage::Pointer InputVectorImagePointer; + typedef TLabelImage LabelImageType; + typedef typename TLabelImage::Pointer LabelImagePointer; + + typedef typename VectorImageType::PixelType VectorPixelType; + typedef typename LabelImageType::PixelType LabelPixelType; + typedef std::map<LabelPixelType, VectorPixelType> MeanValueMapType; + + itkStaticConstMacro(InputImageDimension, unsigned int, + TInputVectorImage::ImageDimension); + + /** Image related typedefs. */ + itkStaticConstMacro(ImageDimension, unsigned int, + TInputVectorImage::ImageDimension); + + /** Smart Pointer type to a DataObject. */ + typedef typename itk::DataObject::Pointer DataObjectPointer; + + /** Type of DataObjects used for scalar outputs */ + typedef itk::SimpleDataObjectDecorator<MeanValueMapType> MeanValueMapObjectType; + + /** Set input label image */ + virtual void SetInputLabelImage( const LabelImageType *image); + + /** Get input label image */ + virtual const LabelImageType * GetInputLabelImage(); + + /** Return the computed Mean for each label in the input label image */ + MeanValueMapType GetMeanValueMap() const + { + return this->GetMeanValueMap()->Get(); + } + + /** Return the computed Mean for each label in the input label image */ + MeanValueMapObjectType* GetMeanValueMap(); + + /** Return the computed Mean for each label in the input label image */ + const MeanValueMapObjectType* GetMeanValueMap() const; + + /** Make a DataObject of the correct type to be used as the specified + * output. */ + virtual DataObjectPointer MakeOutput(unsigned int idx); + + /** Pass the input through unmodified. Do this by Grafting in the + * AllocateOutputs method. + */ + void AllocateOutputs(); + + virtual void GenerateOutputInformation(); + + void Synthetize(void); + + void Reset(void); + +protected: + PersistentStreamingStatisticsMapFromLabelImageFilter(); + virtual ~PersistentStreamingStatisticsMapFromLabelImageFilter() {} + void PrintSelf(std::ostream& os, itk::Indent indent) const; + + /** GenerateData. */ + void GenerateData(); + +private: + PersistentStreamingStatisticsMapFromLabelImageFilter(const Self &); //purposely not implemented + void operator =(const Self&); //purposely not implemented + + MeanValueMapType m_RadiometricValueAccumulator; + std::map<LabelPixelType, unsigned int> m_LabelPopulation; +}; // end of class PersistentStreamingStatisticsMapFromLabelImageFilter + + +/*===========================================================================*/ + +/** \class StreamingStatisticsMapFromLabelImageFilter + * \brief Computes mean radiometric value for each label of a label image, based on a support VectorImage + * + * Currently the class only computes the mean value. + * + * This class streams the whole input image through the PersistentStreamingStatisticsMapFromLabelImageFilter. + * + * This way, it allows to compute the first order global statistics of this image. + * It calls the Reset() method of the PersistentStatisticsImageFilter before streaming + * the image and the Synthetize() method of the PersistentStatisticsImageFilter + * after having streamed the image to compute the statistics. + * The accessor on the results are wrapping the accessors of the + * internal PersistentStatisticsImageFilter. + * + * This filter can be used as: + * \code + * typedef otb::StreamingStatisticsMapFromLabelImageFilter<ImageType> StatisticsType; + * StatisticsType::Pointer statistics = StatisticsType::New(); + * statistics->SetInput(reader->GetOutput()); + * statistics->Update(); + * StatisticsType::MeanValueMapType meanValueMap = statistics->GetMeanValueMap(); + * StatisticsType::MeanValueMapType::const_iterator end = meanValueMap(); + * for (StatisticsType::MeanValueMapType::const_iterator it = meanValueMap.begin(); it != end; ++it) + * { + * std::cout << "label : " << it->first << " , "; + * << "mean value : " << it->second << std::endl; + * } + * \endcode + * + * \todo Implement other statistics (min, max, stddev...) + * \todo Reimplement as a multi-threaded filter + * + * \sa PersistentStatisticsImageFilter + * \sa PersistentImageFilter + * \sa PersistentFilterStreamingDecorator + * \sa StreamingImageVirtualWriter + * + * \ingroup Streamed + * \ingroup Multithreaded + * \ingroup MathematicalStatisticsImageFilters + */ + +template<class TInputVectorImage, class TLabelImage> +class ITK_EXPORT StreamingStatisticsMapFromLabelImageFilter : + public PersistentFilterStreamingDecorator<PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage> > +{ +public: + /** Standard Self typedef */ + typedef StreamingStatisticsMapFromLabelImageFilter Self; + typedef PersistentFilterStreamingDecorator + <PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage> > Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Type macro */ + itkNewMacro(Self); + + /** Creation through object factory macro */ + itkTypeMacro(StreamingStatisticsMapFromLabelImageFilter, PersistentFilterStreamingDecorator); + + typedef TInputVectorImage VectorImageType; + typedef TLabelImage LabelImageType; + + typedef typename Superclass::FilterType::MeanValueMapType MeanValueMapType; + typedef typename Superclass::FilterType::MeanValueMapObjectType MeanValueMapObjectType; + + /** Set input multispectral image */ + void SetInput(const VectorImageType * input) + { + this->GetFilter()->SetInput(input); + } + + /** Get input multispectral image */ + const VectorImageType * GetInput() + { + return this->GetFilter()->GetInput(); + } + + /** Set input label image (monoband) */ + void SetInputLabelImage(const LabelImageType * input) + { + this->GetFilter()->SetInputLabelImage(input); + } + + /** Get input label image (monoband) */ + const LabelImageType * GetInputLabelImage() + { + return this->GetFilter()->GetInputLabelImage(); + } + + /** Return the computed Mean for each label */ + MeanValueMapType GetMeanValueMap() const + { + return this->GetFilter()->GetMeanValueMap(); + } + +protected: + /** Constructor */ + StreamingStatisticsMapFromLabelImageFilter() {} + /** Destructor */ + virtual ~StreamingStatisticsMapFromLabelImageFilter() {} + +private: + StreamingStatisticsMapFromLabelImageFilter(const Self &); //purposely not implemented + void operator =(const Self&); //purposely not implemented +}; + +} // end namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbStreamingStatisticsMapFromLabelImageFilter.txx" +#endif + +#endif diff --git a/Code/BasicFilters/otbStreamingStatisticsMapFromLabelImageFilter.txx b/Code/BasicFilters/otbStreamingStatisticsMapFromLabelImageFilter.txx new file mode 100644 index 0000000000..84ce6674d4 --- /dev/null +++ b/Code/BasicFilters/otbStreamingStatisticsMapFromLabelImageFilter.txx @@ -0,0 +1,208 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.txt for details. + +Some parts of this code are derived from ITK. See ITKCopyright.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 __otbStreamingStatisticsMapFromLabelImageFilter_txx +#define __otbStreamingStatisticsMapFromLabelImageFilter_txx +#include "otbStreamingStatisticsMapFromLabelImageFilter.h" + +#include "itkImageRegionIterator.h" +#include "itkImageRegionConstIterator.h" +#include "itkNumericTraits.h" +#include "itkProgressReporter.h" +#include "otbMacro.h" + + +namespace otb +{ + +template<class TInputVectorImage, class TLabelImage> +PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage> +::PersistentStreamingStatisticsMapFromLabelImageFilter() +{ + // first output is a copy of the image, DataObject created by + // superclass + // + // allocate the data objects for the outputs which are + // just decorators around pixel types + typename MeanValueMapObjectType::Pointer output + = static_cast<MeanValueMapObjectType*>(this->MakeOutput(1).GetPointer()); + this->itk::ProcessObject::SetNthOutput(1, output.GetPointer()); + + this->Reset(); + +} + +template<class TInputVectorImage, class TLabelImage> +typename itk::DataObject::Pointer +PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage> +::MakeOutput(unsigned int output) +{ + switch (output) + { + case 0: + return static_cast<itk::DataObject*>(TInputVectorImage::New().GetPointer()); + break; + case 1: + return static_cast<itk::DataObject*>(MeanValueMapObjectType::New().GetPointer()); + break; + default: + // might as well make an image + return static_cast<itk::DataObject*>(TInputVectorImage::New().GetPointer()); + break; + } +} + +template<class TInputVectorImage, class TLabelImage> +void +PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage> +::SetInputLabelImage(const LabelImageType *input) +{ + // Process object is not const-correct so the const_cast is required here + this->itk::ProcessObject::SetNthInput(1, + const_cast< LabelImageType * >( input ) ); + +} + +template<class TInputVectorImage, class TLabelImage> +const typename PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage>::LabelImageType* +PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage> +::GetInputLabelImage() +{ + return static_cast< const TLabelImage * > + (this->itk::ProcessObject::GetInput(1)); +} + +template<class TInputVectorImage, class TLabelImage> +typename PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage>::MeanValueMapObjectType* +PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage> +::GetMeanValueMap() +{ + return static_cast<MeanValueMapObjectType*>(this->itk::ProcessObject::GetOutput(1)); +} + +template<class TInputVectorImage, class TLabelImage> +const typename PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage>::MeanValueMapObjectType* +PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage> +::GetMeanValueMap() const +{ + return static_cast<const MeanValueMapObjectType*>(this->itk::ProcessObject::GetOutput(1)); +} + +template<class TInputVectorImage, class TLabelImage> +void +PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage> +::GenerateOutputInformation() +{ + Superclass::GenerateOutputInformation(); + + if (this->GetInput()) + { + this->GetOutput()->CopyInformation(this->GetInput()); + this->GetOutput()->SetLargestPossibleRegion(this->GetInput()->GetLargestPossibleRegion()); + + if (this->GetOutput()->GetRequestedRegion().GetNumberOfPixels() == 0) + { + this->GetOutput()->SetRequestedRegion(this->GetOutput()->GetLargestPossibleRegion()); + } + } +} + +template<class TInputVectorImage, class TLabelImage> +void +PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage> +::AllocateOutputs() +{ + // This is commented to prevent the streaming of the whole image for the first stream strip + // It shall not cause any problem because the output image of this filter is not intended to be used. + //InputImagePointer image = const_cast< TInputImage * >( this->GetInput() ); + //this->GraftOutput( image ); + // Nothing that needs to be allocated for the remaining outputs +} + +template<class TInputVectorImage, class TLabelImage> +void +PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage> +::Synthetize() +{ + typename MeanValueMapType::iterator it; + for(it = m_RadiometricValueAccumulator.begin(); it != m_RadiometricValueAccumulator.end(); it++) + { + it->second = it->second / m_LabelPopulation[it->first]; + } + this->GetMeanValueMap()->Set(m_RadiometricValueAccumulator); +} + +template<class TInputVectorImage, class TLabelImage> +void +PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage> +::Reset() +{ + m_RadiometricValueAccumulator.clear(); +} + +template<class TInputVectorImage, class TLabelImage> +void +PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage> +::GenerateData() +{ + /** + * Grab the input + */ + InputVectorImagePointer inputPtr = const_cast<TInputVectorImage *>(this->GetInput()); + LabelImagePointer labelInputPtr = const_cast<TLabelImage *>(this->GetInputLabelImage()); + + itk::ImageRegionConstIterator<TInputVectorImage> inIt(inputPtr, inputPtr->GetRequestedRegion()); + itk::ImageRegionConstIterator<TLabelImage> labelIt(labelInputPtr, labelInputPtr->GetRequestedRegion()); + + + + typename VectorImageType::PixelType value; + typename LabelImageType::PixelType label; + // do the work + for (inIt.GoToBegin(), labelIt.GoToBegin(); + !inIt.IsAtEnd() && !labelIt.IsAtEnd(); + ++inIt, ++labelIt) + { + value = inIt.Get(); + label = labelIt.Get(); + if (m_RadiometricValueAccumulator.count(label)<=0) //add new element to the map + { + m_RadiometricValueAccumulator[label] = value; + m_LabelPopulation[label] = 1; + } + else + { + m_RadiometricValueAccumulator[label] += value; + m_LabelPopulation[label] ++; + } + + } +} + +template<class TInputVectorImage, class TLabelImage> +void +PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage> +::PrintSelf(std::ostream& os, itk::Indent indent) const +{ + Superclass::PrintSelf(os, indent); +} + +} // end namespace otb +#endif -- GitLab