From 6d10b55822c86d49500a3f2496424efffd259c85 Mon Sep 17 00:00:00 2001
From: Julien Michel <julien.michel@cnes.fr>
Date: Fri, 5 Oct 2018 16:57:03 +0200
Subject: [PATCH] ENH: FunctorImageFilter is now fully variadic from Functor
 definition

---
 Modules/Core/ImageBase/test/CMakeLists.txt    |   1 -
 .../ImageBase/test/otbFunctorImageFilter.cxx  | 203 ------------------
 .../ImageBase/test/otbImageBaseTestDriver.cxx |   1 -
 .../include/otbFunctorImageFilter.h           | 172 ++++++++-------
 .../include/otbVariadicInputsImageFilter.h    |  75 +++++++
 .../test/otbFunctorImageFilter.cxx            |  77 ++++++-
 6 files changed, 241 insertions(+), 288 deletions(-)
 delete mode 100644 Modules/Core/ImageBase/test/otbFunctorImageFilter.cxx
 create mode 100644 Modules/Filtering/ImageManipulation/include/otbVariadicInputsImageFilter.h

diff --git a/Modules/Core/ImageBase/test/CMakeLists.txt b/Modules/Core/ImageBase/test/CMakeLists.txt
index ad4522d2e0..b9e7da8cf4 100644
--- a/Modules/Core/ImageBase/test/CMakeLists.txt
+++ b/Modules/Core/ImageBase/test/CMakeLists.txt
@@ -40,7 +40,6 @@ set(OTBImageBaseTests
   otbImageTest.cxx
   otbImageFunctionAdaptor.cxx
   otbMetaImageFunction.cxx
-  otbFunctorImageFilter.cxx
   )
 
 add_executable(otbImageBaseTestDriver ${OTBImageBaseTests})
