From 7fc2e5dac96eb5b2093e357941f4dcbab234d257 Mon Sep 17 00:00:00 2001
From: Cyrille Valladeau <cyrille.valladeau@c-s.fr>
Date: Mon, 9 Feb 2009 15:12:12 +0100
Subject: [PATCH] ENH : texture formalas correction + add sum entropy

---
 .../otbContrastTextureFunctor.h               |   2 +-
 .../otbDifferenceEntropyTextureFunctor.h      |   5 +-
 .../otbSumAverageTextureFunctor.h             |   5 +-
 .../otbSumEntropyTextureFunctor.h             | 149 ++++++++++++++++++
 Testing/Code/FeatureExtraction/CMakeLists.txt |  32 ++++
 .../FeatureExtraction/otbTextureFunctor.cxx   |   8 +
 .../otbTextureImageFunction.cxx               |   7 +-
 7 files changed, 201 insertions(+), 7 deletions(-)
 create mode 100644 Code/FeatureExtraction/otbSumEntropyTextureFunctor.h

diff --git a/Code/FeatureExtraction/otbContrastTextureFunctor.h b/Code/FeatureExtraction/otbContrastTextureFunctor.h
index 8e508bc525..ad1d97300d 100644
--- a/Code/FeatureExtraction/otbContrastTextureFunctor.h
+++ b/Code/FeatureExtraction/otbContrastTextureFunctor.h
@@ -120,7 +120,7 @@ public:
 	    double rVal = (static_cast<double>(r)+0.5)*binsLength[1];
 	    for (unsigned s = 0; s<histo[r].size(); s++)
 	      { 
-		if( vcl_abs( rVal - (static_cast<double>(s)+0.5)*binsLength[0] - nCeil) < vcl_abs(binsLength[0]-binsLength[1]) )
+		if( vcl_abs((static_cast<double>(s)+0.5)*binsLength[0] - rVal - nCeil) < vcl_abs(binsLength[0]) )
 		  {
 		    double p =  static_cast<double>(histo[r][s])*areaInv;
 		    out += nCeilSquare * p;
diff --git a/Code/FeatureExtraction/otbDifferenceEntropyTextureFunctor.h b/Code/FeatureExtraction/otbDifferenceEntropyTextureFunctor.h
index bf667f36e2..d984f13e17 100644
--- a/Code/FeatureExtraction/otbDifferenceEntropyTextureFunctor.h
+++ b/Code/FeatureExtraction/otbDifferenceEntropyTextureFunctor.h
@@ -115,20 +115,19 @@ public:
       { 
 	double Px_y = 0.;
 	double nCeil = (static_cast<double>(sB)+0.5)*binsLength[0];
-	double nCeilSquare = vcl_pow( nCeil, 2);
 	for (unsigned r = 0; r<histo.size(); r++)
 	  {
 	    double rVal = (static_cast<double>(r)+0.5)*binsLength[1];
 	    for (unsigned s = 0; s<histo[r].size(); s++)
 	      { 
-		if( vcl_abs( rVal - (static_cast<double>(s)+0.5)*binsLength[0] - nCeil ) < vcl_abs( binsLength[0]+binsLength[1]) )
+		if( vcl_abs((static_cast<double>(s)+0.5)*binsLength[0] - rVal - nCeil) < vcl_abs(binsLength[0]) )
 		  {
 		    Px_y += static_cast<double>(histo[r][s])*areaInv;
 		  }
 	      }
 	  }
 	if(Px_y != 0.)
-	  out += Px_y * nCeil * vcl_log(Px_y);
+	  out += Px_y * vcl_log(Px_y);
       }
     
     if(out != 0)
diff --git a/Code/FeatureExtraction/otbSumAverageTextureFunctor.h b/Code/FeatureExtraction/otbSumAverageTextureFunctor.h
index c9028a7b27..3de106d2f7 100644
--- a/Code/FeatureExtraction/otbSumAverageTextureFunctor.h
+++ b/Code/FeatureExtraction/otbSumAverageTextureFunctor.h
@@ -122,10 +122,11 @@ public:
 		double sVal = (static_cast<double>(s)+0.5)*binsLength[0];
 		// In theory don't have the abs but will deals with neighborhood and offset without the same histo
 		// thus loop over 2*Ng don't have sense
-		if( vcl_abs(rVal + sVal - nCeil) < vcl_abs(binsLength[0]+binsLength[1]) || vcl_abs(rVal + sVal - 2*nCeil) < vcl_abs(binsLength[0]+binsLength[1]) )
+		//if( vcl_abs(rVal + sVal - nCeil) < vcl_abs(binsLength[0]+binsLength[1]) || vcl_abs(rVal + sVal - 2*nCeil) < vcl_abs(binsLength[0]+binsLength[1]) )
+		if( vcl_abs(rVal + sVal - nCeil) < vcl_abs(binsLength[0]) || vcl_abs(rVal + sVal - 2*nCeil) < 2*vcl_abs(binsLength[0]) )
 		  {
 		    double p =  static_cast<double>(histo[r][s])*areaInv;
-		    out += sVal * p;
+		    out += nCeil * p;
 		  }
 	      }
 	  }
