From d4644f20e0fceb14ac40936ee3684dc6009d43d3 Mon Sep 17 00:00:00 2001
From: Luc Hermitte <luc.hermitte@c-s.fr>
Date: Tue, 12 Mar 2019 09:43:43 +0100
Subject: [PATCH] PERF: Improve FunctorImageFilter performances

`itk::UnaryFunctorImageFilter` only updates the progress reporter once per
line.
This commit mimics that behaviour.

The performance improvment is small, less than 10% on simple filters like a
scaling filter that multiplies pixel values.
---
 .../Functor/include/otbFunctorImageFilter.hxx | 27 ++++++++++++-------
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/Modules/Core/Functor/include/otbFunctorImageFilter.hxx b/Modules/Core/Functor/include/otbFunctorImageFilter.hxx
index 5b2a0fbabf..d9f528a786 100644
--- a/Modules/Core/Functor/include/otbFunctorImageFilter.hxx
+++ b/Modules/Core/Functor/include/otbFunctorImageFilter.hxx
@@ -47,7 +47,7 @@ template<class T> int SetInputRequestedRegion(const T * img, const itk::ImageReg
 
   // The ugly cast in all ITK filters
   T * nonConstImg = const_cast<T*>(img);
-  
+
   if(currentRegion.Crop(img->GetLargestPossibleRegion()))
     {
     nonConstImg->SetRequestedRegion(currentRegion);
@@ -56,7 +56,7 @@ template<class T> int SetInputRequestedRegion(const T * img, const itk::ImageReg
   else
     {
     nonConstImg->SetRequestedRegion(currentRegion);
-        
+
     // build an exception
     itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
     e.SetLocation("::SetInputRequestedRegion<>()");
@@ -281,9 +281,17 @@ void
 FunctorImageFilter<TFunction, TNameMap>
 ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId)
 {
+  const auto &regionSize = outputRegionForThread.GetSize();
+
+  if( regionSize[0] == 0 )
+  {
+    return;
+  }
+  const auto numberOfLinesToProcess = outputRegionForThread.GetNumberOfPixels() / regionSize[0];
+  itk::ProgressReporter p(this, threadId, numberOfLinesToProcess);
+
   // Build output iterator
   itk::ImageScanlineIterator<OutputImageType> outIt(this->GetOutput(),outputRegionForThread);
-  itk::ProgressReporter p(this,threadId,outputRegionForThread.GetNumberOfPixels());
 
   // This will build a tuple of iterators to be used
   auto inputIterators = functor_filter_details::MakeIterators(this->GetInputs(),outputRegionForThread, m_Radius,InputHasNeighborhood{});
@@ -291,21 +299,20 @@ FunctorImageFilter<TFunction, TNameMap>
   // Build a default value
   typename OutputImageType::PixelType outputValueHolder;
   itk::NumericTraits<typename OutputImageType::PixelType>::SetLength(outputValueHolder,this->GetOutput()->GetNumberOfComponentsPerPixel());
-  
+
   while(!outIt.IsAtEnd())
-    {
+  {
     // MoveIterartors will ++ all iterators in the tuple
     for(;!outIt.IsAtEndOfLine();++outIt,functor_filter_details::MoveIterators(inputIterators))
-      {
+    {
       // This will call the operator with inputIterators Get() results
       // and fill outputValueHolder with the result.
       functor_filter_details::CallOperator(outputValueHolder,m_Functor,inputIterators);
       outIt.Set(outputValueHolder);
-      // Update progress
-      p.CompletedPixel();
-      }
-    outIt.NextLine();
     }
+    outIt.NextLine();
+    p.CompletedPixel(); // may throw
+  }
 }
 
 } // end namespace otb
-- 
GitLab