diff --git a/Modules/Core/ImageBase/test/otbFunctorImageFilter.cxx b/Modules/Core/ImageBase/test/otbFunctorImageFilter.cxx
deleted file mode 100644
index 9867264535..0000000000
--- a/Modules/Core/ImageBase/test/otbFunctorImageFilter.cxx
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * 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 "otbFunctor.h"
-//#include "otbFunctorImageFilter.h"
-
-#include "otbImage.h"
-#include "otbVectorImage.h"
-#include "itkNeighborhood.h"
-#include "itkImageRegionIterator.h"
-#include "itkImageSource.h"
-#include <tuple>
-
-
-// Proxy to switch image type from T (Jordi has better code for that)
-template <typename T> struct ImageTypeProxy
-{
-  using ImageType = otb::Image<T>;
-};
-
-template <typename T> struct ImageTypeProxy<itk::VariableLengthVector<T> >
-{
-  using ImageType = otb::VectorImage<T>;
-};
-
-
-// Variadic creation of iterator tuple
-template <class T> auto MakeIterator(itk::SmartPointer<T> img)
-{
-  itk::ImageRegionConstIterator<T> it(img,img->GetLargestPossibleRegion());
-  return it;
-}
-
-
-template<class... T>  auto MakeIterators(itk::SmartPointer<T>... args)
-  {
-    return std::make_tuple(MakeIterator(args)...);
-  }
-
-// Variadic call of operator from iterator tuple
-template <class Tuple, class Oper, size_t...Is> auto CallOperatorImpl(Tuple& t, const Oper & oper,std::index_sequence<Is...>)
-{
-  return oper(std::get<Is>(t).Get()...);
-}
-
-template <class Oper, typename ... Args> auto CallOperator(const Oper& oper, std::tuple<Args...> & t)
-{
-  return CallOperatorImpl(t,oper,std::make_index_sequence<sizeof...(Args)>{});
-}
-
-// Variadic move of iterators
-template<class Tuple,size_t...Is> auto MoveIteratorsImpl(Tuple & t, std::index_sequence<Is...>)
-{
-  return std::make_tuple(++(std::get<Is>(t) )...);
-}
-
-template<typename ... Args> void MoveIterators(std::tuple<Args...> & t)
-{
-  MoveIteratorsImpl(t,std::make_index_sequence<sizeof...(Args)>{});
-}
-
-
-// Variadic functor class (will disapear)
-template <typename Out, typename... T> class VariadicFunctor
-{  
-public:  
-  Out operator()(const T&...) const
-    {
-    return Out();
-    }
-
-  unsigned int GetNumberOfVariadicArgs() const
-  {
-    const unsigned int nbArgs = sizeof...(T);
-    return nbArgs;
-  }
-};
-
-// Example of functor
-template<typename Out, typename In1, typename In2> class AddFunctor : public VariadicFunctor<Out,In1,In2>
-{
-public:
-  Out operator()(const In1 & in1, const In2 & in2)
-  {
-    return static_cast<Out>(in1+in2);
-  }
-};
-
-
-template <typename ... Args> void Ignore(Args ...)
-{}
-
-template<class TOuptut, class ... TInputs> class VariadicInputsImageFilter : public itk::ImageSource<TOuptut>
-{
-public:
-  using Self = VariadicInputsImageFilter<TOuptut, TInputs...>;
-  using Pointer =  itk::SmartPointer<Self>;
-  using ConstPointer = itk::SmartPointer<const Self>;
-  using Superclass = itk::ImageSource<TOuptut>;
-
-  using InputTypesTupleType = std::tuple<TInputs...>;
-
-  itkNewMacro(Self);
-  
-  template <std::size_t I> void SetVInput(typename std::tuple_element<I,InputTypesTupleType>::type * inputPtr)
-  {
-    this->SetNthInput(I,inputPtr);
-  }
-
-  template <std::size_t I> const typename std::tuple_element<I,InputTypesTupleType>::type * GetVInput()
-  {
-    using ImageType = typename std::tuple_element<I,InputTypesTupleType>::type;
-    return dynamic_cast<const ImageType *>(this->GetInput(I));
-  }
-
-  void SetVInputs(TInputs*... inputs)
-  {
-    auto inTuple = std::make_tuple(inputs...);
-    SetInputsImpl(inTuple,std::make_index_sequence<sizeof...(inputs)>{});
-  }
-
-protected:
-  VariadicInputsImageFilter()
-  {
-    this->SetNumberOfRequiredInputs(sizeof...(TInputs));
-  };
-  
-  ~VariadicInputsImageFilter() = default;
-  
-private:
-  template<class Tuple, size_t...Is> auto SetInputsImpl(Tuple& t, std::index_sequence<Is...>)
-  {
-    return std::initializer_list<int>{(this->SetVInput<Is>(std::get<Is>(t)),0)...};
-  }
-  
-  VariadicInputsImageFilter(const Self&) = delete;
-  void operator=(const Self&) = delete;
-};
-
-
-using namespace otb;
-
-int otbFunctorImageFilter(int, char ** )
-{
-  using VectorImageType = VectorImage<double>;
-  using ImageType       = Image<unsigned int>;
-  using RegionType      = typename ImageType::RegionType;
-  using SizeType        = typename RegionType::SizeType;
-  using IndexType       = typename RegionType::IndexType;
-  
-  using NeighborhoodType = itk::Neighborhood<double,2>;
-  using VectorPixelType  = typename VectorImageType::PixelType;
-
-  auto vimage = VectorImageType::New();
-  auto image  = ImageType::New();
-
-  SizeType size({200,200});
-  
-  vimage->SetRegions(size);
-  image->SetRegions(size);
-
-  auto f1 = VariadicFunctor<double,itk::VariableLengthVector<double>,double>();
-  std::cout<<"Nb variadic args: "<<f1.GetNumberOfVariadicArgs();
-
-  auto iterators = MakeIterators(vimage,image);
-
-  MoveIterators(iterators);
-
-  auto res = CallOperator(f1,iterators);
- 
-
-  // auto it = MakeIterator(image,image->GetLargestPossibleRegion(),3, no_radius_tag());
-  // auto vit = MakeIterator(vimage,vimage->GetLargestPossibleRegion(),3,radius_tag());
-
-
-  auto filter = VariadicInputsImageFilter<VectorImageType,VectorImageType,ImageType>::New();
-
-  filter->SetVInput<0>(vimage);
-  filter->SetVInput<1>(image);
-
-  filter->SetVInputs(vimage,image);
-
-  std::cout<<filter->GetVInput<0>()<< filter->GetVInput<1>()<<std::endl;
-  
-  return EXIT_SUCCESS;
-}
diff --git a/Modules/Core/ImageBase/test/otbImageBaseTestDriver.cxx b/Modules/Core/ImageBase/test/otbImageBaseTestDriver.cxx
index 933b9c5a5b..991c0dc859 100644
--- a/Modules/Core/ImageBase/test/otbImageBaseTestDriver.cxx
+++ b/Modules/Core/ImageBase/test/otbImageBaseTestDriver.cxx
@@ -41,5 +41,4 @@ void RegisterTests()
   REGISTER_TEST(otbImageTest);
   REGISTER_TEST(otbImageFunctionAdaptor);
   REGISTER_TEST(otbMetaImageFunction);
-  REGISTER_TEST(otbFunctorImageFilter);
 }
diff --git a/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.h b/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.h
index 99524487fc..b7a5dfbdcd 100644
--- a/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.h
+++ b/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.h
@@ -22,51 +22,56 @@
 #define otbFunctorImageFilter_h
 
 #include "itkImageToImageFilter.h"
+#include "otbVariadicInputsImageFilter.h"
 #include "otbImage.h"
 #include "otbVectorImage.h"
 #include "itkConstNeighborhoodIterator.h"
+#include "itkImageRegionConstIterator.h"
 #include "itkProcessObject.h"
 #include <type_traits>
 #include "otbFunctionTraits.h"
+#include "itkDefaultConvertPixelTraits.h"
 
 namespace otb
 {
 
-template<typename TOutput>
-struct ImageFunctorBase
+namespace functor_filter_details
 {
-  void SetRadius(size_t r)
-  {
-    m_Radius = r;
-  }
-   
-  unsigned int GetNumberOfOutputBands() const
+// Variadic creation of iterator tuple
+template <class T> auto MakeIterator(itk::SmartPointer<T> img)
+{
+  itk::ImageRegionConstIterator<T> it(img,img->GetLargestPossibleRegion());
+  return it;
+}
+
+template<class... T>  auto MakeIterators(itk::SmartPointer<T>... args)
   {
-    return 1;
+    return std::make_tuple(MakeIterator(args)...);
   }
 
-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;
+// Variadic call of operator from iterator tuple
+template <class Tuple, class Oper, size_t...Is> auto CallOperatorImpl(Tuple& t, const Oper & oper,std::index_sequence<Is...>)
+{
+  return oper(std::get<Is>(t).Get()...);
+}
 
-};
+template <class Oper, typename ... Args> auto CallOperator(const Oper& oper, std::tuple<Args...> & t)
+{
+  return CallOperatorImpl(t,oper,std::make_index_sequence<sizeof...(Args)>{});
+}
 
+// Variadic move of iterators
+template<class Tuple,size_t...Is> auto MoveIteratorsImpl(Tuple & t, std::index_sequence<Is...>)
+{
+  return std::make_tuple(++(std::get<Is>(t) )...);
+}
 
-template<typename TInput, typename TOutput>
-struct ImageFunctor<typename itk::ConstNeighborhoodIterator<TInput>, 
-                    TOutput> : ImageFunctorBase<TOutput> {
-  using HasNeighborhood = std::true_type;
-  using InputImageType = TInput;
-};
+template<typename ... Args> void MoveIterators(std::tuple<Args...> & t)
+{
+  MoveIteratorsImpl(t,std::make_index_sequence<sizeof...(Args)>{});
+}
 
+} // end namespace functor_filter_details
 
 template<typename T>
 using FTraits = typename FunctionTraits::function_traits<T>;
@@ -77,48 +82,65 @@ using FResultType = typename FTraits<T>::result_type;
 template<typename T, size_t i>
 using ArgType = typename FTraits<T>::template arg<i>::type;
 
+template <class T> struct IsNeighborhood
+{
+  using ValueType = std::false_type;
+  static constexpr bool value = false;
+  using PixelType = T;
+};
+
+  template <class T> struct IsNeighborhood<itk::Neighborhood<T>>
+{
+  using ValueType = std::true_type;
+  static constexpr bool value = true;
+  using PixelType = T;
+};
+
+template<typename T>
+struct TInputImage
+{
+  using ArgumentType = T; //ArgType<T,N>;
+  using PixelType = typename IsNeighborhood<typename std::remove_cv<typename std::remove_reference<ArgumentType>::type >::type>::PixelType;
+  using ScalarType = typename itk::DefaultConvertPixelTraits<PixelType>::ComponentType;
+  using ImageType = typename std::conditional<std::is_scalar<PixelType>::value,
+                                     otb::Image< ScalarType >,
+                                     otb::VectorImage< ScalarType > >::type;
+};
+
+
 template<typename T>