diff --git a/Code/FeatureExtraction/otbSumEntropyTextureFunctor.h b/Code/FeatureExtraction/otbSumEntropyTextureFunctor.h
new file mode 100644
index 0000000000..dad317125a
--- /dev/null
+++ b/Code/FeatureExtraction/otbSumEntropyTextureFunctor.h
@@ -0,0 +1,149 @@
+/*=========================================================================
+
+  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 __otbSumEntropyTextureFunctor_h
+#define __otbSumEntropyTextureFunctor_h
+
+#include "otbTextureFunctorBase.h"
+
+namespace otb
+{
+namespace Functor
+{
+/** \class SumEntropyTextureFunctor
+ *  \brief This functor calculates the inverse difference moment of an image
+ *
+ *   Computes joint histogram (neighborhood and offset neighborhood) 
+ *   which bins are computing using Scott formula.
+ *   Computes the probabiltiy p for each pair of pixel.
+ *   InverseSumMoment  is the sum 1/(1+(pi-poff)²)*p over the neighborhood.
+ *   TIterInput is an ietrator, TOutput is a PixelType.
+ *
+ *  \ingroup Functor
+ *  \ingroup 
+ *  \ingroup Statistics
+ */
+template <class TIterInput1, class TIterInput2, class TOutput>
+class ITK_EXPORT SumEntropyTextureFunctor : 
+public TextureFunctorBase<TIterInput1, TIterInput2, TOutput>
+{
+public:
+  SumEntropyTextureFunctor(){};
+  ~SumEntropyTextureFunctor(){};
+
+  typedef TIterInput1                           IterType1;
+  typedef TIterInput2                           IterType2;
+  typedef TOutput                               OutputType;
+  typedef typename IterType1::OffsetType        OffsetType;
+  typedef typename IterType1::RadiusType        RadiusType;
+  typedef typename IterType1::InternalPixelType InternalPixelType;
+  typedef typename IterType1::ImageType         ImageType;
+  typedef itk::Neighborhood<InternalPixelType,::itk::GetImageDimension<ImageType>::ImageDimension>    NeighborhoodType;
+  typedef std::vector<double>                   DoubleVectorType;
+  typedef std::vector<int>                      IntVectorType;
+  typedef std::vector<IntVectorType>            IntVectorVectorType;
+
+
+  virtual double ComputeOverSingleChannel(const NeighborhoodType &neigh, const NeighborhoodType &neighOff)
+  {
+    DoubleVectorType binsLength = this->StatComputation(neigh, neighOff);
+
+    RadiusType radius = neigh.GetRadius();
+    double area = static_cast<double>(neigh.GetSize()[0]*neigh.GetSize()[1]);
+    double areaInv = 1/area;
+    OffsetType offset;
+    offset.Fill(0);
+    OffsetType offsetOff;
+    OffsetType offsetOffInit;
+
+    offsetOffInit[0] = -radius[0]+this->GetOffset()[0]-1;
+    offsetOffInit[1] = -radius[1]+this->GetOffset()[1]-1;
+
+    int histoIdX = 0;
+    int histoIdY = 0;
+    double out = 0.;
+
+    IntVectorType histoTemp;
+    IntVectorVectorType histo;
+    if (binsLength[0] != 0)
+      histoTemp = IntVectorType( vcl_floor( static_cast<double>(this->GetMaxi()-this->GetMini())/binsLength[0])+1., 0);
+    else
+      histoTemp = IntVectorType( 1, 0 );
+
+    if (binsLength[1] != 0)
+        histo = IntVectorVectorType( vcl_floor(static_cast<double>(this->GetMaxiOff()-this->GetMiniOff())/binsLength[1])+1., histoTemp );
+    else
+      histo = IntVectorVectorType( 1, histoTemp );
+
+    offsetOff = offsetOffInit;
+    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;
+	      histoIdX = 0;
+	      histoIdY = 0;
+	      if ( binsLength[1] != 0)
+		histoIdX = static_cast<int>(vcl_floor( (static_cast<double>(neighOff[offsetOff])-this->GetMiniOff()) / static_cast<double>(binsLength[1]) ));
+	      if ( binsLength[0] !=0 )
+		histoIdY = static_cast<int>(vcl_floor( (static_cast<double>(neigh[offset])-this->GetMini()) /static_cast<double>( binsLength[0]) ));
+	      
+	      histo[histoIdX][histoIdY]++;
+	      
+	    }
+	}
+    // loop over bin neighborhood values
+    for (unsigned sB = 0; sB<histo[0].size(); sB++)
+      { 
+	double Px_y = 0.;
+	double nCeil = (static_cast<double>(sB)+0.5)*binsLength[0];
+	for (unsigned r = 0; r<histo.size(); r++)
+	  {
+	    double rVal = (static_cast<double>(r)+0.5)*binsLength[1];
+	    for (unsigned s = 0; s<histo[r].size(); s++)
+	      { 
+		double sVal = (static_cast<double>(s)+0.5)*binsLength[0];
+		if( vcl_abs(rVal + sVal - nCeil) < vcl_abs(binsLength[0]) || vcl_abs(rVal + sVal - 2*nCeil) < vcl_abs(binsLength[0]) )
+		  {
+		    Px_y +=  static_cast<double>(histo[r][s])*areaInv;
+		  }
+	      }
+	  }
+	if(Px_y != 0.)
+	  out += Px_y * vcl_log(Px_y);
+      }
+    
+      
+    if(out != 0)
+      out = -out;
+
+  
+    return out;  
+  }
+  
+};
+ 
+ 
+} // namespace Functor
+} // namespace otb
+
+#endif
+
diff --git a/Testing/Code/FeatureExtraction/CMakeLists.txt b/Testing/Code/FeatureExtraction/CMakeLists.txt
index 707964e0a8..0d802c625a 100644
--- a/Testing/Code/FeatureExtraction/CMakeLists.txt
+++ b/Testing/Code/FeatureExtraction/CMakeLists.txt
@@ -1187,6 +1187,21 @@ ADD_TEST(feTvDifferenceEntropyTextureFunctor ${FEATUREEXTRACTION_TESTS12}
     2    # offset[1]	
 )
 
