diff --git a/Code/BasicFilters/otbStreamingInnerProductVectorImageFilter.h b/Code/BasicFilters/otbStreamingInnerProductVectorImageFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..569ce70428e1326a1875c8b03d85c3943406cdaf --- /dev/null +++ b/Code/BasicFilters/otbStreamingInnerProductVectorImageFilter.h @@ -0,0 +1,218 @@ +/*========================================================================= + + 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 MERCHANT2ABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __otbStreamingInnerProductVectorImageFilter_h +#define __otbStreamingInnerProductVectorImageFilter_h + + +#include "otbPersistentImageFilter.h" +#include "otbPersistentFilterStreamingDecorator.h" +#include "itkNumericTraits.h" +#include "itkArray.h" +#include "itkSimpleDataObjectDecorator.h" +#include "itkImageRegionSplitter.h" +#include "itkVariableSizeMatrix.h" +#include "itkVariableLengthVector.h" +#include "vnl/vnl_matrix.h" + + +namespace otb +{ + +/** \class StreamingInnerProductVectorImageFilter + * \brief Compute the inner product of a large image using streaming + * + * 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. + * + * \sa PersistentImageFilter + * \ingroup Streamed + * \ingroup Multithreaded + * \ingroup MathematicalStatisticsImageFilters + * + */ +template<class TInputImage> +class ITK_EXPORT PersistentInnerProductVectorImageFilter : + public PersistentImageFilter<TInputImage, TInputImage> +{ +public: + /** Standard Self typedef */ + typedef PersistentInnerProductVectorImageFilter Self; + typedef PersistentImageFilter<TInputImage,TInputImage> 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(PersistentInnerProductVectorImageFilter,PersistentImageFilter); + + /** Image related typedefs. */ + typedef TInputImage ImageType; + typedef typename TInputImage::Pointer InputImagePointer; + typedef typename TInputImage::RegionType RegionType; + typedef typename TInputImage::PixelType PixelType; + + itkStaticConstMacro(InputImageDimension, unsigned int, TInputImage::ImageDimension); + + /** Image related typedefs. */ + itkStaticConstMacro(ImageDimension, unsigned int, TInputImage::ImageDimension ); + + /** Smart Pointer type to a DataObject. */ + typedef typename itk::DataObject::Pointer DataObjectPointer; + + /** Type definition for a double matrix. */ + typedef vnl_matrix<double> MatrixType; + typedef typename std::vector<MatrixType> ArrayMatrixType; + + /** Type of DataObjects used for scalar outputs */ + typedef itk::SimpleDataObjectDecorator<MatrixType> MatrixObjectType; + + /** Return the computed inner product matrix. */ + + MatrixType GetInnerProduct() const + { + return this->GetInnerProductOutput()->Get(); + }; + MatrixObjectType* GetInnerProductOutput(); + const MatrixObjectType* GetInnerProductOutput() 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. + */ + virtual void AllocateOutputs(); + virtual void GenerateOutputInformation(); + virtual void Synthetize(void); + virtual void Reset(void); + +protected: + PersistentInnerProductVectorImageFilter(); + virtual ~PersistentInnerProductVectorImageFilter() {}; + virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; + /** Multi-thread version GenerateData. */ + void ThreadedGenerateData (const RegionType& outputRegionForThread,int threadId); + +private: + PersistentInnerProductVectorImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + ArrayMatrixType m_ThreadInnerProduct; + +}; // end of class PersistentStatisticsVectorImageFilter + +/**===========================================================================*/ + +/** \class StreamingInnerProductVectorImageFilter + * \brief This class streams the whole input image through the PersistentStatisticsImageFilter. + * + * This way, it allows to compute the inner product 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. + * + * \sa PersistentStatisticsVectorImageFilter + * \sa PersistentImageFilter + * \sa PersistentFilterStreamingDecorator + * \sa StreamingImageVirtualWriter + * \ingroup Streamed + * \ingroup Multithreaded + * \ingroup MathematicalStatisticsImageFilters + */ + +template<class TInputImage> +class ITK_EXPORT StreamingInnerProductVectorImageFilter : + public PersistentFilterStreamingDecorator< PersistentInnerProductVectorImageFilter<TInputImage> > +{ +public: + /** Standard Self typedef */ + typedef StreamingInnerProductVectorImageFilter Self; + typedef PersistentFilterStreamingDecorator + < PersistentInnerProductVectorImageFilter<TInputImage> > Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + + /** Type macro */ + itkNewMacro(Self); + + /** Creation through object factory macro */ + itkTypeMacro(StreamingInnerProductVectorImageFilter,PersistentFilterStreamingDecorator); + + typedef TInputImage InputImageType; + typedef typename Superclass::FilterType StatFilterType; + typedef typename StatFilterType::MatrixType MatrixType; + + + /** Type of DataObjects used for scalar outputs */ + typedef typename StatFilterType::MatrixObjectType MatrixObjectType; + + void SetInput(TInputImage * input) + { + this->GetFilter()->SetInput(input); + } + TInputImage * GetInput() + { + return this->GetFilter()->GetInput(); + } + + /** Return the computed inner product. */ + MatrixType GetInnerProduct() const + { + return this->GetFilter()->GetInnerProductOutput()->Get(); + }; + MatrixObjectType* GetInnerProductOutput() + { + return this->GetFilter()->GetInnerProductOutput(); + }; + const MatrixObjectType* GetInnerProductOutput() const + { + return this->GetFilter()->GetInnerProductOutput(); + }; + +protected: + /** Constructor */ + StreamingInnerProductVectorImageFilter() {}; + /** Destructor */ + virtual ~StreamingInnerProductVectorImageFilter() {}; + +private: + StreamingInnerProductVectorImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented +}; + +} // end namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbStreamingInnerProductVectorImageFilter.txx" +#endif + +#endif diff --git a/Code/BasicFilters/otbStreamingInnerProductVectorImageFilter.txx b/Code/BasicFilters/otbStreamingInnerProductVectorImageFilter.txx new file mode 100644 index 0000000000000000000000000000000000000000..83918751951b6f386f3a2abf50edef1cd503c5dc --- /dev/null +++ b/Code/BasicFilters/otbStreamingInnerProductVectorImageFilter.txx @@ -0,0 +1,243 @@ +/*========================================================================= + +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 __otbStreamingInnerProductVectorImageFilter_txx +#define __otbStreamingInnerProductVectorImageFilter_txx +#include "otbStreamingInnerProductVectorImageFilter.h" + +#include "itkImageRegionIterator.h" +#include "itkImageRegionConstIteratorWithIndex.h" +#include "itkNumericTraits.h" +#include "itkProgressReporter.h" +#include "otbMacro.h" + +namespace otb +{ + +template<class TInputImage> +PersistentInnerProductVectorImageFilter<TInputImage> +::PersistentInnerProductVectorImageFilter() +{ + // 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 + + // allocate the data objects for the outputs which are + // just decorators around matrix types + typename ImageType::Pointer output1 = static_cast<ImageType*>(this->MakeOutput(0).GetPointer()); + this->itk::ProcessObject::SetNthOutput(0, output1.GetPointer()); + typename MatrixObjectType::Pointer output2 = static_cast<MatrixObjectType*>(this->MakeOutput(1).GetPointer()); + this->itk::ProcessObject::SetNthOutput(1, output2.GetPointer()); +} + +template<class TInputImage> +itk::DataObject::Pointer +PersistentInnerProductVectorImageFilter<TInputImage> +::MakeOutput(unsigned int output) +{ + switch (output) + { + case 0: + return static_cast<itk::DataObject*>(TInputImage::New().GetPointer()); + break; + case 1: + return static_cast<itk::DataObject*>(MatrixObjectType::New().GetPointer()); + break; + default: + // might as well make an image + return static_cast<itk::DataObject*>(TInputImage::New().GetPointer()); + break; + } +} + +template<class TInputImage> +typename PersistentInnerProductVectorImageFilter<TInputImage>::MatrixObjectType* +PersistentInnerProductVectorImageFilter<TInputImage> +::GetInnerProductOutput() +{ + return static_cast<MatrixObjectType*>(this->itk::ProcessObject::GetOutput(1)); +} + +template<class TInputImage> +const typename PersistentInnerProductVectorImageFilter<TInputImage>::MatrixObjectType* +PersistentInnerProductVectorImageFilter<TInputImage> +::GetInnerProductOutput() const +{ + return static_cast<const MatrixObjectType*>(this->itk::ProcessObject::GetOutput(1)); +} + + +template<class TInputImage> +void +PersistentInnerProductVectorImageFilter<TInputImage> +::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 TInputImage> +void +PersistentInnerProductVectorImageFilter<TInputImage> +::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 TInputImage> +void +PersistentInnerProductVectorImageFilter<TInputImage> +::Reset() +{ + TInputImage * inputPtr = const_cast<TInputImage * >(this->GetInput()); + inputPtr->UpdateOutputInformation(); + + if (this->GetOutput()->GetRequestedRegion().GetNumberOfPixels()==0) + { + this->GetOutput()->SetRequestedRegion(this->GetOutput()->GetLargestPossibleRegion()); + } + + unsigned int numberOfThreads = this->GetNumberOfThreads(); + unsigned int numberOfTrainingImages = inputPtr->GetNumberOfComponentsPerPixel(); + // Set the number of training image + MatrixType tempMatrix; + tempMatrix.set_size(numberOfTrainingImages, numberOfTrainingImages); + tempMatrix.fill(0); + m_ThreadInnerProduct = ArrayMatrixType(numberOfThreads, tempMatrix); + + MatrixType initMatrix; + initMatrix.set_size(numberOfTrainingImages, numberOfTrainingImages); + initMatrix.fill(0); + this->GetInnerProductOutput()->Set( initMatrix ); + +} + +template<class TInputImage> +void +PersistentInnerProductVectorImageFilter<TInputImage> +::Synthetize() +{ + // Compute Inner product Matrix + TInputImage * inputPtr = const_cast<TInputImage * >(this->GetInput()); + unsigned int numberOfTrainingImages = inputPtr->GetNumberOfComponentsPerPixel(); + unsigned int numberOfThreads = this->GetNumberOfThreads(); + MatrixType innerProduct; + innerProduct.set_size( numberOfTrainingImages, numberOfTrainingImages ); + innerProduct.fill( 0 ); + + // Concatenate threaded matrix + for ( unsigned int thread = 0; thread < numberOfThreads; thread++) + { + innerProduct += m_ThreadInnerProduct[thread]; + } + + //--------------------------------------------------------------------- + // Fill the rest of the inner product matrix and make it symmetric + //--------------------------------------------------------------------- + for(unsigned int band_x = 0; band_x < (numberOfTrainingImages - 1); band_x++) + { + for(unsigned int band_y = band_x+1; band_y < numberOfTrainingImages; band_y++) + { + innerProduct[band_x][band_y] = innerProduct[band_y][band_x]; + }// end band_y loop + }// end band_x loop + + if( ( numberOfTrainingImages - 1 ) != 0 ) + { + innerProduct /= ( numberOfTrainingImages - 1 ); + } + else + { + innerProduct.fill(0); + } + + // Set the output + this->GetInnerProductOutput()->Set( innerProduct ); +} + +template<class TInputImage> +void +PersistentInnerProductVectorImageFilter<TInputImage> +::ThreadedGenerateData(const RegionType& outputRegionForThread, int threadId) +{ + /** + * Grab the input + */ + InputImagePointer inputPtr = const_cast< TInputImage * >( this->GetInput() ); + // support progress methods/callbacks + itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels()); + unsigned int numberOfTrainingImages = inputPtr->GetNumberOfComponentsPerPixel(); + + itk::ImageRegionConstIterator<TInputImage> it (inputPtr, outputRegionForThread); + it.GoToBegin(); + // do the work + while (!it.IsAtEnd()) + { + PixelType vectorValue = it.Get(); + double mean(0.); + for (unsigned int i=0; i<vectorValue.GetSize(); i++) + { + mean += static_cast<double>(vectorValue[i]); + } + mean /= static_cast<double>(vectorValue.GetSize()); + + // Matrix iteration + for(unsigned int band_x = 0; band_x < numberOfTrainingImages; band_x++) + { + for(unsigned int band_y = 0; band_y <= band_x; band_y++ ) + { + m_ThreadInnerProduct[threadId][band_x][band_y] += + (static_cast<double>(vectorValue[band_x]) - mean) * (static_cast<double>(vectorValue[band_y]) - mean); + } // end: band_y loop + } // end: band_x loop + ++it; + progress.CompletedPixel(); + }// end: looping through the image +} + +template <class TImage> +void +PersistentInnerProductVectorImageFilter<TImage> +::PrintSelf(std::ostream& os, itk::Indent indent) const +{ + Superclass::PrintSelf(os,indent); + + os << indent << "InnerProduct: " << this->GetInnerProductOutput()->Get() << std::endl; + +} + + +}// end namespace otb +#endif diff --git a/Testing/Code/BasicFilters/CMakeLists.txt b/Testing/Code/BasicFilters/CMakeLists.txt index 96c31626dddff3ede128eedc3a0cf91fa60aa267..3031a6dee25ce71170baa868d9765f34dccc020c 100644 --- a/Testing/Code/BasicFilters/CMakeLists.txt +++ b/Testing/Code/BasicFilters/CMakeLists.txt @@ -1184,6 +1184,17 @@ ADD_TEST(bfTvFunctionWithNeighborhoodToImageFilterNew ${BASICFILTERS_TESTS11} otbFunctionWithNeighborhoodToImageFilterNew ) +ADD_TEST(bfTuStreamingInnerProductVectorImageFilterNew ${BASICFILTERS_TESTS11} + otbStreamingInnerProductVectorImageFilterNew +) + +ADD_TEST(bfTvStreamingInnerProductVectorImageFilter ${BASICFILTERS_TESTS11} + otbStreamingInnerProductVectorImageFilter + ${INPUTDATA}/poupees_sub.png + ${TEMP}/bfTvStreamingInnerProductVectorImageFilterResults.txt +) + + # A enrichir SET(BasicFilters_SRCS1 @@ -1354,6 +1365,8 @@ otbKeyPointDensityImageFilterNew.cxx otbKeyPointDensityImageFilterTest.cxx otbImagePCAShapeModelEstimatorTest.cxx otbFunctionWithNeighborhoodToImageFilterNew.cxx +otbStreamingInnerProductVectorImageFilterNew.cxx +otbStreamingInnerProductVectorImageFilter.cxx ) diff --git a/Testing/Code/BasicFilters/otbBasicFiltersTests11.cxx b/Testing/Code/BasicFilters/otbBasicFiltersTests11.cxx index 94a81b14a92118c134641c662b5c78fb0f2146cf..a5670072ea8cacad484b7f75ad310ba32ef5dea3 100644 --- a/Testing/Code/BasicFilters/otbBasicFiltersTests11.cxx +++ b/Testing/Code/BasicFilters/otbBasicFiltersTests11.cxx @@ -37,4 +37,6 @@ void RegisterTests() REGISTER_TEST(otbKeyPointDensityImageFilterTest); REGISTER_TEST(otbImagePCAShapeModelEstimatorTest); REGISTER_TEST(otbFunctionWithNeighborhoodToImageFilterNew); + REGISTER_TEST(otbStreamingInnerProductVectorImageFilterNew); + REGISTER_TEST(otbStreamingInnerProductVectorImageFilter); } diff --git a/Testing/Code/BasicFilters/otbStreamingInnerProductVectorImageFilter.cxx b/Testing/Code/BasicFilters/otbStreamingInnerProductVectorImageFilter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ff94bec5753f58cfb16693e9b4cf8ea231ec7eae --- /dev/null +++ b/Testing/Code/BasicFilters/otbStreamingInnerProductVectorImageFilter.cxx @@ -0,0 +1,56 @@ +/*========================================================================= + + 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 "otbStreamingInnerProductVectorImageFilter.h" +#include "otbVectorImage.h" +#include "otbImageFileReader.h" +#include <fstream> + +int otbStreamingInnerProductVectorImageFilter( int argc, char* argv[] ) +{ + const char * inputFileName = argv[1]; + const char * outfname = argv[2]; + + typedef double PixelType; + const unsigned int Dimension = 2; + + // Typedef + typedef otb::VectorImage<PixelType,Dimension> ImageType; + typedef otb::ImageFileReader< ImageType > ReaderType; + typedef otb::StreamingInnerProductVectorImageFilter<ImageType> FilterType; + + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(inputFileName); + + // Instanciation object + FilterType::Pointer filter = FilterType::New(); + + filter->GetStreamer()->SetNumberOfStreamDivisions(10); + filter->SetInput(reader->GetOutput()); + filter->Update(); + + + std::ofstream file; + file.open(outfname); + file.precision(5); + file<<std::fixed; + file<<"Inner Product: Dim ["<<filter->GetInnerProduct().size()<<"]:"<<std::endl; + file<<filter->GetInnerProduct()<<std::endl; + file.close(); + + return EXIT_SUCCESS; +} diff --git a/Testing/Code/BasicFilters/otbStreamingInnerProductVectorImageFilterNew.cxx b/Testing/Code/BasicFilters/otbStreamingInnerProductVectorImageFilterNew.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0b7c15c002d3d6f785ca2c79b3a392993030df6b --- /dev/null +++ b/Testing/Code/BasicFilters/otbStreamingInnerProductVectorImageFilterNew.cxx @@ -0,0 +1,34 @@ +/*========================================================================= + + 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 "otbStreamingInnerProductVectorImageFilter.h" +#include "otbVectorImage.h" + +int otbStreamingInnerProductVectorImageFilterNew( int argc, char* argv[] ) +{ + typedef double PixelType; + const unsigned int Dimension = 2; + + // Typedef + typedef otb::VectorImage<PixelType,Dimension> ImageType; + typedef otb::StreamingInnerProductVectorImageFilter<ImageType> FilterType; + + // Instanciation object + FilterType::Pointer filter = FilterType::New(); + + return EXIT_SUCCESS; +}