From 580f3bc6c66d0e7a2e2984da8043a789d433ab35 Mon Sep 17 00:00:00 2001
From: Guillaume Pasero <guillaume.pasero@c-s.fr>
Date: Wed, 11 Jan 2017 19:28:51 +0100
Subject: [PATCH] ENH: implement sub-sampled texture haralick computation

---
 .../include/otbScalarImageToTexturesFilter.h  |  8 +--
 .../otbScalarImageToTexturesFilter.txx        | 50 ++++++++++++++++++-
 2 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/Modules/Feature/Textures/include/otbScalarImageToTexturesFilter.h b/Modules/Feature/Textures/include/otbScalarImageToTexturesFilter.h
index 2a12f863a9..a8387cd74d 100644
--- a/Modules/Feature/Textures/include/otbScalarImageToTexturesFilter.h
+++ b/Modules/Feature/Textures/include/otbScalarImageToTexturesFilter.h
@@ -173,10 +173,10 @@ public:
   itkGetMacro(SubsampleFactor, SizeType);
 
   /** Set the sub-sampling offset */
-  itkSetMacro(SubsampleOffset, IndexType);
+  itkSetMacro(SubsampleOffset, OffsetType);
 
   /** Get the sub-sampling offset */
-  itkGetMacro(SubsampleOffset, IndexType);
+  itkGetMacro(SubsampleOffset, OffsetType);
 
   /** Get the energy output image */
   OutputImageType * GetEnergyOutput();
@@ -207,6 +207,8 @@ protected:
   ScalarImageToTexturesFilter();
   /** Destructor */
   ~ScalarImageToTexturesFilter() ITK_OVERRIDE;
+  /** Generate the output informations */
+  void GenerateOutputInformation() ITK_OVERRIDE;
   /** Generate the input requested region */
   void GenerateInputRequestedRegion() ITK_OVERRIDE;
   /** Before Parallel textures extraction */
@@ -246,7 +248,7 @@ private:
   SizeType m_SubsampleFactor;
 
   /** Sub-sampling offset */
-  IndexType m_SubsampleOffset;
+  OffsetType m_SubsampleOffset;
 };
 } // End namespace otb
 
diff --git a/Modules/Feature/Textures/include/otbScalarImageToTexturesFilter.txx b/Modules/Feature/Textures/include/otbScalarImageToTexturesFilter.txx
index c67e3a9ebf..9d18b5d1e6 100644
--- a/Modules/Feature/Textures/include/otbScalarImageToTexturesFilter.txx
+++ b/Modules/Feature/Textures/include/otbScalarImageToTexturesFilter.txx
@@ -39,6 +39,8 @@ ScalarImageToTexturesFilter<TInputImage, TOutputImage>
 , m_NumberOfBinsPerAxis(8)
 , m_InputImageMinimum(0)
 , m_InputImageMaximum(255)
+, m_SubsampleFactor()
+, m_SubsampleOffset()
 {
   // There are 8 outputs corresponding to the 8 textures indices
   this->SetNumberOfRequiredOutputs(8);
@@ -52,6 +54,9 @@ ScalarImageToTexturesFilter<TInputImage, TOutputImage>
   this->SetNthOutput(5, OutputImageType::New());
   this->SetNthOutput(6, OutputImageType::New());
   this->SetNthOutput(7, OutputImageType::New());
+
+  this->m_SubsampleFactor.Fill(1);
+  this->m_SubsampleOffset.Fill(0);
 }
 
 template <class TInputImage, class TOutputImage>
@@ -163,6 +168,36 @@ ScalarImageToTexturesFilter<TInputImage, TOutputImage>
   return static_cast<OutputImageType *>(this->GetOutput(7));
 }
 
