Commit 6d10b558 authored by Julien Michel's avatar Julien Michel

ENH: FunctorImageFilter is now fully variadic from Functor definition

parent a6399f2c
......@@ -40,7 +40,6 @@ set(OTBImageBaseTests
otbImageTest.cxx
otbImageFunctionAdaptor.cxx
otbMetaImageFunction.cxx
otbFunctorImageFilter.cxx
)
add_executable(otbImageBaseTestDriver ${OTBImageBaseTests})
......
......@@ -41,5 +41,4 @@ void RegisterTests()
REGISTER_TEST(otbImageTest);
REGISTER_TEST(otbImageFunctionAdaptor);
REGISTER_TEST(otbMetaImageFunction);
REGISTER_TEST(otbFunctorImageFilter);
}
......@@ -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"
......
......@@ -18,94 +18,10 @@
* limitations under the License.
*/
//#include "otbFunctor.h"
//#include "otbFunctorImageFilter.h"
#ifndef otb_VariadicInputsImageFilter_h
#define otb_VariadicInputsImageFilter_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 ...)
{}
namespace otb {
template<class TOuptut, class ... TInputs> class VariadicInputsImageFilter : public itk::ImageSource<TOuptut>
{
......@@ -154,50 +70,6 @@ private:
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;
}
#endif
......@@ -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{});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment