From cf3c68b81cd3bea766197e66faee834e623e0c7e Mon Sep 17 00:00:00 2001
From: Antoine Regimbeau <antoine.regimbeau@c-s.fr>
Date: Thu, 28 Sep 2017 17:14:50 +0200
Subject: [PATCH] ENH: add persistent filter for heavy computation

---
 .../app/otbContrastEnhancement.cxx            | 221 ++++++++++++++++--
 1 file changed, 198 insertions(+), 23 deletions(-)

diff --git a/Modules/Applications/AppFiltering/app/otbContrastEnhancement.cxx b/Modules/Applications/AppFiltering/app/otbContrastEnhancement.cxx
index 82ddaffa10..79df4cf4b9 100644
--- a/Modules/Applications/AppFiltering/app/otbContrastEnhancement.cxx
+++ b/Modules/Applications/AppFiltering/app/otbContrastEnhancement.cxx
@@ -33,8 +33,9 @@
 #include "otbComputeGainLutFilter.h"
 #include "otbApplyGainFilter.h"
 #include "otbImageFileWriter.h"
+#include "itkImageRegionIterator.h"
 
-
+#include "otbStreamingHistogramVectorImageFilter.h"
 
 namespace otb
 {
@@ -119,6 +120,8 @@ public:
                                       FloatVectorImageType > 
           StreamingImageFilterType;
   typedef otb::BufferFilter < FloatImageType > BufferFilterType;
+  typedef otb::StreamingHistogramVectorImageFilter < FloatVectorImageType > 
+      HistoPersistentFilterType;
 
   /** Standard macro */
   itkNewMacro( Self );
@@ -165,6 +168,9 @@ private:
       "image that has no visualization it is ignored by the algorithm.");
     MandatoryOff("nodata");
 
+    AddParameter(ParameterType_Empty , "global" , "Global equalization" );
+    SetParameterDescription("global","");
+
     AddParameter(ParameterType_Group, "thumb", "Thumbnail size");
     SetParameterDescription("thumb","The algorithm can be local : "
       "in each of those thumbnails a histogram will be computed "
@@ -300,7 +306,6 @@ private:
       PerBandEqualization( inImage , inputImageList , 
                            nbChannel , outputImageList );
       }
-
     else if ( mode == "lum")
       {
       std::vector<int> rgb( 3 , 0 );
@@ -389,32 +394,45 @@ private:
                       const GainLutFilterType::Pointer lutFilter ,
                       const StreamingImageFilterType::Pointer streamingFilter ,
                       const FloatImageType::Pointer input ,
+                      // unsigned int channel ,
+                      FloatVectorImageType::Pointer histogram ,
                       float max ,
                       float min)
   {
-    if ( HasValue("hfact") )
-      {
-      histoFilter->SetThreshold( GetParameterInt("hfact") );
-      }
-    if ( IsParameterEnabled("nodata") )
-      {
-      histoFilter->NoDataFlagOn();
-      histoFilter->SetNoData( GetParameterFloat("nodata") );
-      }
-    else
+    if ( !IsParameterEnabled("global") ) //!HasValue("global") )
       {
-      histoFilter->NoDataFlagOff();
+      if ( HasValue("hfact") )
+        {
+        histoFilter->SetThreshold( GetParameterInt("hfact") );
+        }
+      if ( IsParameterEnabled("nodata") )
+        {
+        histoFilter->NoDataFlagOn();
+        histoFilter->SetNoData( GetParameterFloat("nodata") );
+        }
+      else
+        {
+        histoFilter->NoDataFlagOff();
+        }
+      histoFilter->SetMin( min );
+      histoFilter->SetMax( max );
+      histoFilter->SetNbBin( GetParameterInt("bin") );
+      histoFilter->SetThumbSize( m_ThumbSize );
+      histoFilter->SetInput( input );
+      histoFilter->Update();
+      if ( !TemporaryTest( histoFilter->GetHistoOutput() , histogram ) )
+        std::cout<<"not equal"<<std::endl;
+      else
+        std::cout<<"Alles gut"<<std::endl;
+      histogram = histoFilter->GetHistoOutput();
       }
-    histoFilter->SetMin( min );
-    histoFilter->SetMax( max );
     lutFilter->SetMin( min );
     lutFilter->SetMax( max );
     lutFilter->SetNbPixel( 
-      GetParameterInt("thumb.h") * GetParameterInt("thumb.w") );
-    histoFilter->SetNbBin(GetParameterInt("bin"));
-    histoFilter->SetThumbSize( m_ThumbSize );
-    histoFilter->SetInput( input );
-    lutFilter->SetInput( histoFilter->GetHistoOutput() );
+      m_ThumbSize[0] * m_ThumbSize[1] );
+
+    // lutFilter->SetInput( m_Histogram[channel] );
+    lutFilter->SetInput( histogram );
     streamingFilter->SetInput( lutFilter->GetOutput() );
   }
 
@@ -498,18 +516,22 @@ private:
     ComputeVectorMinMax( inImage , max , min );
 
     m_GainLutFilter.resize(nbChannel);