-using InputArgumentType = ArgType<T, 0>;
+struct TOutputImage
+{
+  using ResultType = T; //FResultType<T>;
+  using ScalarType = typename itk::DefaultConvertPixelTraits<ResultType>::ComponentType;
+  using ImageType =  typename std::conditional<std::is_scalar<ResultType>::value,
+                                     typename otb::Image<ScalarType>,
+                                     typename otb::VectorImage<ScalarType> >::type;
+};
 
 
-template<class T, class R = void>  
-struct enable_if_type { typedef R type; };
 
-template<class T, class Enable = void>
-struct IsNeighborhood : std::false_type {};
+template <typename T> struct FunctorFilterSuperclassHelper : public FunctorFilterSuperclassHelper<decltype(&T::operator())> {};
 
-template<class T>
-struct IsNeighborhood<T, typename enable_if_type<typename T::NeighborhoodType>::type> : std::true_type
-{};
 
-template<typename TFunction, bool B = true>
-struct TII
+template <typename R, typename... T> struct FunctorFilterSuperclassHelper<R(*)(T...)>
 {
-  using type = typename InputArgumentType<TFunction>::ImageType;
+  using OutputImageType = typename TOutputImage<R>::ImageType;
+  using FilterType = VariadicInputsImageFilter<OutputImageType,typename TInputImage<T>::ImageType...>;
+
 };
 
-template<typename TFunction>
-struct TII<TFunction, !IsNeighborhood<InputArgumentType<TFunction>>::value>
+template <typename C, typename R, typename... T> struct FunctorFilterSuperclassHelper<R(C::*)(T...) const>
 {
-  using InputArgument = InputArgumentType<TFunction>;
-  using type = typename std::conditional<std::is_scalar<InputArgument>::value,
-                                         typename otb::Image<InputArgument>,
-                                         typename otb::VectorImage<InputArgument>
-                                         >::type ;
+  using OutputImageType = typename TOutputImage<R>::ImageType;
+  using FilterType = VariadicInputsImageFilter<OutputImageType,typename TInputImage<T>::ImageType...>;
 };
 
-template<typename TFunction>
-using TInputImage = typename TII<TFunction>::type;
-
-// OutputImageType: if the result of the 
-// functor is a scalar -> otb::Image,
-// otherwise, otb::VectorImage
-         template<typename TFunction, typename ResultType = FResultType<TFunction>>
-         using TOutputImage =   
-         typename std::conditional< std::is_scalar<ResultType>::value, 
-                                    typename otb::Image<ResultType>,
-                                    typename otb::VectorImage<ResultType>
-                                    >::type;
+template <typename C, typename R, typename... T> struct FunctorFilterSuperclassHelper<R(C::*)(T...)>
+{
+  using OutputImageType = typename TOutputImage<R>::ImageType;
+  using FilterType = VariadicInputsImageFilter<OutputImageType,typename TInputImage<T>::ImageType...>;
+};
 
 
 /** \class FunctorImageFilter
@@ -132,7 +154,7 @@ using TInputImage = typename TII<TFunction>::type;
  */
 template <class TFunction>
     class ITK_EXPORT FunctorImageFilter
