From 8d4e8f1b2d6a05e1824d8966a452aee700d2d3f9 Mon Sep 17 00:00:00 2001
From: Jordi Inglada <jordi.inglada@cesbio.cnes.fr>
Date: Sun, 30 Sep 2018 19:02:08 +0200
Subject: [PATCH] ADD: start of FunctorImageFilter

A generic functor filter which
1. can take and produce vector and scalar images
2. with or without the use of image neighborhoods in input
3. with NbInputs >=1
4. and with any number of output bands
---
 .../include/otbFunctorImageFilter.h           | 175 ++++++++++++++++++
 .../include/otbFunctorImageFilter.hxx         |  54 ++++++
 .../ImageManipulation/test/CMakeLists.txt     |   5 +
 .../test/otbFunctorImageFilter.cxx            |  60 ++++++
 .../test/otbImageManipulationTestDriver.cxx   |   1 +
 5 files changed, 295 insertions(+)
 create mode 100644 Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.h
 create mode 100644 Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.hxx
 create mode 100644 Modules/Filtering/ImageManipulation/test/otbFunctorImageFilter.cxx

diff --git a/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.h b/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.h
new file mode 100644
index 0000000000..ffbbcc69c1
--- /dev/null
+++ b/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
+ *
+ * This file is part of Orfeo Toolbox
+ *
+ *     https://www.orfeo-toolbox.org/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef otbFunctorImageFilter_h
+#define otbFunctorImageFilter_h
+
+#include "itkImageToImageFilter.h"
+#include "otbImage.h"
+#include "otbVectorImage.h"
+#include "itkConstNeighborhoodIterator.h"
+#include "itkProcessObject.h"
+#include <type_traits>
+
+namespace otb
+{
+
+template<typename TOutput>
+struct ImageFunctorBase
+{
+  using OutputImageType = typename std::conditional<std::is_scalar<TOutput>::value, 
+                                                    otb::Image<TOutput>,
+                                                    otb::VectorImage<TOutput>>::type;
+
+  void SetRadius(size_t r)
+  {
+    m_Radius = r;
+  }
+  
+protected:
+  size_t m_Radius = 0;
+
+};
+
+template<typename TInput, typename TOutput>
+struct ImageFunctor : ImageFunctorBase<TOutput> {
+  using HasNeighborhood = std::false_type;
+  using InputImageType = typename std::conditional<std::is_scalar<TInput>::value, 
+                                                   otb::Image<TInput>,
+                                                   otb::VectorImage<TInput>>::type;
+
+};
+
+
+template<typename TInput, typename TOutput>
+struct ImageFunctor<typename itk::ConstNeighborhoodIterator<TInput>, 
+                    TOutput> : ImageFunctorBase<TOutput> {
+  using HasNeighborhood = std::true_type;
+  using InputImageType = TInput;
+};
+
+/** \class FunctorImageFilter
+ * \brief Implements 
+ *
+ * This class is 
+ *
+ * \ingroup IntensityImageFilters   Multithreaded
+ *
+ * \ingroup OTBImageManipulation
+ */
+template <class TFunction>
+class ITK_EXPORT FunctorImageFilter
+  : public itk::ImageToImageFilter<typename TFunction::InputImageType, 
+                                   typename TFunction::OutputImageType>
+{
+public:
+  using Self = FunctorImageFilter;
+  using FunctorType = TFunction;
+  using Pointer = itk::SmartPointer<Self>;
+  using ConstPointer = itk::SmartPointer<const Self>;
+  using InputImageType = typename FunctorType::InputImageType;
+  using InputImagePointer = typename InputImageType::ConstPointer;
+  using InputImageRegionType = typename InputImageType::RegionType;
+  using InputImagePixelType = typename InputImageType::PixelType;
+  using InputImageSizeType = typename InputImageType::SizeType;
+  using InputImageIndexType = typename InputImageType::IndexType;
+  using OutputImageType = typename FunctorType::OutputImageType;
+  using OutputImagePointer = typename OutputImageType::Pointer;
+  using OutputImageRegionType = typename OutputImageType::RegionType;
+  using OutputImagePixelType = typename OutputImageType::PixelType;
+  using Superclass = itk::ImageToImageFilter<InputImageType, 
+                                             OutputImageType>;
+  using ProcessObjectType = itk::ProcessObject;
+
+/** Method for creation by passing the filter type. */
+  itkNewMacro(Self);
+
+
+/** Run-time type information (and related methods). */
+itkTypeMacro(FunctorImageFilter, ImageToImageFilter);
+
+ 
+/** Get the functor object.  The functor is returned by reference.
+   * (Functors do not have to derive from itk::LightObject, so they do
+   * not necessarily have a reference count. So we cannot return a
+   * SmartPointer.) */
+FunctorType& GetFunctor()
+{
+  this->Modified();
+  return m_Functor;
+}
+
+/** Get the functor object.  The functor is returned by reference.
+   * (Functors do not have to derive from itk::LightObject, so they do
+   * not necessarily have a reference count. So we cannot return a
+   * SmartPointer.) */
+const FunctorType& GetFunctor() const
+{
+  return m_Functor;
+}
+
+/** Set the functor object.  This replaces the current Functor with a
+   * copy of the specified Functor. This allows the user to specify a
+   * functor that has ivars set differently than the default functor.
+   * This method requires an operator!=() be defined on the functor
+   * (or the compiler's default implementation of operator!=() being
+   * appropriate). */
+void SetFunctor(const FunctorType& functor)
+{
+  m_Functor = functor;
+  this->Modified();
+}
+
+private:
+FunctorImageFilter(){} ;
+FunctorImageFilter(const Self &) ;
+void operator =(const Self&) ;
+~FunctorImageFilter() override {}
+
+protected:
+
+/** FunctorImageFilter can be implemented as a multithreaded filter.
+   * Therefore, this implementation provides a ThreadedGenerateData() routine
+   * which is called for each processing thread. The output image data is
+   * allocated automatically by the superclass prior to calling
+   * ThreadedGenerateData().  ThreadedGenerateData can only write to the
+   * portion of the output image specified by the parameter
+   * "outputRegionForThread"
+   *
+   * \sa ImageToImageFilter::ThreadedGenerateData(),
+   *     ImageToImageFilter::GenerateData()  */
+    void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId) override;
+
+  /**
+   * Pad the input requested region by radius
+   */
+  void GenerateInputRequestedRegion(void) override;
+
+
+  FunctorType m_Functor;
+};
+
+} // namespace otb
+
+#ifndef OTB_MANUAL_INSTANTIATION
+#include "otbFunctorImageFilter.hxx"
+#endif
+
+#endif
diff --git a/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.hxx b/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.hxx
new file mode 100644
index 0000000000..e5006d887d
--- /dev/null
+++ b/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.hxx
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
+ *
+ * This file is part of Orfeo Toolbox
+ *
+ *     https://www.orfeo-toolbox.org/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef otbFunctorImageFilter_hxx
+#define otbFunctorImageFilter_hxx
+
+#include "otbFunctorImageFilter.h"
+#include "itkImageRegionIterator.h"
+#include "itkProgressReporter.h"
+
+namespace otb
+{
+
+template <class TFunction>
+void
+FunctorImageFilter<TFunction>
+::GenerateInputRequestedRegion()
+{
+  // call the superclass' implementation of this method
+  Superclass::GenerateInputRequestedRegion();
+}
+
+/**
+ * ThreadedGenerateData Performs the neighborhood-wise operation
+ */
+template <class TFunction>
+void
+FunctorImageFilter<TFunction>
+::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId)
+{
+  (void) outputRegionForThread;
+  (void) threadId;
+}
+
+} // end namespace otb
+
+#endif
diff --git a/Modules/Filtering/ImageManipulation/test/CMakeLists.txt b/Modules/Filtering/ImageManipulation/test/CMakeLists.txt
index adc5227175..92822a25e4 100644
--- a/Modules/Filtering/ImageManipulation/test/CMakeLists.txt
+++ b/Modules/Filtering/ImageManipulation/test/CMakeLists.txt
@@ -71,6 +71,7 @@ otbImageToNoDataMaskFilter.cxx
 otbChangeInformationImageFilter.cxx
 otbGridResampleImageFilter.cxx
 otbMaskedIteratorDecorator.cxx
