From 7e74d95583d5612f17071b38d22444d89a652d40 Mon Sep 17 00:00:00 2001 From: Christophe Palmann <christophe.palmann@c-s.fr> Date: Wed, 29 Oct 2014 11:34:05 +0100 Subject: [PATCH] WIP : otbBandMathX --> neighborhood access --- Code/BasicFilters/otbBandMathImageFilterX.h | 7 +- Code/BasicFilters/otbBandMathImageFilterX.txx | 224 ++++++++++++++---- Code/Common/otbParserX.cxx | 2 +- Code/Common/otbParserXPlugins.h | 208 ++++++++++------ Testing/Code/BasicFilters/CMakeLists.txt | 16 +- .../BasicFilters/otbBandMathImageFilterX.cxx | 148 ++++++++++++ .../BasicFilters/otbBasicFiltersTests13.cxx | 3 +- 7 files changed, 476 insertions(+), 132 deletions(-) diff --git a/Code/BasicFilters/otbBandMathImageFilterX.h b/Code/BasicFilters/otbBandMathImageFilterX.h index cab9e032ff..92feeb57bb 100644 --- a/Code/BasicFilters/otbBandMathImageFilterX.h +++ b/Code/BasicFilters/otbBandMathImageFilterX.h @@ -112,6 +112,9 @@ public: /** Set the expression to be parsed */ void SetExpression(const std::string& expression); + /** Set a matrix (or a vector) */ + void SetMatrix(const std::string& name, const std::string& definition); + /** Return the expression to be parsed */ std::string GetExpression(int) const; @@ -158,7 +161,9 @@ private : std::vector<ParserType::Pointer> m_VParser; std::vector< std::vector<adhocStruct2> > m_AImage; std::vector< adhocStruct > m_VVarName; - std::vector< adhocStruct > m_VAllowedVarName; + std::vector< adhocStruct > m_VAllowedVarNameAuto; + std::vector< adhocStruct > m_VAllowedVarNameAddedByUser; + std::vector< adhocStruct > m_VFinalAllowedVarName; // m_VAllowedVarNameAuto + m_VAllowedVarNameAddedByUser std::vector< adhocStruct > m_VNotAllowedVarName; unsigned int m_NbVar; std::vector< int > m_outputsDimensions; diff --git a/Code/BasicFilters/otbBandMathImageFilterX.txx b/Code/BasicFilters/otbBandMathImageFilterX.txx index 63a2df8505..a1b7ea6ffe 100644 --- a/Code/BasicFilters/otbBandMathImageFilterX.txx +++ b/Code/BasicFilters/otbBandMathImageFilterX.txx @@ -24,6 +24,7 @@ #include "itkImageRegionIterator.h" #include "itkImageRegionConstIterator.h" +#include "itkConstNeighborhoodIterator.h" #include "itkNumericTraits.h" #include "itkProgressReporter.h" #include "otbMacro.h" @@ -55,12 +56,12 @@ BandMathImageFilterX<TImage> adhocStruct ahcX; ahcX.name = "idxX"; ahcX.type = 0; - m_VAllowedVarName.push_back(ahcX); + m_VAllowedVarNameAuto.push_back(ahcX); adhocStruct ahcY; ahcY.name = "idxY"; ahcY.type = 1; - m_VAllowedVarName.push_back(ahcY); + m_VAllowedVarNameAuto.push_back(ahcY); //this->SetNumberOfThreads(1); @@ -113,7 +114,7 @@ void BandMathImageFilterX<TImage> ahcPhyX.name = sstmPhyX.str(); ahcPhyX.type = 2; ahcPhyX.info[0] = idx; // Input image #ID - m_VAllowedVarName.push_back(ahcPhyX); + m_VAllowedVarNameAuto.push_back(ahcPhyX); std::stringstream sstmPhyY; adhocStruct ahcPhyY; @@ -121,7 +122,7 @@ void BandMathImageFilterX<TImage> ahcPhyY.name = sstmPhyY.str(); ahcPhyY.type = 3; ahcPhyY.info[0] = idx; // Input image #ID - m_VAllowedVarName.push_back(ahcPhyY); + m_VAllowedVarNameAuto.push_back(ahcPhyY); //imi std::stringstream sstm; @@ -130,7 +131,7 @@ void BandMathImageFilterX<TImage> ahc.name = sstm.str(); ahc.type = 4; ahc.info[0] = idx; // Input image #ID - m_VAllowedVarName.push_back(ahc); + m_VAllowedVarNameAuto.push_back(ahc); //imibj for (int j=0; j<image->GetNumberOfComponentsPerPixel(); j++) @@ -142,25 +143,25 @@ void BandMathImageFilterX<TImage> ahc.type = 5; ahc.info[0] = idx; // Input image #ID ahc.info[1] = j; // Band #ID - m_VAllowedVarName.push_back(ahc); + m_VAllowedVarNameAuto.push_back(ahc); } //imibjNkxp - int size=0; + int size=10; for (int j=0; j<image->GetNumberOfComponentsPerPixel(); j++) - for(int k=1; k<=size; k++) - for(int p=1; p<=size; p++) + for(int x=0; x<=size; x++) + for(int y=0; y<=size; y++) { std::stringstream sstm; adhocStruct ahc; - sstm << varName << "b" << (j+1) << "N" << k << "x" << p; + sstm << varName << "b" << (j+1) << "N" << 2*x+1 << "x" << 2*y+1; ahc.name = sstm.str(); ahc.type = 6; ahc.info[0] = idx; // Input image #ID - ahc.info[1] = j; // Band #ID - ahc.info[2] = k; - ahc.info[3] = p; - m_VAllowedVarName.push_back(ahc); + ahc.info[1] = j; // Band #ID + ahc.info[2] = 2*x+1; // Size x direction (matrix convention = cols) + ahc.info[3] = 2*y+1; // Size y direction (matrix convention = rows) + m_VAllowedVarNameAuto.push_back(ahc); } } @@ -184,6 +185,68 @@ void BandMathImageFilterX<TImage> this->Modified(); } +template< typename TImage > +void BandMathImageFilterX<TImage> +::SetMatrix(const std::string& name, const std::string& definition) +{ + if (name.empty()) + itkExceptionMacro(<< "Please, set a name for your matrix/vector." << std::endl); + + if (definition.empty()) + itkExceptionMacro(<< "Please, set the definition of your matrix/vector." << std::endl); + + if ( (definition.find("{") != 0) || (definition.find("}")) != definition.size()-1 ) + itkExceptionMacro(<< "Definition of a matrix must begin with { and end with } characters." << std::endl); + + //Get rid of { and } characters + std::string def; + for(int i=1; i<definition.size()-1; ++i) + def.push_back(definition[i]); + + + std::vector< std::vector<double> > mat; + std::istringstream iss( def ); + std::string rows; + while (std::getline( iss, rows, ';' ) ) + { + mat.push_back(std::vector<double>(0)); + std::istringstream iss2( rows ); + std::string elmt; + while (std::getline( iss2, elmt, ',' ) ) + { + std::istringstream iss3( elmt ); + double val; + iss3 >> val; + //std::cout << val << std::endl; + mat.back().push_back(val); + } + } + + for(int i=0; i<mat.size(); i++) + { + std::cout << std::endl; + for(int j=0; j<mat[i].size(); j++) + std::cout << mat[i][j] << " "; + } + std::cout << std::endl; + + //Check dimensions of the matrix + for (int i=0; i<mat.size()-1; i++) + if (mat[i].size() != mat[i+1].size()) + itkExceptionMacro(<< "Each row must have the same number of cols : " << definition << std::endl); + + + std::stringstream sstm; + adhocStruct ahc; + sstm << name; + ahc.name = sstm.str(); + ahc.type = 7; + ahc.info[0] = mat[0].size(); // Size x direction (matrix convention = cols) + ahc.info[1] = mat.size(); // Size y direction (matrix convention = rows) + m_VAllowedVarNameAddedByUser.push_back(ahc); + +} + template< typename TImage > std::string BandMathImageFilterX<TImage> ::GetExpression(int IDExpression) const @@ -191,6 +254,7 @@ std::string BandMathImageFilterX<TImage> return m_Expression.at(IDExpression); } + template< typename TImage > std::vector<std::string>& BandMathImageFilterX<TImage> ::GetVarNames() const @@ -200,7 +264,6 @@ std::vector<std::string>& BandMathImageFilterX<TImage> res.push_back(m_VVarName[y].name); return res; - } @@ -226,27 +289,34 @@ void BandMathImageFilterX<TImage> // Generate variables names m_VVarName.clear(); m_VNotAllowedVarName.clear(); + m_VFinalAllowedVarName.clear(); + + //TODO + for(int i=0; i<m_VAllowedVarNameAddedByUser.size(); i++) + m_VFinalAllowedVarName.push_back(m_VAllowedVarNameAddedByUser[i]); + for(int i=0; i<m_VAllowedVarNameAuto.size(); i++) + m_VFinalAllowedVarName.push_back(m_VAllowedVarNameAuto[i]); this->SetNumberOfRequiredOutputs((int) m_Expression.size()); - for(int IDExpression=0; IDExpression<m_Expression.size(); ++IDExpression) + for(int IDExpression=0; IDExpression<m_Expression.size(); ++IDExpression) // For each expression { ParserType::Pointer dummyParser = ParserType::New(); dummyParser->SetExpr(this->GetExpression(IDExpression)); mup::var_maptype vmap = dummyParser->GetExprVar(); for (mup::var_maptype::iterator item = vmap.begin(); item!=vmap.end(); ++item) - { + {//std::cout << "item->first : " << item->first << std::endl; bool OK=false; int i=0; - while( ( !OK ) && (i<m_VAllowedVarName.size()) ) + while( ( !OK ) && (i<m_VFinalAllowedVarName.size()) ) { - if (item->first == m_VAllowedVarName[i].name) + if (item->first == m_VFinalAllowedVarName[i].name) OK=true; else i++; } - if (OK) {AddVariable(m_VAllowedVarName[i]);} + if (OK) {AddVariable(m_VFinalAllowedVarName[i]); } else { adhocStruct ahc; ahc.name = item->first; @@ -254,9 +324,10 @@ void BandMathImageFilterX<TImage> } } - } + }// At this step, m_VVarName has been built + //Checking formulas consistency if (m_VNotAllowedVarName.size()>0) { std::stringstream sstm; @@ -267,7 +338,7 @@ void BandMathImageFilterX<TImage> itkExceptionMacro(<< sstm.str()); } - + // Register variables for each parser (important : one parser per thread) m_VParser.clear(); unsigned int nbThreads = this->GetNumberOfThreads(); @@ -282,10 +353,10 @@ void BandMathImageFilterX<TImage> m_AImage.resize(nbThreads); - double initValue = 1.0; - for(int i = 0; i < nbThreads; ++i) + double initValue = 0.1; + for(int i = 0; i < nbThreads; ++i) // For each thread { - m_AImage[i].resize(m_NbVar); + m_AImage[i].resize(m_NbVar); // For each variable for(int j=0; j < m_NbVar; ++j) { @@ -325,14 +396,23 @@ void BandMathImageFilterX<TImage> if (m_AImage[i][j].type == 6 ) // neighborhood { - //TODO + m_AImage[i][j].value = ValueType(m_AImage[i][j].info[3],m_AImage[i][j].info[2],initValue); + } + + if (m_AImage[i][j].type == 7 ) // TODO + { + m_AImage[i][j].value = ValueType(m_AImage[i][j].info[1],m_AImage[i][j].info[0],0.0); + m_AImage[i][j].value.At(0,0)=0.1; + m_AImage[i][j].value.At(0,1)=0.5; + m_AImage[i][j].value.At(0,2)=0.1; + } m_VParser.at(i)->DefineVar(m_AImage[i][j].name, &(m_AImage[i][j].value)); - initValue += 0.01; - if (initValue>10.0) - initValue=1.0; + initValue += 0.001; + if (initValue>1.0) + initValue=0.1; } } @@ -366,10 +446,15 @@ void BandMathImageFilterX< TImage > case 'm': mup::matrix_type vect = value.GetArray(); - m_outputsDimensions.push_back(vect.GetCols()); + if ( vect.GetRows() == 1 ) //Vector + m_outputsDimensions.push_back(vect.GetCols()); + else //Matrix + itkExceptionMacro(<< "Result of the evaluation can't be a matrix." << std::endl); break; } + + std::cout << "Type = " << value.GetType() << " dimension = " << m_outputsDimensions.back() << std::endl; } } @@ -383,7 +468,7 @@ void BandMathImageFilterX< TImage > typedef itk::ImageBase< TImage::ImageDimension > ImageBaseType; typename ImageBaseType::Pointer outputPtr; - PrepareParsers(); // addition + PrepareParsers(); // addition OutputsDimensions(); // addition // Allocate the output memory @@ -400,7 +485,7 @@ void BandMathImageFilterX< TImage > if ( outputPtr ) { outputPtr->SetBufferedRegion( outputPtr->GetRequestedRegion() ); - outputPtr->SetNumberOfComponentsPerPixel(m_outputsDimensions[i]); + outputPtr->SetNumberOfComponentsPerPixel(m_outputsDimensions[i]); // addition outputPtr->Allocate(); } @@ -485,7 +570,9 @@ void BandMathImageFilterX<TImage> ValueType value; unsigned int nbInputImages = this->GetNumberOfInputs(); - // Iterators + //----------------- --------- -----------------// + //----------------- Iterators -----------------// + //----------------- --------- -----------------// typedef itk::ImageRegionConstIterator<TImage> ImageRegionConstIteratorType; std::vector< ImageRegionConstIteratorType > Vit; Vit.resize(nbInputImages); @@ -499,17 +586,36 @@ void BandMathImageFilterX<TImage> VoutIt[j] = ImageRegionConstIteratorType (this->GetOutput(j), outputRegionForThread); + //Special case : neighborhoods + + //std::vector< adhocStruct > ngbhName; + std::vector< itk::ConstNeighborhoodIterator<TImage> > VNit; + for(int j=0; j<m_VVarName.size(); ++j) + if (m_VVarName[j].type == 6) + { + typename itk::ConstNeighborhoodIterator<TImage>::RadiusType radius; + radius[0]=(int) ((m_VVarName[j].info[2]-1)/2); // Size x direction (otb convention) + radius[1]=(int) ((m_VVarName[j].info[3]-1)/2); // Size y direction (otb convention) + VNit.push_back( itk::ConstNeighborhoodIterator<TImage>(radius, this->GetNthInput(m_VVarName[j].info[0]),outputRegionForThread)); // info[0] = Input image ID + VNit.back().NeedToUseBoundaryConditionOn(); //TODO + } + + // Support progress methods/callbacks itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels()); - // Pixel affectation - for(int j=0; j < nbInputImages; ++j) {Vit[j].GoToBegin();} - for(int j=0; j < m_Expression.size(); ++j) {VoutIt[j].GoToBegin();} - //outIt.GoToBegin(); + + //----------------- --------------------- -----------------// + //----------------- Variable affectations -----------------// + //----------------- --------------------- -----------------// + for(int j=0; j < nbInputImages; ++j) { Vit[j].GoToBegin(); } + for(int j=0; j < m_Expression.size(); ++j) { VoutIt[j].GoToBegin(); } + for(int j=0; j < VNit.size(); ++j) { VNit[j].GoToBegin(); } while(!Vit.at(0).IsAtEnd()) // For each pixel { + int ngbhNameIndex=0; int index=0; for(int j=0; j < m_AImage[threadId].size(); ++j) // For each variable, perform a copy { @@ -546,14 +652,35 @@ void BandMathImageFilterX<TImage> case 6 : //neighborhood // TODO + + // m_AImage[threadId][j].info[1] : Band #ID + if (m_AImage[threadId][j].info[2]*m_AImage[threadId][j].info[3] != VNit[ngbhNameIndex].Size() ) + itkExceptionMacro(<< "Size of muparserx variable is different from its related otb neighborhood iterator") + + for(int cols=0; cols<m_AImage[threadId][j].info[2]; ++cols) + for(int rows=0; rows<m_AImage[threadId][j].info[3]; ++rows) + { + m_AImage[threadId][j].value.At(rows,cols) = VNit[ngbhNameIndex].GetPixel(index)[m_AImage[threadId][j].info[1]]; + index++; + } + + ngbhNameIndex++; + break; + + case 7 : + //Nothing to do break; default : itkExceptionMacro(<< "Type of the variable is unknown"); break; } - } + }//End while + + //----------------- ----------- -----------------// + //----------------- Evaluations -----------------// + //----------------- ----------- -----------------// for(int IDExpression=0; IDExpression<m_Expression.size(); ++IDExpression) { @@ -579,18 +706,22 @@ void BandMathImageFilterX<TImage> break; case 'c': - itkExceptionMacro(<< "Complex numbers not supported." << std::endl); + itkExceptionMacro(<< "Complex numbers are not supported." << std::endl); break; case 'm': mup::matrix_type vect = value.GetArray(); - for(int p=0; p<vect.GetCols(); ++p) - VoutIt[IDExpression].Get()[p] = vect.At(0,p); - break; + if ( vect.GetRows() == 1 ) //Vector + for(int p=0; p<vect.GetCols(); ++p) + VoutIt[IDExpression].Get()[p] = vect.At(0,p).GetFloat(); + else //Matrix + itkExceptionMacro(<< "Result of the evaluation can't be a matrix." << std::endl); + break; } - + + //----------------- Pixel affectations -----------------// for(int p=0; p<VoutIt[IDExpression].Get().GetSize(); ++p) { // Case value is equal to -inf or inferior to the minimum value @@ -611,9 +742,10 @@ void BandMathImageFilterX<TImage> } - for(int j=0; j < nbInputImages; ++j) {++Vit[j];} - for(int j=0; j < m_Expression.size(); ++j) {++VoutIt[j];} - + for(int j=0; j < nbInputImages; ++j) { ++Vit[j]; } + for(int j=0; j < m_Expression.size(); ++j) { ++VoutIt[j]; } + for(int j=0; j < VNit.size(); ++j) { ++VNit[j]; } + progress.CompletedPixel(); } diff --git a/Code/Common/otbParserX.cxx b/Code/Common/otbParserX.cxx index b3082a34bf..9b4fb4d314 100644 --- a/Code/Common/otbParserX.cxx +++ b/Code/Common/otbParserX.cxx @@ -58,7 +58,7 @@ public: virtual void InitFun() { m_MuParserX.DefineFun(new ndvi); - //m_MuParserX.DefineFun(new conv); + m_MuParserX.DefineFun(new conv); m_MuParserX.DefineFun(new bands); m_MuParserX.DefineFun(new vcos); m_MuParserX.DefineFun(new vsin); diff --git a/Code/Common/otbParserXPlugins.h b/Code/Common/otbParserXPlugins.h index 698365eee8..d2495f73d5 100644 --- a/Code/Common/otbParserXPlugins.h +++ b/Code/Common/otbParserXPlugins.h @@ -65,53 +65,75 @@ public: }; - -class ndvi : public mup::ICallback +class conv : public mup::ICallback { public: - ndvi():ICallback(mup::cmFUNC, "ndvi", 2) + conv():ICallback(mup::cmFUNC, "conv", -1) {} virtual void Eval(mup::ptr_val_type &ret, const mup::ptr_val_type *a_pArg, int a_iArgc) { // Get the argument from the argument input vector - mup::float_type r = a_pArg[0]->GetFloat(); + mup::matrix_type m1 = a_pArg[0]->GetArray(); - mup::float_type niri = a_pArg[1]->GetFloat(); + int nbrows = m1.GetRows(); + int nbcols = m1.GetCols(); - // The return value is passed by writing it to the reference ret - if ( vcl_abs(r + niri) < 1E-6 ) - *ret = 0.; - else - *ret = (niri-r)/(niri+r); + //matrix_type m3(nbrows,nbcols,0); + + mup::matrix_type res(a_iArgc-1,1,0); + + for (int k=1; k<a_iArgc; ++k) + { + + float sum=0.0; + + mup::matrix_type m2 = a_pArg[k]->GetArray(); + + for (int i=0; i<nbrows; i++) + for (int j=0; j<nbcols; j++) + sum += m1.At(i,j).GetFloat() * m2.At(i,j).GetFloat(); + + + res.At(k-1,0)=sum; + } + + + // The return value is passed by writing it to the reference ret + *ret = res; } const mup::char_type* GetDesc() const { - return "NDVI - Normalized Difference Vegetation Index"; + return "conv(m1,m2) - A matrix convolution"; } mup::IToken* Clone() const { - return new ndvi(*this); + return new conv(*this); } }; -//--------------------------------------------------------------------------------------------------------// -class vcos : public mup::ICallback + +class MatDiv : public mup::IOprtBin { -public: - vcos():ICallback(mup::cmFUNC, "vcos", 1) + public: + MatDiv():IOprtBin(_T("div"), (int)(mup::prMUL_DIV), mup::oaLEFT) {} - virtual void Eval(mup::ptr_val_type &ret, const mup::ptr_val_type *a_pArg, int a_iArgc) + virtual void Eval(mup::ptr_val_type &ret, const mup::ptr_val_type *a_pArg, int) { - // Get the argument from the argument input vector const mup::matrix_type a = a_pArg[0]->GetArray(); + const mup::matrix_type b = a_pArg[1]->GetArray(); + /*if (!arg1->IsNonComplexScalar()) + throw ParserError( ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg1->GetType(), 'f', 1)); + if (!arg2->IsNonComplexScalar()) + throw ParserError( ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg2->GetType(), 'f', 2));*/ + int nbrows = a.GetRows(); int nbcols = a.GetCols(); @@ -119,37 +141,43 @@ public: for (int k=0; k<nbcols; ++k) for (int p=0; p<nbrows; ++p) - res.At(p,k) = vcl_cos(a.At(p,k).GetFloat()); + res.At(p,k) = a.At(p,k).GetFloat() / b.At(p,k).GetFloat(); // The return value is passed by writing it to the reference ret - *ret = res; + *ret = res; } - const mup::char_type* GetDesc() const - { - return "vcos - Cosinus for noncomplex vectors & matrices"; + virtual const mup::char_type* GetDesc() const + { + return _T("x ./ y - Division for noncomplex vectors & matrices"); } - - mup::IToken* Clone() const - { - return new vcos(*this); + + virtual mup::IToken* Clone() const + { + return new MatDiv(*this); } }; -class vsin : public mup::ICallback + +class MatConv : public mup::IOprtBin { -public: - vsin():ICallback(mup::cmFUNC, "vsin", 1) + public: + MatConv():IOprtBin(_T("mult"), (int)(mup::prMUL_DIV), mup::oaLEFT) {} - virtual void Eval(mup::ptr_val_type &ret, const mup::ptr_val_type *a_pArg, int a_iArgc) + virtual void Eval(mup::ptr_val_type &ret, const mup::ptr_val_type *a_pArg, int) { - // Get the argument from the argument input vector const mup::matrix_type a = a_pArg[0]->GetArray(); + const mup::matrix_type b = a_pArg[1]->GetArray(); + /*if (!arg1->IsNonComplexScalar()) + throw ParserError( ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg1->GetType(), 'f', 1)); + if (!arg2->IsNonComplexScalar()) + throw ParserError( ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg2->GetType(), 'f', 2));*/ + int nbrows = a.GetRows(); int nbcols = a.GetCols(); @@ -157,41 +185,71 @@ public: for (int k=0; k<nbcols; ++k) for (int p=0; p<nbrows; ++p) - res.At(p,k) = vcl_sin(a.At(p,k).GetFloat()); - + res.At(p,k) = a.At(p,k).GetFloat() * b.At(p,k).GetFloat(); + // The return value is passed by writing it to the reference ret - *ret = res; + *ret = res; + } + + virtual const mup::char_type* GetDesc() const + { + return _T("x mult y - Convolution for noncomplex vectors & matrices"); + } + + virtual mup::IToken* Clone() const + { + return new MatConv(*this); + } + }; + + + +class ndvi : public mup::ICallback + { +public: + ndvi():ICallback(mup::cmFUNC, "ndvi", 2) + {} + + virtual void Eval(mup::ptr_val_type &ret, const mup::ptr_val_type *a_pArg, int a_iArgc) + { + // Get the argument from the argument input vector + mup::float_type r = a_pArg[0]->GetFloat(); + + mup::float_type niri = a_pArg[1]->GetFloat(); + + + // The return value is passed by writing it to the reference ret + if ( vcl_abs(r + niri) < 1E-6 ) + *ret = 0.; + else + *ret = (niri-r)/(niri+r); } const mup::char_type* GetDesc() const { - return "vsin - Sinus for noncomplex vectors & matrices"; + return "NDVI - Normalized Difference Vegetation Index"; } mup::IToken* Clone() const { - return new vsin(*this); + return new ndvi(*this); } }; -class MatDiv : public mup::IOprtBin +//--------------------------------------------------------------------------------------------------------// +class vcos : public mup::ICallback { - public: - MatDiv():IOprtBin(_T("div"), (int)(mup::prMUL_DIV), mup::oaLEFT) +public: + vcos():ICallback(mup::cmFUNC, "vcos", 1) {} - virtual void Eval(mup::ptr_val_type &ret, const mup::ptr_val_type *a_pArg, int) + virtual void Eval(mup::ptr_val_type &ret, const mup::ptr_val_type *a_pArg, int a_iArgc) { + // Get the argument from the argument input vector const mup::matrix_type a = a_pArg[0]->GetArray(); - const mup::matrix_type b = a_pArg[1]->GetArray(); - /*if (!arg1->IsNonComplexScalar()) - throw ParserError( ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg1->GetType(), 'f', 1)); - if (!arg2->IsNonComplexScalar()) - throw ParserError( ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg2->GetType(), 'f', 2));*/ - int nbrows = a.GetRows(); int nbcols = a.GetCols(); @@ -199,41 +257,37 @@ class MatDiv : public mup::IOprtBin for (int k=0; k<nbcols; ++k) for (int p=0; p<nbrows; ++p) - res.At(p,k) = a.At(p,k).GetFloat() / b.At(p,k).GetFloat(); + res.At(p,k) = vcl_cos(a.At(p,k).GetFloat()); // The return value is passed by writing it to the reference ret - *ret = res; + *ret = res; } - virtual const mup::char_type* GetDesc() const - { - return _T("x ./ y - Division for noncomplex vectors & matrices"); + const mup::char_type* GetDesc() const + { + return "vcos - Cosinus for noncomplex vectors & matrices"; } - - virtual mup::IToken* Clone() const - { - return new MatDiv(*this); + + mup::IToken* Clone() const + { + return new vcos(*this); } }; -class MatConv : public mup::IOprtBin + +class vsin : public mup::ICallback { - public: - MatConv():IOprtBin(_T("mult"), (int)(mup::prMUL_DIV), mup::oaLEFT) +public: + vsin():ICallback(mup::cmFUNC, "vsin", 1) {} - virtual void Eval(mup::ptr_val_type &ret, const mup::ptr_val_type *a_pArg, int) + virtual void Eval(mup::ptr_val_type &ret, const mup::ptr_val_type *a_pArg, int a_iArgc) { + // Get the argument from the argument input vector const mup::matrix_type a = a_pArg[0]->GetArray(); - const mup::matrix_type b = a_pArg[1]->GetArray(); - /*if (!arg1->IsNonComplexScalar()) - throw ParserError( ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg1->GetType(), 'f', 1)); - if (!arg2->IsNonComplexScalar()) - throw ParserError( ErrorContext(ecTYPE_CONFLICT_FUN, -1, GetIdent(), arg2->GetType(), 'f', 2));*/ - int nbrows = a.GetRows(); int nbcols = a.GetCols(); @@ -241,24 +295,26 @@ class MatConv : public mup::IOprtBin for (int k=0; k<nbcols; ++k) for (int p=0; p<nbrows; ++p) - res.At(p,k) = a.At(p,k).GetFloat() * b.At(p,k).GetFloat(); - + res.At(p,k) = vcl_sin(a.At(p,k).GetFloat()); + // The return value is passed by writing it to the reference ret - *ret = res; + *ret = res; } - virtual const mup::char_type* GetDesc() const - { - return _T("x mult y - Convolution for noncomplex vectors & matrices"); + const mup::char_type* GetDesc() const + { + return "vsin - Sinus for noncomplex vectors & matrices"; } - - virtual mup::IToken* Clone() const - { - return new MatConv(*this); + + mup::IToken* Clone() const + { + return new vsin(*this); } }; + + }//end namespace otb #endif diff --git a/Testing/Code/BasicFilters/CMakeLists.txt b/Testing/Code/BasicFilters/CMakeLists.txt index d147b73c4a..1096ef9b93 100644 --- a/Testing/Code/BasicFilters/CMakeLists.txt +++ b/Testing/Code/BasicFilters/CMakeLists.txt @@ -2117,22 +2117,24 @@ add_test(bfTvImageAndVectorImageOperationFilterTest ${BASICFILTERS_TESTS12} add_test(bfTuBandMathImageFilter ${BASICFILTERS_TESTS13} otbBandMathImageFilterNew) -add_test(bfTuBandMathImageFilterX ${BASICFILTERS_TESTS13} - otbBandMathImageFilterXNew) - add_test(bfTvBandMathImageFilter ${BASICFILTERS_TESTS13} otbBandMathImageFilter) -add_test(bfTvBandMathImageFilterX ${BASICFILTERS_TESTS13} - otbBandMathImageFilterX) - - add_test(bfTvBandMathImageFilterWithIdx ${BASICFILTERS_TESTS13} otbBandMathImageFilterWithIdx ${TEMP}/bfTvBandMathImageFilterWithIdx1.tif ${TEMP}/bfTvBandMathImageFilterWithIdx2.tif ) +add_test(bfTuBandMathImageFilterXNew ${BASICFILTERS_TESTS13} + otbBandMathImageFilterXNew) + +add_test(bfTvBandMathImageFilterX ${BASICFILTERS_TESTS13} + otbBandMathImageFilterX) + +add_test(bfTvotbBandMathImageFilterXConv ${BASICFILTERS_TESTS13} + otbBandMathImageFilterXConv) + add_test(bfTvBandMathImageFilterXWithIdx ${BASICFILTERS_TESTS13} otbBandMathImageFilterXWithIdx ${TEMP}/bfTvBandMathImageFilterWithIdx1.tif diff --git a/Testing/Code/BasicFilters/otbBandMathImageFilterX.cxx b/Testing/Code/BasicFilters/otbBandMathImageFilterX.cxx index 6ab50093e4..9930766e55 100644 --- a/Testing/Code/BasicFilters/otbBandMathImageFilterX.cxx +++ b/Testing/Code/BasicFilters/otbBandMathImageFilterX.cxx @@ -199,6 +199,154 @@ int otbBandMathImageFilterX( int itkNotUsed(argc), char* itkNotUsed(argv) []) } +int otbBandMathImageFilterXConv( int itkNotUsed(argc), char* itkNotUsed(argv) []) +{ + + typedef otb::VectorImage<double, 2> ImageType; + typedef ImageType::PixelType PixelType; + typedef otb::BandMathImageFilterX<ImageType> FilterType; + + unsigned int i; + const unsigned int N = 100, D1=3, D2=1, D3=1; + unsigned int FAIL_FLAG = 0; + + ImageType::SizeType size; + size.Fill(N); + ImageType::IndexType index; + index.Fill(0); + ImageType::RegionType region; + region.SetSize(size); + region.SetIndex(index); + + ImageType::Pointer image1 = ImageType::New(); + ImageType::Pointer image2 = ImageType::New(); + ImageType::Pointer image3 = ImageType::New(); + + image1->SetLargestPossibleRegion( region ); + image1->SetBufferedRegion( region ); + image1->SetRequestedRegion( region ); + image1->SetNumberOfComponentsPerPixel(D1); + image1->Allocate(); + + image2->SetLargestPossibleRegion( region ); + image2->SetBufferedRegion( region ); + image2->SetRequestedRegion( region ); + image2->SetNumberOfComponentsPerPixel(D2); + image2->Allocate(); + + image3->SetLargestPossibleRegion( region ); + image3->SetBufferedRegion( region ); + image3->SetRequestedRegion( region ); + image3->SetNumberOfComponentsPerPixel(D3); + image3->Allocate(); + + typedef itk::ConstNeighborhoodIterator<ImageType> IteratorType; + typename IteratorType::RadiusType radius; + radius[0]=1; // Size x direction + radius[1]=0; // Size y direction + + IteratorType it1(radius, image1, region); + IteratorType it2(radius, image2, region); + IteratorType it3(radius, image3, region); + + for (it1.GoToBegin(), it2.GoToBegin(), it3.GoToBegin(); !it1.IsAtEnd(); ++it1, ++it2, ++it3) + { + ImageType::IndexType i1 = it1.GetIndex(); + ImageType::IndexType i2 = it2.GetIndex(); + ImageType::IndexType i3 = it3.GetIndex(); + + it1.GetCenterPixel()[0] = i1[0] + i1[1] -50; it1.GetCenterPixel()[1] = i1[0] * i1[1] -50; it1.GetCenterPixel()[2] = i1[0] / (i1[1]+1)+5; + it2.GetCenterPixel()[0] = i2[0] * i2[1]; + it3.GetCenterPixel()[0] = i3[0] + i3[1] * i3[1]; + + } + + + FilterType::Pointer filter = FilterType::New(); + std::cout << "Number Of Threads : " << filter->GetNumberOfThreads() << std::endl; + + + filter->SetNthInput(0, image1); + filter->SetNthInput(1, image2); + filter->SetNthInput(2, image3, "canal3"); + filter->SetMatrix("kernel1N3x1","{0.1 , 0.5 , 0.1}"); + filter->SetExpression("conv(kernel1N3x1,im1b1N3x1)"); + filter->Update(); + + if (filter->GetNumberOfOutputs() != 1) + itkGenericExceptionMacro( <<std::endl << "Error = wrong number of outputs "); + + + ImageType::Pointer output1 = filter->GetOutput(0); + + if (output1->GetNumberOfComponentsPerPixel() != 1) + itkGenericExceptionMacro( <<std::endl << "Error = wrong number of components per pixel "); + + std::cout << "\n--- Standard Use\n"; + std::cout << "Parsed Expression : " << filter->GetExpression(0) << std::endl; + + + + //Sub-test 1 + IteratorType itoutput1(radius, output1, region); + + for (it1.GoToBegin(), it2.GoToBegin(), it3.GoToBegin(), itoutput1.GoToBegin(); !it1.IsAtEnd(); ++it1, ++it2, ++it3, ++itoutput1) + { + ImageType::IndexType i1 = it1.GetIndex(); + ImageType::IndexType i2 = it2.GetIndex(); + ImageType::IndexType i3 = it3.GetIndex(); + PixelType px1(D1),px2(D2),px3(D3); + + px1[0]=0; float coefs[3]={0.1,0.5,0.1}; + for(int i=0; i<it1.Size(); ++i) + px1[0] += coefs[i]*it1.GetPixel(i)[0]; + //px1[1] = ( i1[0] * i1[1] -50 ); px1[2] = ( i1[0] / (i1[1]+1)+5 ); + + + px2[0] = ( i2[0] * i2[1] ); + px3[0] = ( i3[0] + i3[1] * i3[1] ); + + double result1 = itoutput1.GetCenterPixel()[0], result2 = itoutput1.GetCenterPixel()[1], result3 = itoutput1.GetCenterPixel()[2]; + double error1,error2,error3; + + double expected1 = px1[0]; + /*double expected2 = px1[1]; + double expected3 = px1[2]; */ + + /*std::cout << "Pixel_1 = " << it1.Get()[0] << " Pixel_2 = " << it2.Get()[0] << " Pixel_3 = " << it3.Get()[0] + << " Result = " << itoutput1.Get()[0] << " Expected = " << expected1 << std::endl;*/ + + + error1 = (result1 - expected1) * (result1 - expected1) / (result1 + expected1); + /*error2 = (result2 - expected2) * (result2 - expected2) / (result2 + expected2); + error3 = (result3 - expected3) * (result3 - expected3) / (result3 + expected3);*/ + + if ( ( error1 > 1E-9 ) /*|| ( error2 > 1E-9 ) || ( error3 > 1E-9 )*/) + { + itkGenericExceptionMacro( <<std::endl +<< "Error = " << error1 << " > 1E-9 -> TEST FAILLED" << std::endl + << "Pixel_[-1]_band1 = " << it1.GetPixel(0)[0] + << " Pixel_[0]_band1 = " << it1.GetPixel(1)[0] + << " Pixel_[1]_band1 = " << it1.GetPixel(2)[0] + << " Result = " << result1 + << " Expected = " << expected1 << std::endl); +/*<< "Error = " << error2 << " > 1E-9 -> TEST FAILLED" << std::endl + << "Pixel_[-1]_band2 = " << it1.GetPixel(0)[1] + << " Pixel_[0]_band2 = " << it1.GetPixel(1)[1] + << " Pixel_[1]_band2 = " << it1.GetPixel(2)[1] + << " Result = " << result2 + << " Expected = " << expected2 << std::endl +<< "Error = " << error3 << " > 1E-9 -> TEST FAILLED" << std::endl + << "Pixel_[-1]_band3 = " << it1.GetPixel(0)[2] + << " Pixel_[0]_band3 = " << it1.GetPixel(1)[2] + << " Pixel_[1]_band3 = " << it1.GetPixel(2)[2] + << " Result = " << result3 + << " Expected = " << expected3 << std::endl);*/ + } + } + + return EXIT_SUCCESS; +} int otbBandMathImageFilterXWithIdx( int itkNotUsed(argc), char* argv[]) diff --git a/Testing/Code/BasicFilters/otbBasicFiltersTests13.cxx b/Testing/Code/BasicFilters/otbBasicFiltersTests13.cxx index 3784e866ee..2d95f95d03 100644 --- a/Testing/Code/BasicFilters/otbBasicFiltersTests13.cxx +++ b/Testing/Code/BasicFilters/otbBasicFiltersTests13.cxx @@ -25,9 +25,10 @@ void RegisterTests() { REGISTER_TEST(otbBandMathImageFilterNew); - REGISTER_TEST(otbBandMathImageFilterXNew); REGISTER_TEST(otbBandMathImageFilter); + REGISTER_TEST(otbBandMathImageFilterXNew); REGISTER_TEST(otbBandMathImageFilterX); + REGISTER_TEST(otbBandMathImageFilterXConv); REGISTER_TEST(otbBandMathImageFilterWithIdx); REGISTER_TEST(otbBandMathImageFilterXWithIdx); REGISTER_TEST(otbComplexToIntensityFilterTest); -- GitLab