-  : public itk::ImageToImageFilter<TInputImage<TFunction>, TOutputImage<TFunction>>
+  : public FunctorFilterSuperclassHelper<TFunction>::FilterType
 {
 
 public:
@@ -141,19 +163,21 @@ public:
   using Pointer = itk::SmartPointer<Self>;
   using ConstPointer = itk::SmartPointer<const Self>;
 
-  using InputImageType = TInputImage<TFunction>;
-  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 = TOutputImage<TFunction>;
-  using OutputImagePointer = typename OutputImageType::Pointer;
+  // using InputImageType = typename TInputImage<TFunction,0>::ImageType;
+  // 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 TOutputImage<TFunction>::ImageType;
+  // using OutputImagePointer = typename OutputImageType::Pointer;
+  // using OutputImageRegionType = typename OutputImageType::RegionType;
+  // using OutputImagePixelType = typename OutputImageType::PixelType;
+  using Superclass = typename FunctorFilterSuperclassHelper<TFunction>::FilterType;
+  using OutputImageType = typename Superclass::OutputImageType;
   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. */
@@ -201,7 +225,7 @@ FunctorImageFilter();
 FunctorImageFilter(const FunctorType& f) : m_Functor(f) {};
 FunctorImageFilter(const Self &) ;
 void operator =(const Self&) ;
-~FunctorImageFilter() override {}
+~FunctorImageFilter() {}
 
 protected:
 
@@ -215,18 +239,18 @@ protected:
    *
    * \sa ImageToImageFilter::ThreadedGenerateData(),
    *     ImageToImageFilter::GenerateData()  */
-    void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId) override;
+    virtual void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId) override;
 
   /**
    * Pad the input requested region by radius
    */
-  void GenerateInputRequestedRegion(void) override;
+  virtual void GenerateInputRequestedRegion(void) override;
 
 
   FunctorType m_Functor;
 };
 
-} // namespace otb
+}// namespace otb
 
 #ifndef OTB_MANUAL_INSTANTIATION
 #include "otbFunctorImageFilter.hxx"