+template <class TInputImage, class TOutputImage>
+void
+ScalarImageToTexturesFilter<TInputImage, TOutputImage>
+::GenerateOutputInformation()
+{
+  // First, call superclass implementation
+  Superclass::GenerateOutputInformation();
+
+  // Compute output size, origin & spacing
+  OutputImagePointerType outputPtr = this->GetOutput();
+
+  InputRegionType inputRegion = this->GetInput()->GetLargestPossibleRegion();
+  OutputRegionType outputRegion;
+  outputRegion.SetIndex(0,0);
+  outputRegion.SetIndex(1,0);
+  outputRegion.SetSize(0, 1 + (inputRegion.GetSize(0) - 1 - m_SubsampleOffset[0]) / m_SubsampleFactor[0]);
+  outputRegion.SetSize(1, 1 + (inputRegion.GetSize(1) - 1 - m_SubsampleOffset[1]) / m_SubsampleFactor[1]);
+
+  typename OutputImageType::SpacingType outSpacing = this->GetInput()->GetSpacing();
+  outSpacing[0] *= m_SubsampleFactor[0];
+  outSpacing[1] *= m_SubsampleFactor[1];
+
+  typename OutputImageType::PointType outOrigin;
+  this->GetInput()->TransformIndexToPhysicalPoint(inputRegion.GetIndex()+m_SubsampleOffset,outOrigin);
+
+  outputPtr->SetLargestPossibleRegion(outputRegion);
+  outputPtr->SetOrigin(outOrigin);
+  outputPtr->SetSpacing(outSpacing);
+}
+
 template <class TInputImage, class TOutputImage>
 void
 ScalarImageToTexturesFilter<TInputImage, TOutputImage>
@@ -189,6 +224,13 @@ ScalarImageToTexturesFilter<TInputImage, TOutputImage>
   typename OutputRegionType::SizeType  outputSize   = outputRequestedRegion.GetSize();
   typename InputRegionType::IndexType  inputIndex;
   typename InputRegionType::SizeType   inputSize;
+  InputRegionType inputLargest = inputPtr->GetLargestPossibleRegion();
+
+  // Convert index and size to full grid
+  outputIndex[0] = outputIndex[0] * m_SubsampleFactor[0] + m_SubsampleOffset[0] + inputLargest.GetIndex(0);
+  outputIndex[1] = outputIndex[1] * m_SubsampleFactor[1] + m_SubsampleOffset[1] + inputLargest.GetIndex(1);
+  outputSize[0] = 1 + (outputSize[0] - 1) * m_SubsampleFactor[0];
+  outputSize[1] = 1 + (outputSize[1] - 1) * m_SubsampleFactor[1];
 
   // First, apply offset
   for (unsigned int dim = 0; dim < InputImageType::ImageDimension; ++dim)
@@ -278,6 +320,8 @@ ScalarImageToTexturesFilter<TInputImage, TOutputImage>
 
   const double log2 = vcl_log(2.0);
 
+  InputRegionType inputLargest = inputPtr->GetLargestPossibleRegion();
+
   // Set-up progress reporting
   itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels());
 
@@ -295,11 +339,15 @@ ScalarImageToTexturesFilter<TInputImage, TOutputImage>
     typename InputRegionType::IndexType inputIndex;
     typename InputRegionType::SizeType inputSize;
 
+    // Convert index to full grid
+    typename OutputImageType::IndexType outIndex;
+
     // First, create an window for neighborhood iterator based on m_Radius
     // For example, if xradius and yradius is 2. window size is 5x5 (2 * radius + 1).
     for (unsigned int dim = 0; dim < InputImageType::ImageDimension; ++dim)
       {
-      inputIndex[dim] = energyIt.GetIndex()[dim] - m_Radius[dim];
+      outIndex[dim] = energyIt.GetIndex()[dim] * m_SubsampleFactor[dim] + m_SubsampleOffset[dim] + inputLargest.GetIndex(dim);
+      inputIndex[dim] = outIndex[dim] - m_Radius[dim];
       inputSize[dim] = 2 * m_Radius[dim] + 1;
       }
 
-- 
GitLab