From 0b03f59ca75a104b37b4c0d006a865a3dfcdecb1 Mon Sep 17 00:00:00 2001 From: Cyrille Valladeau <cyrille.valladeau@c-s.fr> Date: Fri, 30 Jan 2009 19:46:50 +0100 Subject: [PATCH] ENH : ENTROPY FUNCTOR added --- ...otbFunctionWithNeighborhoodToImageFilter.h | 1 + ...bFunctionWithNeighborhoodToImageFilter.txx | 12 +- ...FunctorNeighborhoodWithOffsetImageFilter.h | 4 + ...nctorNeighborhoodWithOffsetImageFilter.txx | 20 +- .../otbEnergyTextureFunctor.h | 3 +- .../otbEntropyTextureFunctor.h | 244 ++++++++++++++++++ Testing/Code/FeatureExtraction/CMakeLists.txt | 13 + .../otbEntropyTextureFunctor.cxx | 65 +++++ .../otbFeatureExtractionTests11.cxx | 1 + 9 files changed, 358 insertions(+), 5 deletions(-) create mode 100644 Code/FeatureExtraction/otbEntropyTextureFunctor.h create mode 100644 Testing/Code/FeatureExtraction/otbEntropyTextureFunctor.cxx diff --git a/Code/BasicFilters/otbFunctionWithNeighborhoodToImageFilter.h b/Code/BasicFilters/otbFunctionWithNeighborhoodToImageFilter.h index 968f0e920a..0b37640da2 100644 --- a/Code/BasicFilters/otbFunctionWithNeighborhoodToImageFilter.h +++ b/Code/BasicFilters/otbFunctionWithNeighborhoodToImageFilter.h @@ -134,6 +134,7 @@ private: InputImageSizeType m_Radius; InputImageOffsetType m_Offset; + //std::vector<FunctionType*> m_FunctionVector; }; } // end namespace otb diff --git a/Code/BasicFilters/otbFunctionWithNeighborhoodToImageFilter.txx b/Code/BasicFilters/otbFunctionWithNeighborhoodToImageFilter.txx index 6ea469338e..f51a774807 100644 --- a/Code/BasicFilters/otbFunctionWithNeighborhoodToImageFilter.txx +++ b/Code/BasicFilters/otbFunctionWithNeighborhoodToImageFilter.txx @@ -36,6 +36,7 @@ FunctionWithNeighborhoodToImageFilter<TInputImage,TOutputImage,TFunction> { m_Radius.Fill(0); m_Offset.Fill(0); + //m_FunctionVector.clear(); } @@ -47,7 +48,16 @@ FunctionWithNeighborhoodToImageFilter<TInputImage,TOutputImage,TFunction> Superclass::BeforeThreadedGenerateData(); m_Radius = this->GetFunction()->GetRadius(); - m_Offset = this->GetFunction()->GetOffset(); + m_Offset = this->GetFunction()->GetOffset(); + /* + for(unsigned int i =0; i<this->GetNumberOfThreads(); i++) + { + FunctionType * func; + func = (this->GetFunction()); + m_FunctionVector.push_back(func); + std::cout<<func<<std::endl; + } + */ } template <class TInputImage, class TOutputImage, class TFunction > diff --git a/Code/Common/otbUnaryFunctorNeighborhoodWithOffsetImageFilter.h b/Code/Common/otbUnaryFunctorNeighborhoodWithOffsetImageFilter.h index 159f6ce1f9..150046c004 100644 --- a/Code/Common/otbUnaryFunctorNeighborhoodWithOffsetImageFilter.h +++ b/Code/Common/otbUnaryFunctorNeighborhoodWithOffsetImageFilter.h @@ -120,6 +120,8 @@ protected: */ virtual ~UnaryFunctorNeighborhoodWithOffsetImageFilter() {}; + virtual void BeforeThreadedGenerateData(); + /** UnaryFunctorNeighborhoodWithOffsetImageFilter can be implemented as a multithreaded filter. * Therefore, this implementation provides a ThreadedGenerateData() routine * which is called for each processing thread. The output image data is @@ -136,6 +138,7 @@ protected: * Pad the input requested region by radius */ virtual void GenerateInputRequestedRegion(void); + std::vector<FunctorType> m_FunctorList; private: UnaryFunctorNeighborhoodWithOffsetImageFilter(const Self&); //purposely not implemented @@ -144,6 +147,7 @@ private: unsigned int m_Radius; FunctorType m_Functor; + InputImageOffsetType m_Offset; }; diff --git a/Code/Common/otbUnaryFunctorNeighborhoodWithOffsetImageFilter.txx b/Code/Common/otbUnaryFunctorNeighborhoodWithOffsetImageFilter.txx index e537531bc2..34b84c801a 100644 --- a/Code/Common/otbUnaryFunctorNeighborhoodWithOffsetImageFilter.txx +++ b/Code/Common/otbUnaryFunctorNeighborhoodWithOffsetImageFilter.txx @@ -39,9 +39,24 @@ UnaryFunctorNeighborhoodWithOffsetImageFilter<TInputImage,TOutputImage,TFunction this->SetNumberOfRequiredInputs( 1 ); m_Radius = 1; m_Offset.Fill(1); + m_FunctorList.clear(); } +template <class TInputImage, class TOutputImage, class TFunction > +void +UnaryFunctorNeighborhoodWithOffsetImageFilter<TInputImage,TOutputImage,TFunction> +::BeforeThreadedGenerateData() +{ + Superclass::BeforeThreadedGenerateData(); + + for(unsigned int i =0; i<this->GetNumberOfThreads(); i++) + { + m_FunctorList.push_back(m_Functor); + } + } + + template <class TInputImage, class TOutputImage, class TFunction > void UnaryFunctorNeighborhoodWithOffsetImageFilter<TInputImage,TOutputImage,TFunction> @@ -103,7 +118,7 @@ template <class TInputImage, class TOutputImage, class TFunction > void UnaryFunctorNeighborhoodWithOffsetImageFilter<TInputImage, TOutputImage, TFunction> ::ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, int threadId) -{ +{ std::cout<<"threadId : "<<threadId<<std::endl; itk::ZeroFluxNeumannBoundaryCondition<TInputImage> nbc; itk::ZeroFluxNeumannBoundaryCondition<TInputImage> nbcOff; // We use dynamic_cast since inputs are stored as DataObjects. The @@ -159,7 +174,7 @@ UnaryFunctorNeighborhoodWithOffsetImageFilter<TInputImage, TOutputImage, TFuncti while ( ! outputIt.IsAtEnd() ) { - outputIt.Set( m_Functor( neighInputIt, neighInputOffIt) ); + outputIt.Set( m_FunctorList[threadId]( neighInputIt, neighInputOffIt) ); ++neighInputIt; ++neighInputOffIt; @@ -169,6 +184,7 @@ UnaryFunctorNeighborhoodWithOffsetImageFilter<TInputImage, TOutputImage, TFuncti ++fit; ++fitOff; } +std::cout<<"threadIdFIN : "<<threadId<<std::endl; } } // end namespace otb diff --git a/Code/FeatureExtraction/otbEnergyTextureFunctor.h b/Code/FeatureExtraction/otbEnergyTextureFunctor.h index e04ed396c3..ac19adf18f 100644 --- a/Code/FeatureExtraction/otbEnergyTextureFunctor.h +++ b/Code/FeatureExtraction/otbEnergyTextureFunctor.h @@ -82,7 +82,6 @@ class EnergyTextureFunctor { offsetOff[0]++; offsetOff[1] = offsetOffInit[1]; - offset[0] = l; ll = l*l; for( int k = -static_cast<int>(radius[1]); k <= static_cast<int>(radius[1]); k++) @@ -90,7 +89,7 @@ class EnergyTextureFunctor offsetOff[1]++; offset[1] = k; norm = vcl_pow(static_cast<double>(itOff.GetPixel(offsetOff)[i]-itOff.GetCenterPixel()[i]), 2); - temp += norm; + temp += norm; } temp /= area; outPix[i] = static_cast<OutputPixelType>( vcl_pow(temp, 2) ); diff --git a/Code/FeatureExtraction/otbEntropyTextureFunctor.h b/Code/FeatureExtraction/otbEntropyTextureFunctor.h new file mode 100644 index 0000000000..65820cf48b --- /dev/null +++ b/Code/FeatureExtraction/otbEntropyTextureFunctor.h @@ -0,0 +1,244 @@ +/*========================================================================= + + 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 __otbEntropyTextureFunctor_h +#define __ootbEntropyTextureFunctor_h + +#include "otbMath.h" + +namespace otb +{ +namespace Functor + { + /** \class EntropyTextureFunctor + * \brief This functor calculates the local energy of an image + * + * Computes the sqaure gradient which is computed using offset and + * angle pixel of the neighborhood. + * TIterInput is an ietrator, TOutput is a PixelType. + * + * \ingroup Functor + * \ingroup Statistics + */ +template <class TIterInput1, class TIterInput2, class TOutput> +class EntropyTextureFunctor + { + public: + EntropyTextureFunctor() + { + m_Offset.Fill(1); + //m_BinLength = IntVectyorType(0, 1); + }; + ~EntropyTextureFunctor(){}; + + typedef TIterInput1 IterType1; + typedef TIterInput2 IterType2; + typedef TOutput OutputType; + typedef typename IterType1::OffsetType OffsetType; + typedef typename IterType1::RadiusType RadiusType; + typedef typename OutputType::ValueType OutputPixelType; + typedef std::vector<double> DoubleVectorType; + typedef std::vector<int> IntVectorType; + typedef std::vector<IntVectorType> IntVectorVectorType; + + void SetOffset(OffsetType off){ m_Offset=off; }; + OffsetType GetOffset(){ return m_Offset; }; + + IntVectorVectorType StatComputation(const TIterInput1 &it, const TIterInput2 &itOff) + { + IntVectorVectorType output; + IntVectorType binLength; + IntVectorType binLengthOff; + RadiusType radius = it.GetRadius(); + unsigned int nbComp = it.GetCenterPixel().GetSize(); + m_Mini = DoubleVectorType(nbComp, itk::NumericTraits<double>::max()); + m_MiniOff = DoubleVectorType(nbComp, itk::NumericTraits<double>::max()); + m_Maxi = DoubleVectorType(nbComp, itk::NumericTraits<double>::NonpositiveMin()); + m_MaxiOff = DoubleVectorType(nbComp, itk::NumericTraits<double>::NonpositiveMin()); + double area = static_cast<double>(radius[0]*radius[1]); + double areaInv = 1/area; + + OffsetType offset; + offset.Fill(0); + OffsetType offsetOff; + OffsetType offsetOffInit; + + offsetOffInit[0] = -radius[0]+m_Offset[0]-1; + offsetOffInit[1] = -radius[1]+m_Offset[1]-1; + IntVectorType mean; + IntVectorType meanOff; + for( unsigned int i=0; i<nbComp; i++ ) + { + offsetOff = offsetOffInit; + double meanCh = 0.; + double meanChOff = 0.; + for( int l = -static_cast<int>(radius[0]); l <= static_cast<int>(radius[0]); l++ ) + { + offsetOff[0]++; + offsetOff[1] = offsetOffInit[1]; + offset[0] = l; + for( int k = -static_cast<int>(radius[1]); k <= static_cast<int>(radius[1]); k++) + { + //std::cout<<it.GetPixel(offset)[i]<<std::endl; + offsetOff[1]++; + offset[1] = k; + meanCh += static_cast<double>(it.GetPixel(offset)[i]); + meanChOff += static_cast<double>(itOff.GetPixel(offsetOff)[i]); + + m_Mini[i] = std::min(static_cast<double>(it.GetPixel(offset)[i]), m_Mini[i]); + m_MiniOff[i] = std::min(static_cast<double>(itOff.GetPixel(offsetOff)[i]), m_MiniOff[i]); + m_Maxi[i] = std::max(static_cast<double>(it.GetPixel(offset)[i]), m_Maxi[i]); + m_MaxiOff[i] = std::max(static_cast<double>(itOff.GetPixel(offsetOff)[i]), m_MaxiOff[i]); + } + mean.push_back(meanCh * areaInv); + meanOff.push_back(meanChOff * areaInv); + } + } + + for( unsigned int i=0; i<nbComp; i++ ) + { + offsetOff = offsetOffInit; + double stdCh = 0.; + double stdChOff = 0.; + for( int l = -static_cast<int>(radius[0]); l <= static_cast<int>(radius[0]); l++ ) + { + offsetOff[0]++; + offsetOff[1] = offsetOffInit[1]; + offset[0] = l; + for( int k = -static_cast<int>(radius[1]); k <= static_cast<int>(radius[1]); k++) + { + offsetOff[1]++; + offset[1] = k; + stdCh += vcl_pow( (mean[i]-static_cast<double>(it.GetPixel(offset)[i])), 2); + stdChOff += vcl_pow( (meanOff[i]-static_cast<double>(itOff.GetPixel(offsetOff)[i])), 2); + } + } + stdCh *= areaInv; + stdCh = vcl_sqrt( stdCh ); + stdChOff *= areaInv; + stdChOff = vcl_sqrt( stdChOff ); + binLength.push_back( (3.5*stdCh) /(vcl_pow(area, 1/3) ) ); + binLengthOff.push_back( (3.5*stdChOff) /(vcl_pow(area, 1/3) ) ); + } + + output.push_back(binLength); + output.push_back(binLengthOff); + + return output; + } + + + inline TOutput operator()(const TIterInput1 &it, const TIterInput2 &itOff) + { + //std::cout<<"operator"<<std::endl; + IntVectorVectorType binsLength = this->StatComputation(it, itOff); + + RadiusType radius = it.GetRadius(); + unsigned int nbComp = it.GetCenterPixel().GetSize(); + double area = static_cast<double>(radius[0]*radius[1]); + double areaInv = 1/area; + OutputType outPix; + outPix.SetSize( nbComp ); + outPix.Fill(0); + + + OffsetType offset; + offset.Fill(0); + OffsetType offsetOff; + OffsetType offsetOffInit; + + offsetOffInit[0] = -radius[0]+m_Offset[0]-1; + offsetOffInit[1] = -radius[1]+m_Offset[1]-1; + + int histoIdX = 0; + int histoIdY = 0; + + for( unsigned int i=0; i<nbComp; i++ ) + { + //std::cout<<"i :"<<i<<" "<<std::endl; + + IntVectorType histoTemp; + IntVectorVectorType histo; + if(binsLength[0][i] != 0) + histoTemp = IntVectorType( vcl_floor((m_Maxi[i]-m_Mini[i])/binsLength[0][i])+1, 0 ); + else + histoTemp = IntVectorType( 1, 0 ); + if(binsLength[1][i] != 0) + histo = IntVectorVectorType( vcl_floor((m_MaxiOff[i]-m_MiniOff[i])/binsLength[1][i])+1, histoTemp ); + else + histo = IntVectorVectorType( 1, histoTemp ); + + //std::cout<<"m_Maxi[i]-m_Mini[i] "<<m_Maxi[i]<<" "<<m_Mini[i]<<std::endl; + //std::cout<<"binsLength[0][i] "<<binsLength[0][i]<<std::endl; + //std::cout<<histoTemp.size()<<" "<<histo.size()<<std::endl; + + offsetOff = offsetOffInit; + for( int l = -static_cast<int>(radius[0]); l <= static_cast<int>(radius[0]); l++ ) + { //std::cout<<"i :"<<i<<" "<<l<<std::endl; + offsetOff[0]++; + offsetOff[1] = offsetOffInit[1]; + offset[0] = l; + for( int k = -static_cast<int>(radius[1]); k <= static_cast<int>(radius[1]); k++) + { + //std::cout<<i<<" "<<l<<" "<<k<<std::endl; + offsetOff[1]++; + offset[1] = k; + if( binsLength[1][i] != 0) + histoIdX = vcl_floor( (itOff.GetPixel(offsetOff)[i]-m_MiniOff[i]) / binsLength[1][i] ); + else + histoIdX = 0; + if( binsLength[0][i] !=0 ) + histoIdY = vcl_floor( (it.GetPixel(offset)[i]-m_Mini[i]) / binsLength[0][i] ); + else + histoIdY = 0; + histo[histoIdX][histoIdY]++; + + } + } + for(unsigned r = 0; r<binsLength.size(); r++) + { + for(unsigned s = 0; s<binsLength[r].size(); s++) + { + double p = binsLength[r][s] * areaInv; + if(p != 0) + outPix[i] += static_cast<OutputPixelType>(p * vcl_log(p)); + } + } + + } + + //std::cout<<"operator FIN"<<std::endl; + return outPix; + + } + + private: + OffsetType m_Offset; + DoubleVectorType m_Mini; + DoubleVectorType m_MiniOff; + DoubleVectorType m_Maxi; + DoubleVectorType m_MaxiOff; + }; + + + + + } // namespace Functor +} // namespace otb + +#endif + diff --git a/Testing/Code/FeatureExtraction/CMakeLists.txt b/Testing/Code/FeatureExtraction/CMakeLists.txt index 7361936bf1..a4dd84ccb5 100644 --- a/Testing/Code/FeatureExtraction/CMakeLists.txt +++ b/Testing/Code/FeatureExtraction/CMakeLists.txt @@ -1052,6 +1052,18 @@ ADD_TEST(feTvEnergyTextureFunctor ${FEATUREEXTRACTION_TESTS11} 2 # offset[1] ) +# ------- otb::EntropyTextureFunctor ------------- +ADD_TEST(feTvEntropyTextureFunctor ${FEATUREEXTRACTION_TESTS11} +--compare-image ${EPS} + ${BASELINE}/feTvEntropyTextureFunctor.tif + ${TEMP}/feTvEntropyTextureFunctor.tif + otbEntropyTextureFunctor + ${INPUTDATA}/poupees.tif + ${TEMP}/feTvEntropyTextureFunctor.tif + 5 # radius + -2 # offset[0] + 2 # offset[1] +) # ------- otb::EnergyTextureImageFunction ------------- ADD_TEST(feTvEnergyTextureImageFunctionNew ${FEATUREEXTRACTION_TESTS11} @@ -1203,6 +1215,7 @@ otbSimplifyManyPathListFilter.cxx otbEnergyTextureFunctor.cxx otbEnergyTextureImageFunctionNew.cxx otbEnergyTextureImageFunction.cxx +otbEntropyTextureFunctor.cxx ) INCLUDE_DIRECTORIES("${OTBTesting_BINARY_DIR}") diff --git a/Testing/Code/FeatureExtraction/otbEntropyTextureFunctor.cxx b/Testing/Code/FeatureExtraction/otbEntropyTextureFunctor.cxx new file mode 100644 index 0000000000..fbaaaf0e8f --- /dev/null +++ b/Testing/Code/FeatureExtraction/otbEntropyTextureFunctor.cxx @@ -0,0 +1,65 @@ +/*========================================================================= + + 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 "otbUnaryFunctorNeighborhoodWithOffsetImageFilter.h" +#include "otbVectorImage.h" +#include "itkConstNeighborhoodIterator.h" +#include "otbImageFileReader.h" +#include "otbStreamingImageFileWriter.h" +#include "otbEntropyTextureFunctor.h" + + +int otbEntropyTextureFunctor(int argc, char * argv[]) +{ + const char * inputFileName = argv[1]; + const char * outputFileName = argv[2]; + + typedef double InputPixelType; + const int Dimension = 2; + typedef otb::VectorImage<InputPixelType,Dimension> ImageType; + typedef ImageType::PixelType PixelType; + typedef ImageType::OffsetType OffsetType; + typedef otb::ImageFileReader<ImageType> ReaderType; + typedef otb::StreamingImageFileWriter<ImageType> WriterType; + + typedef itk::ConstNeighborhoodIterator<ImageType> IterType;; + typedef otb::Functor::EntropyTextureFunctor<IterType, IterType, PixelType> FunctorType; + typedef otb::UnaryFunctorNeighborhoodWithOffsetImageFilter<ImageType, ImageType, FunctorType> UnaryFunctorNeighborhoodImageFilterType; + + // Instantiating object + UnaryFunctorNeighborhoodImageFilterType::Pointer object = UnaryFunctorNeighborhoodImageFilterType::New(); + ReaderType::Pointer reader = ReaderType::New(); + WriterType::Pointer writer = WriterType::New(); + reader->SetFileName(inputFileName); + writer->SetFileName(outputFileName); + + object->SetInput(reader->GetOutput()); + object->SetRadius(atoi(argv[3])); + OffsetType offset; + offset[0] = atoi(argv[4]); + offset[1] = atoi(argv[5]); + + object->SetOffset(offset); + writer->SetInput(object->GetOutput()); + + writer->Update(); + + + return EXIT_SUCCESS; +} diff --git a/Testing/Code/FeatureExtraction/otbFeatureExtractionTests11.cxx b/Testing/Code/FeatureExtraction/otbFeatureExtractionTests11.cxx index cba71ce767..c8e891cc6f 100644 --- a/Testing/Code/FeatureExtraction/otbFeatureExtractionTests11.cxx +++ b/Testing/Code/FeatureExtraction/otbFeatureExtractionTests11.cxx @@ -36,4 +36,5 @@ REGISTER_TEST(otbSimplifyManyPathListFilter); REGISTER_TEST(otbEnergyTextureFunctor); REGISTER_TEST(otbEnergyTextureImageFunctionNew); REGISTER_TEST(otbEnergyTextureImageFunction); +REGISTER_TEST(otbEntropyTextureFunctor); } -- GitLab