diff --git a/Modules/Filtering/ImageManipulation/include/otbVariadicInputsImageFilter.h b/Modules/Filtering/ImageManipulation/include/otbVariadicInputsImageFilter.h
new file mode 100644
index 0000000000..ecc6269c63
--- /dev/null
+++ b/Modules/Filtering/ImageManipulation/include/otbVariadicInputsImageFilter.h
@@ -0,0 +1,75 @@
+/*
+ * 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 otb_VariadicInputsImageFilter_h
+#define otb_VariadicInputsImageFilter_h
+
+namespace otb {
+
+template<class TOuptut, class ... TInputs> class VariadicInputsImageFilter : public itk::ImageSource<TOuptut>
+{
+public:
+  using Self = VariadicInputsImageFilter<TOuptut, TInputs...>;
+  using Pointer =  itk::SmartPointer<Self>;
+  using ConstPointer = itk::SmartPointer<const Self>;
+  using Superclass = itk::ImageSource<TOuptut>;
+
+  using InputTypesTupleType = std::tuple<TInputs...>;
+
+  itkNewMacro(Self);
+  
+  template <std::size_t I> void SetVInput(typename std::tuple_element<I,InputTypesTupleType>::type * inputPtr)
+  {
+    this->SetNthInput(I,inputPtr);
+  }
+
+  template <std::size_t I> const typename std::tuple_element<I,InputTypesTupleType>::type * GetVInput()
+  {
+    using ImageType = typename std::tuple_element<I,InputTypesTupleType>::type;
+    return dynamic_cast<const ImageType *>(this->GetInput(I));
+  }
+
+  void SetVInputs(TInputs*... inputs)
+  {
+    auto inTuple = std::make_tuple(inputs...);
+    SetInputsImpl(inTuple,std::make_index_sequence<sizeof...(inputs)>{});
+  }
+
+protected:
+  VariadicInputsImageFilter()
+  {
+    this->SetNumberOfRequiredInputs(sizeof...(TInputs));
+  };
+  
+  ~VariadicInputsImageFilter() = default;
+  
+private:
+  template<class Tuple, size_t...Is> auto SetInputsImpl(Tuple& t, std::index_sequence<Is...>)
+  {
+    return std::initializer_list<int>{(this->SetVInput<Is>(std::get<Is>(t)),0)...};
+  }
+  
+  VariadicInputsImageFilter(const Self&) = delete;
+  void operator=(const Self&) = delete;
+};
+
+}
+
+#endif
diff --git a/Modules/Filtering/ImageManipulation/test/otbFunctorImageFilter.cxx b/Modules/Filtering/ImageManipulation/test/otbFunctorImageFilter.cxx
index 95d5b97d79..49986b1e5a 100644
--- a/Modules/Filtering/ImageManipulation/test/otbFunctorImageFilter.cxx
+++ b/Modules/Filtering/ImageManipulation/test/otbFunctorImageFilter.cxx
@@ -20,8 +20,17 @@
 
 #include "itkMacro.h"
 #include "otbFunctorImageFilter.h"
+#include "otbVariadicInputsImageFilter.h"
 
-struct Funct1 : otb::ImageFunctor<double, double>
+#include "otbImage.h"
+#include "otbVectorImage.h"
+#include "itkNeighborhood.h"
+#include "itkImageRegionIterator.h"
+#include "itkImageSource.h"
+#include <tuple>
+
+
+struct Funct1
 {
   double operator()(double p)
   {
@@ -29,9 +38,9 @@ struct Funct1 : otb::ImageFunctor<double, double>
   }
 };
 
-struct Funct2 : otb::ImageFunctor<double, itk::VariableLengthVector<double>>
+struct Funct2
 {
-  itk::VariableLengthVector<double> operator()(double p)
+  itk::VariableLengthVector<double> operator()(double p) const
   {
     itk::VariableLengthVector<double> result(2);
     result[0] = result[1] = p;
@@ -39,13 +48,12 @@ struct Funct2 : otb::ImageFunctor<double, itk::VariableLengthVector<double>>
   }
 };
 
-using IntImageNeighborhood = itk::ConstNeighborhoodIterator<otb::Image<int>>;
-struct Funct3 : otb::ImageFunctor<IntImageNeighborhood, 
-                                  double>
+using IntImageNeighborhood = itk::Neighborhood<int>;
+struct Funct3
 {
-  double operator()(IntImageNeighborhood p)
+  double operator()(const IntImageNeighborhood & p)
   {
-    return static_cast<double>(p.GetPixel(0));
+    return static_cast<double>(p.GetCenterValue());
   }
 };
 
@@ -54,17 +62,68 @@ auto Lambda1 = [](double p)
                  return p;
                };
 
+struct Funct4
+{
+  itk::VariableLengthVector<double> operator()(double p, const itk::VariableLengthVector<double> & vp) const
+  {
+    itk::VariableLengthVector<double> result(2);
+    result[0] = result[1] = p;
+    return result;
+  }
+};
 
 using OImage = typename otb::Image<int>;
-using Neig = typename itk::ConstNeighborhoodIterator<OImage>;
+using Neig = typename itk::Neighborhood<int>;
 
 static_assert(otb::IsNeighborhood<Neig>::value, "err");
 static_assert(!otb::IsNeighborhood<OImage>::value, "err");
 static_assert(!otb::IsNeighborhood<double>::value, "err");
 
 
+using namespace otb::functor_filter_details;
+using namespace otb;
+
 int otbFunctorImageFilter(int itkNotUsed(argc), char * itkNotUsed(argv) [])
 {
+  // test functions in functor_filter_details namespace
+  using VectorImageType = VectorImage<double>;
+  using ImageType       = Image<unsigned int>;
+  using RegionType      = typename ImageType::RegionType;
+  using SizeType        = typename RegionType::SizeType;
+  using IndexType       = typename RegionType::IndexType;
+  
+  using NeighborhoodType = itk::Neighborhood<double,2>;
+  using VectorPixelType  = typename VectorImageType::PixelType;
+
+  auto vimage = VectorImageType::New();
+  auto image  = ImageType::New();
+
+  SizeType size = {200,200};
+  
+  vimage->SetRegions(size);
+  image->SetRegions(size);
+
+  auto iterators = MakeIterators(image,vimage);
+
+  MoveIterators(iterators);
+
+  Funct4 f{};
+  
+  auto res = CallOperator(f,iterators);
+
+  // Test VariadicInputsImageFilter
+
+  auto filter = otb::VariadicInputsImageFilter<VectorImageType,VectorImageType,ImageType>::New();
+
+  filter->SetVInput<0>(vimage);
+  filter->SetVInput<1>(image);
+
+  filter->SetVInputs(vimage,image);
+
+  std::cout<<filter->GetVInput<0>()<< filter->GetVInput<1>()<<std::endl;
+
+  
+  // test FunctorImageFilter
   auto filter1 = otb::FunctorImageFilter<Funct1>::New(Funct1{});
   auto filter2 = otb::FunctorImageFilter<Funct2>::New(Funct2{});
   auto filter3 = otb::FunctorImageFilter<Funct3>::New(Funct3{});
-- 
GitLab