+# -------   otb::SumEntropyTextureFunctor  -------------
+ADD_TEST(feTvSumEntropyTextureFunctor ${FEATUREEXTRACTION_TESTS12} 
+--compare-image ${EPS}
+                ${BASELINE}/feTvSumEntropyTextureFunctor.tif
+                ${TEMP}/feTvSumEntropyTextureFunctor.tif
+  otbTextureFunctor
+    SEN #difference entropy
+    ${INPUTDATA}/poupees_sub.png
+    ${TEMP}/feTvSumEntropyTextureFunctor.tif
+    5    # radius
+    -2   # offset[0]
+    2    # offset[1]	
+)
+
+
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ otbFeatureExtractionTests13 ~~~~~~~~~~~~~~~~~~~~~
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1328,6 +1343,23 @@ ADD_TEST(feTvDifferenceEntropyTextureImageFunction ${FEATUREEXTRACTION_TESTS13}
     2    # offset[1]
  )
 
+
+# -------        otb::SumEntropyTextureImageFunction   -------------
+ADD_TEST(feTvSumEntropyTextureImageFunction ${FEATUREEXTRACTION_TESTS13} 
+--compare-image ${EPS}
+                ${BASELINE}/feTuSumEntropyTextureImageFunction.tif
+                ${TEMP}/feTvSumEntropyTextureImageFunction.tif
+   otbTextureImageFunction
+    SEN #difference entropy
+    ${INPUTDATA}/poupees_sub_c1.png
+    ${TEMP}/feTvSumEntropyTextureImageFunction.tif
+    5    # radius[0]
+    5    # radius[1]
+    -2   # offset[0]
+    2    # offset[1]
+ )
+
+
 # A enrichir
 SET(BasicFeatureExtraction_SRCS1
 otbAlignImageToPath.cxx
diff --git a/Testing/Code/FeatureExtraction/otbTextureFunctor.cxx b/Testing/Code/FeatureExtraction/otbTextureFunctor.cxx
index 2ac85ea177..a2714c59f6 100644
--- a/Testing/Code/FeatureExtraction/otbTextureFunctor.cxx
+++ b/Testing/Code/FeatureExtraction/otbTextureFunctor.cxx
@@ -33,6 +33,9 @@
 #include "otbContrastTextureFunctor.h"
 #include "otbSumAverageTextureFunctor.h"
 #include "otbDifferenceEntropyTextureFunctor.h"
+#include "otbSumEntropyTextureFunctor.h"
+
+
 
 template<class TInputImage, class TOutputImage, class TFunctor>
 int generic_TextureFunctor(int argc, char * argv[])
@@ -125,6 +128,11 @@ int otbTextureFunctor(int argc, char * argv[])
       typedef otb::Functor::DifferenceEntropyTextureFunctor<IteratorType, IteratorType, PixelType> FunctorType;
       return( generic_TextureFunctor<ImageType, ImageType, FunctorType>(argc,argv) );
     }