+otbFunctorFilter.cxx
 )
 
 add_executable(otbImageManipulationTestDriver ${OTBImageManipulationTests})
@@ -621,3 +622,7 @@ otb_add_test(NAME bfTvMaskedIteratorDecoratorDegenerate COMMAND otbImageManipula
 otb_add_test(NAME bfTvMaskedIteratorDecoratorExtended COMMAND otbImageManipulationTestDriver
   otbMaskedIteratorDecoratorExtended
 )
+
+otb_add_test(NAME bfTvFunctorFilter COMMAND otbImageManipulationTestDriver
+  otbFunctorFilter
+  )
diff --git a/Modules/Filtering/ImageManipulation/test/otbFunctorImageFilter.cxx b/Modules/Filtering/ImageManipulation/test/otbFunctorImageFilter.cxx
new file mode 100644
index 0000000000..9e82bd71d9
--- /dev/null
+++ b/Modules/Filtering/ImageManipulation/test/otbFunctorImageFilter.cxx
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
+ *
+ * This file is part of Orfeo Toolbox
+ *
+ *     https://www.orfeo-toolbox.org/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "itkMacro.h"
+#include "otbFunctorImageFilter.h"
+
+struct Funct1 : otb::ImageFunctor<double, double>
+{
+  double operator()(double p)
+  {
+    return p;
+  }
+};
+
+struct Funct2 : otb::ImageFunctor<double, itk::VariableLengthVector<double>>
+{
+  itk::VariableLengthVector<double> operator()(double p)
+  {
+    itk::VariableLengthVector<double> result(2);
+    result[0] = result[1] = p;
+    return result;
+  }
+};
+
+using IntImageNeighborhood = itk::ConstNeighborhoodIterator<otb::Image<int>>;
+struct Funct3 : otb::ImageFunctor<IntImageNeighborhood, 
+                                  double>
+{
+  double operator()(IntImageNeighborhood p)
+  {
+    return static_cast<double>(p.GetPixel(0));
+  }
+};
+
+
+int otbFunctorFilter(int itkNotUsed(argc), char * itkNotUsed(argv) [])
+{
+  auto filter1 = otb::FunctorImageFilter<Funct1>::New();
+  auto filter2 = otb::FunctorImageFilter<Funct2>::New();
+  auto filter3 = otb::FunctorImageFilter<Funct3>::New();
+  return EXIT_SUCCESS;
+}
+
diff --git a/Modules/Filtering/ImageManipulation/test/otbImageManipulationTestDriver.cxx b/Modules/Filtering/ImageManipulation/test/otbImageManipulationTestDriver.cxx
index 08aa5acb7d..739dd77304 100644
--- a/Modules/Filtering/ImageManipulation/test/otbImageManipulationTestDriver.cxx
+++ b/Modules/Filtering/ImageManipulation/test/otbImageManipulationTestDriver.cxx
@@ -74,4 +74,5 @@ void RegisterTests()
   REGISTER_TEST(otbMaskedIteratorDecoratorNominal);
   REGISTER_TEST(otbMaskedIteratorDecoratorDegenerate);
   REGISTER_TEST(otbMaskedIteratorDecoratorExtended);
+  REGISTER_TEST(otbFunctorImageFilter);
 }
-- 
GitLab