diff --git a/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.h b/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.h index a4f366445546e79565d5fe05b9e44df18385cb3e..6c06c2b347ba955df00afd5b1b54eab50f24db0f 100644 --- a/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.h +++ b/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.h @@ -91,26 +91,60 @@ template <typename ...T> auto GetNumberOfComponentsPerInput(std::tuple<T...> & t return GetNumberOfComponentsPerInputImpl(t, std::make_index_sequence<sizeof...(T)>{}); } -template <class T> auto MakeIterator(const T * img, const itk::ImageRegion<2> & region) +template <typename N> struct MakeIterator {}; + +template <> struct MakeIterator<std::false_type> { - itk::ImageRegionConstIterator<T> it(img,region); - return it; -} + template <class T> static auto Make(const T * img, const itk::ImageRegion<2> & region, const itk::Size<2>&) + { + itk::ImageRegionConstIterator<T> it(img,region); + return it; + } +}; + +template <> struct MakeIterator<std::true_type> +{ + template <class T> static auto Make(const T * img, const itk::ImageRegion<2> & region, const itk::Size<2>& radius) + { + itk::ConstNeighborhoodIterator<T> it(radius,img,region); + return it; + } +}; + -template <class Tuple, size_t...Is> auto MakeIteratorsImpl(const Tuple& t, const itk::ImageRegion<2> & region, std::index_sequence<Is...>) +template <class TNeigh, class Tuple, size_t...Is> auto MakeIteratorsImpl(const Tuple& t, const itk::ImageRegion<2> & region, const itk::Size<2> & radius, std::index_sequence<Is...>, TNeigh) { - return std::make_tuple(MakeIterator(std::get<Is>(t),region)...); + return std::make_tuple(MakeIterator<typename std::tuple_element<Is,TNeigh>::type >::Make(std::get<Is>(t),region,radius)...); } -template<typename... T> auto MakeIterators(std::tuple<T...> &&t, const itk::ImageRegion<2> & region) +template<class TNeigh, typename... T> auto MakeIterators(std::tuple<T...> &&t,const itk::ImageRegion<2> & region, const itk::Size<2> & radius, TNeigh n) { - return MakeIteratorsImpl(t,region,std::make_index_sequence<sizeof...(T)>{}); + return MakeIteratorsImpl(t,region,radius,std::make_index_sequence<sizeof...(T)>{},n); } // Variadic call of operator from iterator tuple +template <typename T> struct GetProxy{}; + + +template <typename T> struct GetProxy<itk::ImageRegionConstIterator<T> > +{ + static auto Get(const itk::ImageRegionConstIterator<T> & t) +{ + return t.Get(); +} +}; + +template <typename T> struct GetProxy<itk::ConstNeighborhoodIterator<T> > +{ + static auto Get(const itk::ConstNeighborhoodIterator<T> & t) +{ + return t.GetNeighborhood(); +} +}; + 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()...); + return oper(GetProxy<typename std::remove_reference<decltype(std::get<Is>(t))>::type>::Get(std::get<Is>(t))...); } template <class Oper, typename ... Args> auto CallOperator(const Oper& oper, std::tuple<Args...> & t) @@ -153,25 +187,52 @@ template <class F, class T, size_t N> struct NumberOfOutputComponents<F,otb::Vec } // end namespace functor_filter_details -template <class T> struct IsNeighborhood +template <class T, class Enable = void> struct IsNeighborhood{}; + +template <class T> struct IsNeighborhood<T,typename std::enable_if<std::is_scalar<typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value >::type> { using ValueType = std::false_type; static constexpr bool value = false; using PixelType = T; }; - template <class T> struct IsNeighborhood<itk::Neighborhood<T>> +template <class T> struct IsNeighborhood<itk::Neighborhood<T>> +{ + using ValueType = std::true_type; + static constexpr bool value = true; + using PixelType = T; +}; + +template <class T> struct IsNeighborhood<const itk::Neighborhood<T>&> { using ValueType = std::true_type; static constexpr bool value = true; using PixelType = T; }; +template <class T> struct IsNeighborhood<itk::VariableLengthVector<T>> +{ + using ValueType = std::false_type; + static constexpr bool value = false; + using PixelType = itk::VariableLengthVector<T>; +}; + + +template <class T> struct IsNeighborhood<const itk::VariableLengthVector<T>&> +{ + using ValueType = std::false_type; + static constexpr bool value = false; + using PixelType = itk::VariableLengthVector<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 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 >, @@ -198,19 +259,21 @@ template <typename R, typename... T> struct FunctorFilterSuperclassHelper<R(*)(T { using OutputImageType = typename TOutputImage<R>::ImageType; using FilterType = VariadicInputsImageFilter<OutputImageType,typename TInputImage<T>::ImageType...>; - + using InputHasNeighborhood = std::tuple<typename IsNeighborhood<T>::ValueType...>; }; template <typename C, typename R, typename... T> struct FunctorFilterSuperclassHelper<R(C::*)(T...) const> { using OutputImageType = typename TOutputImage<R>::ImageType; using FilterType = VariadicInputsImageFilter<OutputImageType,typename TInputImage<T>::ImageType...>; + using InputHasNeighborhood = std::tuple<typename IsNeighborhood<T>::ValueType...>; }; 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...>; + using InputHasNeighborhood = std::tuple<typename IsNeighborhood<T>::ValueType...>; }; // template <class F> class NumberOfOutputDecorator @@ -258,6 +321,8 @@ public: using ProcessObjectType = itk::ProcessObject; + using InputHasNeighborhood = typename FunctorFilterSuperclassHelper<TFunction>::InputHasNeighborhood; + /** Method for creation by passing the filter type. */ static Pointer New(const TFunction& f, itk::Size<2> radius = {{0,0}}); diff --git a/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.hxx b/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.hxx index 7ac39b47d1c3aed0b29d2aa1d2fda24215485cc3..b163697616a893e96d99a4b8c344b1e4b5b1f79f 100644 --- a/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.hxx +++ b/Modules/Filtering/ImageManipulation/include/otbFunctorImageFilter.hxx @@ -53,7 +53,9 @@ FunctorImageFilter<TFunction> auto requestedRegion = outputPtr->GetRequestedRegion(); // Propagate to each variadic inputs, including possible radius - functor_filter_details::SetInputRequestedRegions(this->GetVInputs(),requestedRegion, {{0,0}}); + // TODO: For now all inputs are padded with the radius, even if they + // are not neighborhood based + functor_filter_details::SetInputRequestedRegions(this->GetVInputs(),requestedRegion, m_Radius); } template <class TFunction> @@ -85,7 +87,7 @@ FunctorImageFilter<TFunction> itk::ImageScanlineIterator<OutputImageType> outIt(this->GetOutput(),outputRegionForThread); itk::ProgressReporter p(this,threadId,outputRegionForThread.GetNumberOfPixels()); - auto inputIterators = functor_filter_details::MakeIterators(this->GetVInputs(),outputRegionForThread); + auto inputIterators = functor_filter_details::MakeIterators(this->GetVInputs(),outputRegionForThread, m_Radius,InputHasNeighborhood{}); while(!outIt.IsAtEnd()) { diff --git a/Modules/Filtering/ImageManipulation/test/otbFunctorImageFilter.cxx b/Modules/Filtering/ImageManipulation/test/otbFunctorImageFilter.cxx index 60290096f52b408fbb68ce9cdfcbba854196fbda..6416d222368027dcb2e168eac77e8165775f3b4e 100644 --- a/Modules/Filtering/ImageManipulation/test/otbFunctorImageFilter.cxx +++ b/Modules/Filtering/ImageManipulation/test/otbFunctorImageFilter.cxx @@ -184,8 +184,8 @@ using OImage = typename otb::Image<int>; 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"); +static_assert(!otb::IsNeighborhood<itk::VariableLengthVector<double>>::value, "err"); using namespace otb::functor_filter_details; @@ -256,10 +256,10 @@ int otbFunctorImageFilter(int itkNotUsed(argc), char * itkNotUsed(argv) []) extract->Update(); // Test FunctorImageFilter With Mean functor - // using MeanFunctorType = Mean<double,double>; - // auto median = otb::FunctorImageFilter<MeanFunctorType>::New(MeanFunctorType{}); - // median->SetVInputs(image); - // median->Update(); + using MeanFunctorType = Mean<double,double>; + auto median = otb::FunctorImageFilter<MeanFunctorType>::New(MeanFunctorType{},{{2,2}}); + median->SetVInputs(image); + median->Update(); return EXIT_SUCCESS; }