+  else if ( strArgv == "SEN" )
+    {
+      typedef otb::Functor::SumEntropyTextureFunctor<IteratorType, IteratorType, PixelType> FunctorType;
+      return( generic_TextureFunctor<ImageType, ImageType, FunctorType>(argc,argv) );
+    }
   else
     {
       return EXIT_FAILURE;
diff --git a/Testing/Code/FeatureExtraction/otbTextureImageFunction.cxx b/Testing/Code/FeatureExtraction/otbTextureImageFunction.cxx
index 45bc396d2a..052cdcabde 100644
--- a/Testing/Code/FeatureExtraction/otbTextureImageFunction.cxx
+++ b/Testing/Code/FeatureExtraction/otbTextureImageFunction.cxx
@@ -36,6 +36,7 @@
 #include "otbContrastTextureFunctor.h"
 #include "otbSumAverageTextureFunctor.h"
 #include "otbDifferenceEntropyTextureFunctor.h"
+#include "otbSumEntropyTextureFunctor.h"
 
 
 template<class TInputImage, class TOutputImage, class TFunctor>
@@ -98,7 +99,6 @@ int otbTextureImageFunction(int argc, char * argv[])
 
   if(strArgv == "ENJ")
     {
-      std::cout<<"ENEGRY"<<std::endl;
       typedef otb::Functor::EnergyTextureFunctor<IteratorType, IteratorType, VectorType> FunctorType;
       return( generic_TextureImageFunction<ImageType, ImageType, FunctorType>(argc,argv) );
     }
@@ -142,6 +142,11 @@ int otbTextureImageFunction(int argc, char * argv[])
       typedef otb::Functor::DifferenceEntropyTextureFunctor<IteratorType, IteratorType, VectorType> FunctorType;
       return( generic_TextureImageFunction<ImageType, ImageType, FunctorType>(argc,argv) );
     }
+  else if ( strArgv == "SEN" )
+    {
+      typedef otb::Functor::SumEntropyTextureFunctor<IteratorType, IteratorType, VectorType> FunctorType;
+      return( generic_TextureImageFunction<ImageType, ImageType, FunctorType>(argc,argv) );
+    }
   else
     {
       return EXIT_FAILURE;
-- 
GitLab