-    m_HistoFilter.resize(nbChannel);
     m_GainFilter.resize(nbChannel);
     m_BufferFilter.resize(nbChannel);
     m_StreamingFilter.resize(nbChannel);
+    m_Histogram.resize(nbChannel);
+    m_HistoFilter.resize(nbChannel);
+
+    if ( true )
+      PersistentComputation( inImage , nbChannel , max , min );
 
     for ( unsigned int channel = 0 ; channel < nbChannel ; channel++ ) 
       {
       m_GainLutFilter[channel] = GainLutFilterType::New();
-      m_HistoFilter[channel] = HistoFilterType::New();
       m_GainFilter[channel] = GainFilterType::New();
       m_StreamingFilter[channel] = StreamingImageFilterType::New();
       m_BufferFilter[channel] = BufferFilterType::New();
+      m_HistoFilter[channel] = HistoFilterType::New();
 
       if ( min[channel] == max[channel] )
         {
@@ -527,8 +549,9 @@ private:
                       m_GainLutFilter[channel] ,
                       m_StreamingFilter[channel] ,
                       inputImageList->GetNthElement(channel) ,
+                      // channel ,
+                      m_Histogram[channel],
                       max[channel] , min[channel] );
-
       if( IsParameterEnabled("nodata") )
         {
         m_GainFilter[channel]->NoDataFlagOn();
@@ -592,6 +615,8 @@ private:
                     m_GainLutFilter[0] ,
                     m_StreamingFilter[0] ,
                     m_LuminanceFunctor->GetOutput() ,
+                    // 0 ,
+                    m_Histogram[0] ,
                     max , min);
 
     for ( int channel = 0 ; channel < 3 ; channel++ ) 
@@ -619,12 +644,161 @@ private:
       }
   }
 
