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