From 5d3bfa864b1250cea2e179c1775ce3413a810344 Mon Sep 17 00:00:00 2001
From: Jonathan Guinet <jonathan.guinet@c-s.fr>
Date: Thu, 7 Apr 2011 10:01:15 +0200
Subject: [PATCH] ENH MuPaser based Functor for binary mask generation and
 connected component segmentation application

---
 .../otbConnectedComponentMuParserFunctor.h    | 194 ++++++++++++++++++
 Code/BasicFilters/otbMaskMuParserFilter.h     | 142 +++++++++++++
 Code/BasicFilters/otbMaskMuParserFilter.txx   | 169 +++++++++++++++
 Code/BasicFilters/otbMaskMuParserFunctor.h    | 185 +++++++++++++++++
 4 files changed, 690 insertions(+)
 create mode 100644 Code/BasicFilters/otbConnectedComponentMuParserFunctor.h
 create mode 100644 Code/BasicFilters/otbMaskMuParserFilter.h
 create mode 100644 Code/BasicFilters/otbMaskMuParserFilter.txx
 create mode 100644 Code/BasicFilters/otbMaskMuParserFunctor.h

diff --git a/Code/BasicFilters/otbConnectedComponentMuParserFunctor.h b/Code/BasicFilters/otbConnectedComponentMuParserFunctor.h
new file mode 100644
index 0000000000..98080cf6fa
--- /dev/null
+++ b/Code/BasicFilters/otbConnectedComponentMuParserFunctor.h
@@ -0,0 +1,194 @@
+/*=========================================================================
+
+ 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 __otbConnectedComponentMuParserFunctor_h
+#define __otbConnectedComponentMuParserFunctor_h
+
+#include "otbParser.h"
+#include "otbMacro.h"
+#include "itkMacro.h"
+
+
+#include <vnl/algo/vnl_lsqr.h>
+#include <vnl/vnl_sparse_matrix_linear_system.h>
+#include <vnl/vnl_least_squares_function.h>
+
+
+namespace otb
+{
+/** \class ConnectedComponentMuParserFunctor
+ * \brief functor used as input to itk connected component segmentation module.
+ *
+ * This functor is based on the mathematical parser library muParser.
+ * The built in functions and operators list is available at:
+ * http://muparser.sourceforge.net/mup_features.html#idDef2
+ *
+ * image pixels :
+ * p1bX, p2bX, where X denote band index.
+ *
+ * Specific Functor additional input :
+ * distance : euclidian distance
+ * spectralAngle : NOT IMPLEMENTED
+ *
+ * OTB additional functions:
+ * ndvi(r, niri)
+ *
+ * OTB additional constants:
+ * e - log2e - log10e - ln2 - ln10 - pi - euler
+ *
+ *
+ * \sa Parser
+ *
+ */
+
+/** \class ConnectedComponentMuParserFunctor
+ *  \brief This functor use MuParser as criteria for itk connected component module
+ */
+  namespace Functor
+  {
+
+    template<class TInput>
+    class ITK_EXPORT ConnectedComponentMuParserFunctor
+    {
+   
+    public:
+      typedef Parser ParserType;
+      typedef ConnectedComponentMuParserFunctor Self;
+
+      std::string GetNameOfClass()
+      {
+        return "ConnectedComponentMuParserFunctor";
+      }
+
+      inline bool operator()(const TInput &p1, const TInput &p2)
+      {
+
+
+        double value;
+
+        if(p1.GetSize()!=m_NbOfBands)
+          {
+          this->SetNumberOfBands(p1.GetSize());
+          }
+
+        // we fill the buffer
+        for(unsigned int i=0; i<m_NbOfBands; i++)
+          {
+          m_AImageP1[i]= static_cast<double> (p1[i]);
+          m_AImageP2[i]= static_cast<double> (p2[i]);
+          }
+
+        m_Distance = 0.0;
+        for(unsigned int i = 0; i<m_NbOfBands;++i)
+          {
+          m_Distance +=(p1[i]-p2[i])*(p1[i]-p2[i]);
+          }
+        m_Distance  = vcl_sqrt(m_Distance);
+
+        // cast
+        try
+        {
+          value = m_Parser->Eval();
+        }
+        catch(itk::ExceptionObject& err)
+        {
+          itkExceptionMacro(<< err);
+        }
+
+        return static_cast<bool> (value);
+      }
+
+
+      void SetExpression(const std::string expression)
+      {
+        m_Expression=expression;
+        m_Parser->SetExpr(m_Expression);
+      }
+
+      /** Return the expression to be parsed */
+      std::string GetExpression() const
+      {
+        return m_Expression;
+      }
+
+      void SetNumberOfBands(unsigned int NbOfBands)
+      {
+
+        m_NbOfBands=NbOfBands;
+        std::ostringstream varName;
+
+
+        m_AImageP1.resize(NbOfBands,0.0);
+        m_AImageP2.resize(NbOfBands,0.0);
+
+        for(unsigned int i=0;i<NbOfBands;i++)
+          {
+          varName << "p1b" << i+1 ;
+          m_Parser->DefineVar(varName.str(), &(m_AImageP1[i]));
+          varName.str("");
+          varName << "p2b" << i+1 ;
+          m_Parser->DefineVar(varName.str(), &(m_AImageP2[i]));
+          varName.str("");
+          }
+        // customized data
+        //m_NbVar++;
+        //this->SetDataSize(m_NbVar);
+        m_Parser->DefineVar("distance", &m_Distance);
+        m_Parser->DefineVar("spectralAngle", &m_SpectralAngle);
+        //this->SetVarName(m_NbVar-1,"spectralDistance");
+
+      }
+
+      ConnectedComponentMuParserFunctor()
+      {
+        m_Parser = ParserType::New();
+        m_NbOfBands =0;
+      };
+
+      ~ConnectedComponentMuParserFunctor()
+      {};
+
+    protected:
+
+
+    private:
+
+      ConnectedComponentMuParserFunctor(const Self &);//purposely not implemented
+      void operator =(const Self &);    //purposely not implemented
+
+      std::string m_Expression;
+      ParserType::Pointer m_Parser;
+      std::vector<double> m_AImageP1;
+      std::vector<double> m_AImageP2;
+      double m_Distance;
+      double m_SpectralAngle;
+      std::vector<std::string > m_VarName;
+      unsigned int m_NbOfBands;
+      double m_ParserResult;
+
+    };
+  } // end of Functor namespace
+
+
+}//end namespace otb
+
+
+#endif
diff --git a/Code/BasicFilters/otbMaskMuParserFilter.h b/Code/BasicFilters/otbMaskMuParserFilter.h
new file mode 100644
index 0000000000..26d5044362
--- /dev/null
+++ b/Code/BasicFilters/otbMaskMuParserFilter.h
@@ -0,0 +1,142 @@
+/*=========================================================================
+
+  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 __otbMaskMuParserFilter_h
+#define __otbMaskMuParserFilter_h
+
+
+#include "itkProgressReporter.h"
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "itkArray.h"
+
+#include "otbParser.h"
+#include "otbMacro.h"
+#include "itkMacro.h"
+#include "otbMaskMuParserFunctor.h"
+
+#include "itkImageToImageFilter.h"
+#include "itkImageRegionIteratorWithIndex.h"
+
+namespace otb
+{
+/** \class MaskMuParserImageFilter
+ * \brief Performs a mathematical operation on the input images
+ * according to the formula specified by the user. values different from 0 are set to 1
+ *
+ * This filter is based on the mathematical parser library muParser.
+ * The built in functions and operators list is available at:
+ * http://muparser.sourceforge.net/mup_features.html#idDef2
+ *
+ * OTB additional functions:
+ * ndvi(r, niri)
+ *
+ * OTB additional constants:
+ * e - log2e - log10e - ln2 - ln10 - pi - euler
+ *
+ * an input vector image and a Mu Parser compliant fomula is needed
+ * each band of vector image is  name im1bX, where X is the band index
+ * for example im1b2 correspond to the second band of the input image.
+ * Next step is to set the expression according to the variable
+ * names. For example, in the default case with three input images the
+ * following expression is valid :
+ * "im1b1<140"
+ *
+ *
+ * \sa Parser
+ *
+ * \ingroup Streamed
+ * \ingroup Threaded
+ */
+
+
+
+template< class TInputImage,class TOutputImage,class TFunction=Functor::MaskMuParserFunctor<
+	    typename TInputImage::PixelType > >
+class ITK_EXPORT MaskMuParserFilter : public itk::ImageToImageFilter<TInputImage, TOutputImage>
+{
+public:
+  /** Standard class typedefs. */
+  typedef MaskMuParserFilter                Self;
+  typedef itk::ImageToImageFilter< TInputImage, TOutputImage>             Superclass;
+  typedef itk::SmartPointer< Self >                     Pointer;
+  typedef itk::SmartPointer< const Self >               ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(MaskMuParserFilter, itk::ImageToImageFilter);
+
+  /** Some convenient typedefs. */
+  typedef TInputImage                             InputImageType;
+  typedef typename    InputImageType::RegionType  InputImageRegionType;
+  typedef typename    InputImageType::PixelType           PixelType;
+  typedef typename    InputImageType::Pointer     InputImagePointer;
+  typedef typename    InputImageType::ConstPointer     InputImageConstPointer;
+  typedef TOutputImage                            OutputImageType;
+  typedef typename    OutputImageType::RegionType OutputImageRegionType;
+
+  typedef typename    OutputImageType::Pointer    OutputImagePointer;
+
+  typedef TFunction						                    FunctorType;
+  typedef typename    FunctorType::Pointer        FunctorPointer;
+
+  typedef MaskMuParserFilter<InputImageType,OutputImageType,FunctorType>  MaskMuParserFilterType;
+
+
+  /** Set the expression to be parsed */
+  void SetExpression(const std::string expression);
+
+  /** Return the expression to be parsed */
+  std::string GetExpression() const;
+
+protected :
+  MaskMuParserFilter();
+  virtual ~MaskMuParserFilter();
+  virtual void PrintSelf(std::ostream& os, itk::Indent indent) const;
+
+   void BeforeThreadedGenerateData();
+   void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread,int threadId);
+   void AfterThreadedGenerateData();
+
+
+private :
+  MaskMuParserFilter(const Self&); //purposely not implemented
+  void operator=(const Self&); //purposely not implemented
+
+  std::vector<FunctorPointer>           m_VFunctor;
+  std::string                           m_Expression;
+  long                                  m_UnderflowCount;
+  long                                  m_OverflowCount;
+  itk::Array<long>                      m_ThreadUnderflow;
+  itk::Array<long>                      m_ThreadOverflow;
+};
+
+}//end namespace otb
+
+#ifndef OTB_MANUAL_INSTANTIATION
+#include "otbMaskMuParserFilter.txx"
+#endif
+
+#endif
diff --git a/Code/BasicFilters/otbMaskMuParserFilter.txx b/Code/BasicFilters/otbMaskMuParserFilter.txx
new file mode 100644
index 0000000000..1d4d01d72c
--- /dev/null
+++ b/Code/BasicFilters/otbMaskMuParserFilter.txx
@@ -0,0 +1,169 @@
+/*=========================================================================
+
+  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 __otbMaskMuParserFilter_txx
+#define __otbMaskMuParserFilter_txx
+
+#include "otbMaskMuParserFilter.h"
+#include <iostream>
+#include <string>
+
+#include "itkImageRegionIterator.h"
+#include "itkImageRegionConstIterator.h"
+#include "itkNumericTraits.h"
+#include "itkProgressReporter.h"
+
+namespace otb
+{
+
+// constructor
+template 	< class TInputImage,class TOutputImage,class TFunction>
+MaskMuParserFilter<TInputImage,TOutputImage,TFunction>::MaskMuParserFilter()
+{
+  m_UnderflowCount = 0;
+  m_OverflowCount = 0;
+  m_ThreadUnderflow.SetSize(1);
+  m_ThreadOverflow.SetSize(1);
+}
+
+// Destructor
+template 	< class TInputImage,class TOutputImage,class TFunction>
+MaskMuParserFilter<TInputImage,TOutputImage,TFunction>::~MaskMuParserFilter()
+{
+
+}
+
+template 	< class TInputImage,class TOutputImage,class TFunction>
+void MaskMuParserFilter<TInputImage,TOutputImage,TFunction>::PrintSelf(std::ostream& os, itk::Indent indent) const
+{
+  Superclass::PrintSelf(os, indent);
+
+  os << indent << "Expression: "      << m_Expression                  << std::endl;
+}
+
+
+
+template< class TInputImage,class TOutputImage,class TFunction>
+void MaskMuParserFilter<TInputImage,TOutputImage,TFunction>
+::SetExpression(const std::string expression)
+ {
+  if (m_Expression != expression)
+    m_Expression = expression;
+  this->Modified();
+ }
+
+template< class TInputImage,class TOutputImage,class TFunction>
+std::string MaskMuParserFilter<TInputImage,TOutputImage,TFunction>
+::GetExpression() const
+ {
+  return m_Expression;
+ }
+
+
+/**
+ * BeforeThreadedGenerateData
+ */
+template 	< class TInputImage,class TOutputImage,class TFunction>
+void MaskMuParserFilter<TInputImage,TOutputImage,TFunction>
+::BeforeThreadedGenerateData()
+ {
+
+  typename std::vector<FunctorPointer>::iterator        itFunctor;
+  unsigned int nbThreads = this->GetNumberOfThreads();
+  unsigned int nbInputImages = this->GetNumberOfInputs();
+  unsigned int nbOfBands =this->GetInput()->GetNumberOfComponentsPerPixel();
+  unsigned int thread_index;
+  std::ostringstream varName;
+
+  // Allocate and initialize the thread temporaries
+  m_ThreadUnderflow.SetSize(nbThreads);
+  m_ThreadUnderflow.Fill(0);
+  m_ThreadOverflow.SetSize(nbThreads);
+  m_ThreadOverflow.Fill(0);
+  m_VFunctor.resize(nbThreads);
+
+
+  for(itFunctor = m_VFunctor.begin(); itFunctor < m_VFunctor.end(); itFunctor++)
+    {
+    *itFunctor = FunctorType::New();
+    }
+
+  for(thread_index = 0; thread_index < nbThreads; thread_index++)
+    {
+
+    m_VFunctor.at(thread_index)->SetExpression(m_Expression);
+    m_VFunctor.at(thread_index)->SetNumberOfBands(nbOfBands);
+    // we associate image band with its name im1b1 for band 1
+    for(unsigned int i=0;i<nbOfBands;i++)
+      {
+      varName << "b" << i+1; // +1 var[0]=im1b1
+      m_VFunctor.at(thread_index)->SetVarName(i,varName.str());
+      varName.str("");
+      }
+
+    if(!m_VFunctor.at(thread_index)->CheckExpression())
+      {
+      std::cerr<<"parser can't evaluate formula "<<this->GetExpression()<<"in thread "<<thread_index<<std::endl;
+      }
+    }
+
+ }
+
+template 	< class TInputImage,class TOutputImage,class TFunction>
+void MaskMuParserFilter<TInputImage,TOutputImage,TFunction>
+::ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread,int threadId)
+ {
+
+
+  InputImageConstPointer  inputPtr = this->GetInput();
+  OutputImagePointer outputPtr = this->GetOutput(0);
+
+  // Define the portion of the input to walk for this thread, using
+  // the CallCopyOutputRegionToInputRegion method allows for the input
+  // and output images to be different dimensions
+  InputImageRegionType inputRegionForThread;
+  this->CallCopyOutputRegionToInputRegion(inputRegionForThread, outputRegionForThread);
+
+  // Define the iterators
+  itk::ImageRegionConstIterator<TInputImage>  inputIt(inputPtr, inputRegionForThread);
+  itk::ImageRegionIterator<TOutputImage> outputIt(outputPtr, outputRegionForThread);
+
+  itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels());
+
+  inputIt.GoToBegin();
+  outputIt.GoToBegin();
+
+  FunctorPointer functorP = m_VFunctor.at(threadId);
+  FunctorType&   functor = *functorP;
+  while( !inputIt.IsAtEnd() )
+    {
+    outputIt.Set( functor( inputIt.Get() ) );
+    ++inputIt;
+    ++outputIt;
+    progress.CompletedPixel();  // potential exception thrown here
+    }
+ }
+
+template 	< class TInputImage,class TOutputImage,class TFunction>
+void MaskMuParserFilter<TInputImage,TOutputImage,TFunction>
+::AfterThreadedGenerateData()
+ {
+ }
+
+} // end namespace otb
+
+#endif
diff --git a/Code/BasicFilters/otbMaskMuParserFunctor.h b/Code/BasicFilters/otbMaskMuParserFunctor.h
new file mode 100644
index 0000000000..63632da2d1
--- /dev/null
+++ b/Code/BasicFilters/otbMaskMuParserFunctor.h
@@ -0,0 +1,185 @@
+/*=========================================================================
+
+ 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 __otbMaskMuParserFunctor_h
+#define __otbMaskMuParserFunctor_h
+
+#include "otbParser.h"
+#include "otbMacro.h"
+#include "itkMacro.h"
+
+
+#include "itkLightObject.h"
+#include "itkObjectFactory.h"
+
+
+namespace otb
+{
+/** \class MaskMuParserFunctor
+ * \brief functor used to create binary mask for input of connected component segmentation module.
+ *
+ * This functor is based on the mathematical parser library muParser.
+ * The built in functions and operators list is available at:
+ * http://muparser.sourceforge.net/mup_features.html#idDef2
+ *
+ * OTB additional functions:
+ * ndvi(r, niri)
+ *
+ * OTB additional constants:
+ * e - log2e - log10e - ln2 - ln10 - pi - euler
+ *
+ * \sa Parser
+ *
+ */
+
+/** \class MaskMuParserFunctor
+ *  \brief This functor use MuParser to evaluate and process mathematical expression
+ */
+namespace Functor
+{
+
+template<class TInput>
+class ITK_EXPORT MaskMuParserFunctor : public itk::LightObject
+{
+public:
+typedef Parser ParserType;
+typedef MaskMuParserFunctor Self;
+typedef itk::LightObject                         Superclass;
+typedef itk::SmartPointer<Self>                  Pointer;
+typedef itk::SmartPointer<const Self>            ConstPointer;
+/** Method for creation through the object factory. */
+itkNewMacro(Self);
+
+/** Run-time type information (and related methods). */
+itkTypeMacro(MaskMuParserFunctor,itk::LightObject);
+
+inline bool operator()(const TInput &p)
+{
+
+  double value;
+
+  if(p.Size() !=m_NbVar)
+    {
+    itkExceptionMacro(<< "wrong number of bands" << std::endl);
+    }
+
+  // we fill the buffer
+  for(unsigned int i=0; i<m_NbVar; i++)
+    {
+
+    m_AImage[i]= static_cast<double> (p[i]);
+    }
+
+  // cast
+  try
+  {
+    value = m_Parser->Eval();
+  }
+  catch(itk::ExceptionObject& err)
+  {
+    itkExceptionMacro(<< err);
+  }
+  return static_cast<bool> (value);
+
+}
+
+void SetExpression(const std::string expression)
+{
+  m_Expression=expression;
+  m_Parser->SetExpr(m_Expression);
+}
+
+/** Return the expression to be parsed */
+std::string GetExpression() const
+{
+  return m_Expression;
+}
+
+void SetVarName(unsigned int idx, const std::string varName)
+{
+  m_VarName[idx] = varName;
+  m_Parser->DefineVar(m_VarName[idx], &(m_AImage[idx]));
+}
+
+std::string GetVarName(unsigned int idx)
+{
+  return m_VarName[idx];
+}
+
+void SetNumberOfBands(unsigned int NumberOfBands)
+{
+  m_NbVar=NumberOfBands;
+  m_VarName.resize(NumberOfBands,"");
+  m_AImage.resize(NumberOfBands,0.0);
+}
+
+/** Check the expression */
+bool CheckExpression()
+{
+
+  for(unsigned int i=0; i<m_NbVar; i++)
+    {
+    m_AImage[i]=0;
+    }
+
+  try
+  {
+    m_Parser->Eval();
+
+  }
+  catch(itk::ExceptionObject& err)
+  {
+    return false;
+  }
+
+  return true;
+}
+
+protected:
+MaskMuParserFunctor()
+{
+m_Parser = ParserType::New();
+};
+
+~MaskMuParserFunctor()
+{};
+
+
+private:
+
+MaskMuParserFunctor(const Self &);//purposely not implemented
+void operator =(const Self &);    //purposely not implemented
+
+std::string m_Expression;
+ParserType::Pointer m_Parser;
+std::vector<double> m_AImage;
+std::vector<std::string > m_VarName;
+unsigned int m_NbVar;
+double m_ParserResult;
+
+};
+} // end of Functor namespace
+
+
+}//end namespace otb
+
+
+#endif
-- 
GitLab