+  void PersistentComputation( const FloatVectorImageType::Pointer inImage ,
+                              const unsigned int nbChannel ,
+                              const FloatVectorImageType::PixelType & max ,
+                              const FloatVectorImageType::PixelType & min)
+  { 
+
+    HistoPersistentFilterType::Pointer histoPersistent (
+        HistoPersistentFilterType::New());
+    unsigned int nbBin ( GetParameterInt( "bin" ) );
+    histoPersistent->SetInput( inImage );
+    FloatVectorImageType::PixelType pixel ( nbChannel ) , step( nbChannel );
+    pixel.Fill( nbBin );
+    histoPersistent->GetFilter()->SetNumberOfBins( pixel );
+    if ( IsParameterEnabled("nodata") )
+      {
+      histoPersistent->GetFilter()->NoDataFlagOn();
+      histoPersistent->GetFilter()->SetNoDataValue( 
+                GetParameterFloat( "nodata" ) );
+      }
+    step = ( max - min ) / nbBin;
+    pixel = min - 0.5 * step;
+    histoPersistent->GetFilter()->SetHistogramMin(pixel);
+    pixel = max + 0.5 * step;
+    histoPersistent->GetFilter()->SetHistogramMax(pixel);
+    histoPersistent->Update();
+    HistoPersistentFilterType::HistogramListType * histotest = 
+            histoPersistent->GetHistogramList();
+    // std::cout<<"test "<< histotest->GetNthElement(0)<<std::endl;
+    // std::cout<<"test "<< histotest->GetNthElement(0)->GetSize()<<std::endl;
+    Transfert( histotest );
+    // HistoPersistentFilterType::HistogramType::IndexType index(1);
+    // for ( int i = 0 ; i < 256 ; i++)
+    //   {
+    //   index[0] = i;
+    //   std::cout<<histotest->GetNthElement(0)->GetFrequency(index)<<std::endl;
+    //   std::cout<<histotest->GetNthElement(0)->GetMeasurementVector(index)<<std::endl;
+    //   std::cout<<histotest->GetNthElement(0)->GetHistogramMinFromIndex(index)<<std::endl;
+    //   std::cout<<histotest->GetNthElement(0)->GetHistogramMaxFromIndex(index)<<std::endl;
+    //   }
+    if ( HasValue("hfact") )
+    {
+    for ( auto j = 0 ; j < m_Histogram.size() ; j++ )
+      {
+      unsigned int rest(0);
+      unsigned int height ( static_cast<unsigned int>( 
+          GetParameterFloat( "hfact" ) * 
+          ( histotest->GetNthElement(j)->GetTotalFrequency() / nbBin ) ) );
+      // Do i need to static_cast in a an assignation?
+      // Warning!!!! Need to handle out of bound int!!!
+      FloatVectorImageType::IndexType zero;
+      FloatVectorImageType::Pointer & histoToThresh = m_Histogram[j];
+      zero.Fill(0);
+      for( unsigned int i = 0 ; i < nbBin ; i++ )
+        {
+        if ( histoToThresh->GetPixel(zero)[i] > height )
+          {
+          rest += histoToThresh->GetPixel(zero)[i] - height ;
+          histoToThresh->GetPixel(zero)[i] = height ;
+          }
+        }
+      height = rest / nbBin;
+      rest = rest % nbBin;
+      for( unsigned int i = 0 ; i < nbBin ; i++ )
+        {
+        histoToThresh->GetPixel(zero)[i] += height ;
+        if ( i > (nbBin - rest)/2 && i <= (nbBin - rest)/2 + rest )
+          {
+          ++histoToThresh->GetPixel(zero)[i];
+          }
+        }
+      }
+    }
+  }
+
+  void Transfert( HistoPersistentFilterType::HistogramListType * histoList )
+  {
+    int nbBin( GetParameterInt( "bin" ) );
+    m_Histogram.resize(0);
+
+    FloatVectorImageType::SizeType sizeOne;
+    sizeOne.Fill( 1 );
+
+    FloatVectorImageType::PixelType histoPixel( nbBin );
+
+    FloatVectorImageType::IndexType index;
+    index.Fill(0);
+    HistoPersistentFilterType::HistogramType::Pointer histo;
+    FloatImageType::SpacingType inputSpacing ( GetParameterImage("in")->GetSpacing() );
+    FloatImageType::PointType inputOrigin ( GetParameterImage("in")->GetOrigin() );
+
+    FloatVectorImageType::SpacingType histoSpacing ;
+    histoSpacing[0] = inputSpacing[0] * m_ThumbSize[0] ;
+    histoSpacing[1] = inputSpacing[1] * m_ThumbSize[1] ;
+    FloatVectorImageType::PointType histoOrigin ;
+    histoOrigin[0] = histoSpacing[0] / 2 +  inputOrigin[0] - inputSpacing[0] / 2 ;
+    histoOrigin[1] = histoSpacing[1] / 2 +  inputOrigin[1] - inputSpacing[1] / 2 ;
+
+    for ( unsigned int i = 0 ; i < histoList->Size() ; i++ )
+      {
+      FloatVectorImageType::Pointer histoVectorImage ( 
+            FloatVectorImageType::New() );
+      histoVectorImage->SetVectorLength( nbBin );
+      histoVectorImage->SetBufferedRegion( sizeOne );
+      histoVectorImage->SetRequestedRegion( sizeOne );
+      histoVectorImage->SetLargestPossibleRegion( sizeOne );
+      histoVectorImage->SetSpacing( histoSpacing ) ;
+      histoVectorImage->SetOrigin( histoOrigin );
+      histoVectorImage->Allocate();
+      histo  = histoList->GetNthElement( i );
+      for (int j = 0 ; j < nbBin ; j++ )
+        {
+        histoPixel[j] = histo->GetFrequency( j );
+        }
+      histoVectorImage->SetPixel( index , histoPixel );
+      m_Histogram.push_back( histoVectorImage );
+      }
+  }
+
+  bool TemporaryTest( FloatVectorImageType::Pointer output ,
+                      FloatVectorImageType::Pointer histogram )
+  {
+    bool result ( true );
+    auto sizeh ( histogram->GetVectorLength() );
+    auto sizeo ( output->GetVectorLength() );
+    if ( sizeo != sizeh )
+      result = false;
+    itk::ImageRegionIterator < FloatVectorImageType > 
+        hit( histogram , histogram->GetLargestPossibleRegion() );
+    itk::ImageRegionIterator < FloatVectorImageType > 
+        oit( output , output->GetLargestPossibleRegion() );
+    for ( hit.GoToBegin() , oit.GoToBegin() ; !hit.IsAtEnd() || !oit.IsAtEnd() ;
+          ++oit , ++hit )
+      {
+        for ( auto i = 0 ; i < sizeh && i < sizeo ; i++ )
+          {
+          if ( oit.Get()[i] != hit.Get()[i] )
+            {
+            std::cout<<"bin n_ "<<i<<std::endl;
+            std::cout<<"histoFilter says : "<<oit.Get()[i]<<std::endl;
+            std::cout<<"persistentFilter says : "<<hit.Get()[i]<<std::endl;
+            result = false;
+            }
+          }
+      }
+    return result;
+  }
+
+
   FloatImageType::SizeType m_ThumbSize;
   ImageListToVectorFilterType::Pointer m_ImageListToVectorFilterOut;
   LuminanceFunctorType::Pointer m_LuminanceFunctor;
   VectorToImageListFilterType::Pointer m_VectorToImageListFilter;
   std::vector < GainLutFilterType::Pointer > m_GainLutFilter;
   std::vector < HistoFilterType::Pointer > m_HistoFilter;
+  std::vector < FloatVectorImageType::Pointer > m_Histogram;
   std::vector < GainFilterType::Pointer > m_GainFilter;
   std::vector < StreamingImageFilterType::Pointer > m_StreamingFilter;
   std::vector < BufferFilterType::Pointer > m_BufferFilter;
@@ -632,6 +806,7 @@ private:
 };
 
 
+
 } //End namespace Wrapper
 } //End namespace otb
 
-- 
GitLab