Commit e3585999 authored by Julien Michel's avatar Julien Michel

ENH: FunctorImageFilter starts to be fully implemented (WIP)

parent 6d10b558
......@@ -26,6 +26,7 @@
#include "otbImage.h"
#include "otbVectorImage.h"
#include "itkConstNeighborhoodIterator.h"
#include "itkImageScanlineIterator.h"
#include "itkImageRegionConstIterator.h"
#include "itkProcessObject.h"
#include <type_traits>
......@@ -37,16 +38,76 @@ namespace otb
namespace functor_filter_details
{
// Variadic SetRequestedRegion
template<class T> int SetInputRequestedRegion(const T * img, const itk::ImageRegion<2> & region, const itk::Size<2>& radius)
{
auto currentRegion = region;
currentRegion.PadByRadius(radius);
// The ugly cast in all ITK filters
T * nonConstImg = const_cast<T*>(img);
if(currentRegion.Crop(img->GetLargestPossibleRegion()))
{
nonConstImg->SetRequestedRegion(currentRegion);
return 0;
}
else
{
nonConstImg->SetRequestedRegion(currentRegion);
// build an exception
itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
std::ostringstream msg;
msg << "::SetInputRequestedRegion<>()";
e.SetLocation(msg.str());
e.SetDescription("Requested region is (at least partially) outside the largest possible region.");
e.SetDataObject(nonConstImg);
throw e;
}
return 0;
}
template <class Tuple, size_t...Is> auto SetInputRequestedRegionsImpl(Tuple & t, const itk::ImageRegion<2> & region, std::index_sequence<Is...>,const itk::Size<2> & radius)
{
return std::make_tuple(SetInputRequestedRegion(std::get<Is>(t),region,radius)...);
}
template <typename... T> auto SetInputRequestedRegions(std::tuple<T...> && t,const itk::ImageRegion<2> & region, const itk::Size<2> & radius)
{
return SetInputRequestedRegionsImpl(t,region,std::make_index_sequence<sizeof...(T)>{},radius);
}
// Variadic creation of iterator tuple
template <class T> auto MakeIterator(itk::SmartPointer<T> img)
template <class T> auto MakeIterator(const T * img, const itk::ImageRegion<2> & region)
{
itk::ImageRegionConstIterator<T> it(img,region);
return it;
}
template <class T> auto MakeIterator(itk::SmartPointer<T> img, const itk::ImageRegion<2> & region)
{
itk::ImageRegionConstIterator<T> it(img,region);
return it;
}
template <class T> auto MakeIterator(itk::SmartPointer<const T> img, const itk::ImageRegion<2> & region)
{
itk::ImageRegionConstIterator<T> it(img,img->GetLargestPossibleRegion());
itk::ImageRegionConstIterator<T> it(img,region);
return it;
}
template<class... T> auto MakeIterators(itk::SmartPointer<T>... args)
template <class Tuple, size_t...Is> auto MakeIteratorsImpl(const Tuple& t, const itk::ImageRegion<2> & region, std::index_sequence<Is...>)
{
return std::make_tuple(MakeIterator(std::get<Is>(t),region)...);
}
template<typename... T> auto MakeIterators(std::tuple<T...> &&t, const itk::ImageRegion<2> & region)
{
return std::make_tuple(MakeIterator(args)...);
return MakeIteratorsImpl(t,region,std::make_index_sequence<sizeof...(T)>{});
}
// Variadic call of operator from iterator tuple
......@@ -73,14 +134,6 @@ template<typename ... Args> void MoveIterators(std::tuple<Args...> & t)
} // end namespace functor_filter_details
template<typename T>
using FTraits = typename FunctionTraits::function_traits<T>;
template<typename T>
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
{
......@@ -142,6 +195,24 @@ template <typename C, typename R, typename... T> struct FunctorFilterSuperclassH
using FilterType = VariadicInputsImageFilter<OutputImageType,typename TInputImage<T>::ImageType...>;
};
// Default implementation does nothing
template <class F, class O, class cond = void> struct NumberOfOutputComponents
{
// We can not be here if output type is VectorImage
//static_assert(std::is_same<O, otb::VectorImage<typename O::InternalPixelType> >::value,"Return type of Functor is a VariableLenghtVector, add a constexpr size_t OutputSize member");
static void Set(const F&, O *){}
};
// Case 1: O is a VectorImage AND F has a fixed OuptutSize unsigned
// int constexpr
template <class F, class T> struct NumberOfOutputComponents<F,T,typename std::enable_if<std::is_same<size_t, decltype(F::OutputSize)>::value>::type >
{
static void Set(const F &, otb::VectorImage<T> * outputImage)
{
std::cout<<"Use OutputSize to set number of output components"<<std::endl;
outputImage->SetNumberOfComponentsPerPixel(F::OutputSize);
}
};
/** \class FunctorImageFilter
* \brief Implements
......@@ -163,17 +234,6 @@ public:
using Pointer = itk::SmartPointer<Self>;
using ConstPointer = itk::SmartPointer<const Self>;
// 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;
......@@ -246,7 +306,8 @@ protected:
*/
virtual void GenerateInputRequestedRegion(void) override;
virtual void GenerateOutputInformation() override;
FunctorType m_Functor;
};
......
......@@ -50,6 +50,20 @@ FunctorImageFilter<TFunction>
{
// call the superclass' implementation of this method
Superclass::GenerateInputRequestedRegion();
// Get requested region for output
typename Superclass::OutputImagePointer outputPtr = this->GetOutput();
auto requestedRegion = outputPtr->GetRequestedRegion();
// Propagate to each variadic inputs, including possible radius
functor_filter_details::SetInputRequestedRegions(this->GetVInputs(),requestedRegion, {{0,0}});
}
template <class TFunction>
void
FunctorImageFilter<TFunction>::GenerateOutputInformation()
{
NumberOfOutputComponents<TFunction,OutputImageType>::Set(m_Functor,this->GetOutput());
}
/**
......@@ -60,8 +74,23 @@ void
FunctorImageFilter<TFunction>
::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId)
{
(void) outputRegionForThread;
(void) threadId;
itk::ImageScanlineIterator<OutputImageType> outIt(this->GetOutput(),outputRegionForThread);
itk::ProgressReporter p(this,threadId,outputRegionForThread.GetNumberOfPixels());
auto inputIterators = functor_filter_details::MakeIterators(this->GetVInputs(),outputRegionForThread);
while(!outIt.IsAtEnd())
{
for(;!outIt.IsAtEndOfLine();++outIt,functor_filter_details::MoveIterators(inputIterators))
{
outIt.Set(functor_filter_details::CallOperator(m_Functor,inputIterators));
// Update progress
p.CompletedPixel();
}
outIt.NextLine();
}
}
} // end namespace otb
......
......@@ -52,6 +52,11 @@ public:
SetInputsImpl(inTuple,std::make_index_sequence<sizeof...(inputs)>{});
}
auto GetVInputs()
{
return GetInputsImpl(std::make_index_sequence<sizeof...(TInputs)>{});
}
protected:
VariadicInputsImageFilter()
{
......@@ -65,6 +70,11 @@ private:
{
return std::initializer_list<int>{(this->SetVInput<Is>(std::get<Is>(t)),0)...};
}
template <size_t...Is> auto GetInputsImpl(std::index_sequence<Is...>)
{
return std::make_tuple(this->GetVInput<Is>()...);
}
VariadicInputsImageFilter(const Self&) = delete;
void operator=(const Self&) = delete;
......
......@@ -32,7 +32,7 @@
struct Funct1
{
double operator()(double p)
double operator()(double p) const
{
return p;
}
......@@ -42,16 +42,18 @@ struct Funct2
{
itk::VariableLengthVector<double> operator()(double p) const
{
itk::VariableLengthVector<double> result(2);
itk::VariableLengthVector<double> result(OutputSize);
result[0] = result[1] = p;
return result;
}
static constexpr size_t OutputSize = 2;
};
using IntImageNeighborhood = itk::Neighborhood<int>;
struct Funct3
{
double operator()(const IntImageNeighborhood & p)
double operator()(const IntImageNeighborhood & p) const
{
return static_cast<double>(p.GetCenterValue());
}
......@@ -67,7 +69,7 @@ struct Funct4
itk::VariableLengthVector<double> operator()(double p, const itk::VariableLengthVector<double> & vp) const
{
itk::VariableLengthVector<double> result(2);
result[0] = result[1] = p;
result.Fill(p);
return result;
}
};
......@@ -87,7 +89,7 @@ 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 ImageType = Image<double>;
using RegionType = typename ImageType::RegionType;
using SizeType = typename RegionType::SizeType;
using IndexType = typename RegionType::IndexType;
......@@ -98,12 +100,20 @@ int otbFunctorImageFilter(int itkNotUsed(argc), char * itkNotUsed(argv) [])
auto vimage = VectorImageType::New();
auto image = ImageType::New();
SizeType size = {200,200};
SizeType size = {{200,200}};
vimage->SetRegions(size);
vimage->SetNumberOfComponentsPerPixel(2);
vimage->Allocate();
itk::VariableLengthVector<double> v(2);
v.Fill(0);
vimage->FillBuffer(v);
image->SetRegions(size);
image->Allocate();
image->FillBuffer(0);
auto iterators = MakeIterators(image,vimage);
auto iterators = MakeIterators(std::make_tuple(image,vimage),image->GetBufferedRegion());
MoveIterators(iterators);
......@@ -126,8 +136,23 @@ int otbFunctorImageFilter(int itkNotUsed(argc), char * itkNotUsed(argv) [])
// test FunctorImageFilter
auto filter1 = otb::FunctorImageFilter<Funct1>::New(Funct1{});
auto filter2 = otb::FunctorImageFilter<Funct2>::New(Funct2{});
auto filter3 = otb::FunctorImageFilter<Funct3>::New(Funct3{});
auto filter4 = otb::FunctorImageFilter<decltype(Lambda1)>::New(Lambda1);
//auto filter3 = otb::FunctorImageFilter<Funct3>::New(Funct3{});
auto filter4 = otb::FunctorImageFilter<Funct4>::New(Funct4{});
auto filterLambda = otb::FunctorImageFilter<decltype(Lambda1)>::New(Lambda1);
filter1->SetVInputs(image);
filter1->Update();
filter2->SetVInputs(image);
filter2->Update();
filter4->SetVInputs(image,vimage);
filter4->Update();
filterLambda->SetVInputs(image);
filterLambda->Update();
return EXIT_SUCCESS;
}
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