diff --git a/Code/FeatureExtraction/otbMetaImageFunction.h b/Code/FeatureExtraction/otbMetaImageFunction.h index e2e85809bdbb07928b23ab1cf52c81ba975645d6..2d056fa826ca98d388f9e29b7e93dd5a627ab9bd 100644 --- a/Code/FeatureExtraction/otbMetaImageFunction.h +++ b/Code/FeatureExtraction/otbMetaImageFunction.h @@ -22,11 +22,21 @@ #include "itkPoint.h" #include "itkVariableLengthVector.h" +#include <vector> + namespace otb { /** \class MetaImageFunction - * \brief TODO + * \brief Concatenate results from multiple ImageFunction + * + * The MetaImageFunction class allows to call multiple ImageFunction at the same location + * and to concatenate their result into a single VariableLengthVector. + * + * In the case of ImageFunction which do not produce VariableLengthVector, one can wrap these + * function using the ImageFunctionAdaptor class, which will translate the image function output to + * a VariableLengthVector. * + * \ingroup ImageFunction */ template <class TOutputPrecision = double, class TCoordRep = double> class ITK_EXPORT MetaImageFunction @@ -54,9 +64,32 @@ public: typedef TOutputPrecision ValueType; typedef itk::VariableLengthVector<ValueType> OutputType; + // Compatible functions typedefs + typedef Superclass FunctionType; + typedef typename FunctionType::Pointer FunctionPointerType; + typedef std::vector<FunctionPointerType> FunctionContainerType; + /** Evaluate the function at the given location */ OutputType Evaluate(const PointType & point) const; + /** Add a new function to the functions vector */ + void AddFunction(FunctionType * function); + + /** Add a new function the functions vector (compatibility via adapters) */ +// template <typename T1, typename T2> void AddFunction(itk::ImageFunction<T1,T2,TCoordRep> * function); + + /** Clear functions vector */ + void ClearFunctions(); + + /** Get the number of function registered */ + unsigned int GetNumberOfFunctions() const; + + /** Retrieve the nth function */ + FunctionType * GetNthFunction(unsigned int index); + + /** Remove the nth function */ + void RemoveNthFunction(unsigned int index); + protected: /** Constructor */ MetaImageFunction(); @@ -70,6 +103,8 @@ protected: private: MetaImageFunction(const Self& ); //purposely not implemented void operator=(const Self& ); //purposely not implemented + + FunctionContainerType m_FunctionContainer; }; diff --git a/Code/FeatureExtraction/otbMetaImageFunction.txx b/Code/FeatureExtraction/otbMetaImageFunction.txx index 5f299735c352718467a4f0d4bd778d6765b7e40f..94239e2ba64cb89374e04f27b979c9bb0bd048ff 100644 --- a/Code/FeatureExtraction/otbMetaImageFunction.txx +++ b/Code/FeatureExtraction/otbMetaImageFunction.txx @@ -19,12 +19,15 @@ #define __otbMetaImageFunction_txx #include "otbMetaImageFunction.h" +#include "otbImageFunctionAdapter.h" + +#include <algorithm> namespace otb { template <class TOutputPrecision, class TCoordRep> MetaImageFunction<TOutputPrecision,TCoordRep> -::MetaImageFunction() +::MetaImageFunction() : m_FunctionContainer() { } @@ -33,17 +36,100 @@ template <class TOutputPrecision, class TCoordRep> MetaImageFunction<TOutputPrecision,TCoordRep> ::~MetaImageFunction() { + this->ClearFunctions(); + } + +template <class TOutputPrecision, class TCoordRep> +void +MetaImageFunction<TOutputPrecision,TCoordRep> +::AddFunction(FunctionType * function) + { + m_FunctionContainer.push_back(function); + } +//template <class TOutputPrecision, class TCoordRep, typename T1, typename T2> +//void +//MetaImageFunction<TOutputPrecision,TCoordRep> +//::AddFunction(itk::ImageFunction<T1,T2,TCoordRep> * function) +// { +// // Define the adapter +// typedef itk::ImageFunction<T1,T2,TCoordRep> ImageFunctionType; +// typedef otb::ImageFunctionAdapter<T1,ImageFunctionType,TCoordRep > AdapterType; +// +// typename AdapterType::Pointer adapter = AdapterType::New(); +// adapte +// +// } + +template <class TOutputPrecision, class TCoordRep> +void +MetaImageFunction<TOutputPrecision,TCoordRep> +::ClearFunctions() + { + m_FunctionContainer.clear(); + } + +template <class TOutputPrecision, class TCoordRep> +unsigned int +MetaImageFunction<TOutputPrecision,TCoordRep> +::GetNumberOfFunctions() const + { + return m_FunctionContainer.size(); } +template <class TOutputPrecision, class TCoordRep> +typename MetaImageFunction<TOutputPrecision,TCoordRep> +::FunctionType * +MetaImageFunction<TOutputPrecision,TCoordRep> +::GetNthFunction(unsigned int index) + { + return m_FunctionContainer.at(index); + } + + template <class TOutputPrecision, class TCoordRep> + void + MetaImageFunction<TOutputPrecision,TCoordRep> + ::RemoveNthFunction(unsigned int index) + { + typename FunctionContainerType::iterator fIt = m_FunctionContainer.begin()+index; + m_FunctionContainer.erase(fIt); + } + template <class TOutputPrecision, class TCoordRep> typename MetaImageFunction<TOutputPrecision,TCoordRep> ::OutputType MetaImageFunction<TOutputPrecision,TCoordRep> ::Evaluate(const PointType & point) const { + // Build output OutputType resp; + // For each function + typename FunctionContainerType::const_iterator fIt = m_FunctionContainer.begin(); + while(fIt != m_FunctionContainer.end()) + { + // Store current size + unsigned int currentSize = static_cast<unsigned int>(resp.GetSize()); + + // Call current function evaluation + OutputType currentVector = (*fIt)->Evaluate(point); + + // Compute current vector size + unsigned int currentVectorSize = static_cast<unsigned int>(currentVector.GetSize()); + + // Enlarge the output vector + resp.SetSize(currentSize + currentVectorSize,false); + + // Fill the output + for(unsigned int i = 0; i < currentVectorSize; ++i) + { + resp.SetElement(currentSize+i,static_cast<ValueType>(currentVector[i])); + } + + // Go to next function + ++fIt; + } + return resp; } @@ -54,6 +140,7 @@ MetaImageFunction<TOutputPrecision,TCoordRep> ::PrintSelf(std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); + os<<indent<<"Number of image functions: "<<this->GetNumberOfFunctions()<<std::endl; } } // end namespace otb diff --git a/Testing/Code/FeatureExtraction/CMakeLists.txt b/Testing/Code/FeatureExtraction/CMakeLists.txt index ee91fba126174323a444238caaae90ed140f0f0d..560bcf869530627cf44fba8f1214cefa96728ca2 100644 --- a/Testing/Code/FeatureExtraction/CMakeLists.txt +++ b/Testing/Code/FeatureExtraction/CMakeLists.txt @@ -1518,6 +1518,15 @@ ADD_TEST(feTuMetaImageFunctionNew ${FEATUREEXTRACTION_TESTS16} otbMetaImageFunctionNew ) +ADD_TEST(feTvMetaImageFunction ${FEATUREEXTRACTION_TESTS16} +--compare-ascii ${EPSILON_8} + ${BASELINE_FILES}/feTvMetaImageFunction.txt + ${TEMP}/feTvMetaImageFunction.txt + otbMetaImageFunction + ${INPUTDATA}/ROI_IKO_PAN_LesHalles.tif + ${TEMP}/feTvMetaImageFunction.txt + 451846.014047961 5412466.57452216 +) # A enrichir SET(BasicFeatureExtraction_SRCS1 diff --git a/Testing/Code/FeatureExtraction/otbFeatureExtractionTests16.cxx b/Testing/Code/FeatureExtraction/otbFeatureExtractionTests16.cxx index 7f6647cc38b5f499cb1317f5e65c28dafee9ef43..0b1ddb8e18db845756e4f2828bbf52142cf9ec51 100644 --- a/Testing/Code/FeatureExtraction/otbFeatureExtractionTests16.cxx +++ b/Testing/Code/FeatureExtraction/otbFeatureExtractionTests16.cxx @@ -35,4 +35,5 @@ void RegisterTests() REGISTER_TEST(otbImageFunctionAdapterNew); REGISTER_TEST(otbImageFunctionAdapter); REGISTER_TEST(otbMetaImageFunctionNew); + REGISTER_TEST(otbMetaImageFunction); } diff --git a/Testing/Code/FeatureExtraction/otbMetaImageFunction.cxx b/Testing/Code/FeatureExtraction/otbMetaImageFunction.cxx index 4c3e90ba5c9af9c3d435f49abad5875afd7241e1..fb5441ee64dcf4bc8085443f7e35c3dc8a9e2d12 100644 --- a/Testing/Code/FeatureExtraction/otbMetaImageFunction.cxx +++ b/Testing/Code/FeatureExtraction/otbMetaImageFunction.cxx @@ -20,8 +20,23 @@ #endif #include "otbMetaImageFunction.h" +#include "otbImage.h" +#include "otbImageFileReader.h" +#include "otbFlusserMomentsImageFunction.h" +#include "otbImageFunctionAdapter.h" -typedef otb::MetaImageFunction<> MetaImageFunctionType; +typedef unsigned short InputPixelType; +const unsigned int Dimension = 2; + +typedef otb::Image<InputPixelType, Dimension> InputImageType; +typedef otb::ImageFileReader<InputImageType> ReaderType; +typedef otb::FlusserMomentsImageFunction<InputImageType> FlusserFunctionType; +typedef otb::ImageFunctionAdapter<InputImageType,FlusserFunctionType> FunctionType; + +typedef otb::MetaImageFunction< + itk::NumericTraits<InputPixelType>::RealType,double> MetaImageFunctionType; +typedef MetaImageFunctionType::PointType PointType; +typedef MetaImageFunctionType::OutputType OutputType; int otbMetaImageFunctionNew(int argc, char * argv[]) { @@ -29,3 +44,62 @@ int otbMetaImageFunctionNew(int argc, char * argv[]) return EXIT_SUCCESS; } + +int otbMetaImageFunction(int argc, char * argv[]) +{ + // Read the input image + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(argv[1]); + reader->Update(); + + // Build flusser functions with different radius + FunctionType::Pointer function1 = FunctionType::New(); + FunctionType::Pointer function2 = FunctionType::New(); + FunctionType::Pointer function3 = FunctionType::New(); + + function1->SetInputImage(reader->GetOutput()); + function2->SetInputImage(reader->GetOutput()); + function3->SetInputImage(reader->GetOutput()); + + function1->GetImageFunction()->SetNeighborhoodRadius(3); + function2->GetImageFunction()->SetNeighborhoodRadius(5); + function3->GetImageFunction()->SetNeighborhoodRadius(7); + + std::ofstream outputStream(argv[2]); + + MetaImageFunctionType::Pointer metaFunction = MetaImageFunctionType::New(); + metaFunction->AddFunction(function1); + metaFunction->AddFunction(function2); + metaFunction->AddFunction(function3); + + outputStream<<"Initial number of functions: "<<metaFunction->GetNumberOfFunctions()<<std::endl; + + metaFunction->RemoveNthFunction(2); + + outputStream<<"Number of functions after removing the 2nd: "<<metaFunction->GetNumberOfFunctions()<<std::endl; + + metaFunction->ClearFunctions(); + + outputStream<<"Number of functions after clear: "<<metaFunction->GetNumberOfFunctions()<<std::endl; + + metaFunction->AddFunction(function1); + metaFunction->AddFunction(function2); + metaFunction->AddFunction(function3); + + outputStream<<"Adding functions again: "<<metaFunction->GetNumberOfFunctions()<<std::endl; + + // For coverage + metaFunction->GetNthFunction(0); + + PointType p; + p[0] = atof(argv[3]); + p[1] = atof(argv[4]); + + OutputType output = metaFunction->Evaluate(p); + + outputStream<<"Evaluate("<<p<<") = "<<output<<std::endl; + + outputStream.close(); + + return EXIT_SUCCESS; +}