Commit f5f6bcf0 authored by Julien Michel's avatar Julien Michel

COMP: Code review (and adding a few examples with std::complex)

parent 82b8d997
......@@ -32,20 +32,16 @@ namespace otb
/**
* \struct IsNeighborhood
* Struct testing if T is a neighborhood
* \brief Struct testing if T is a neighborhood
*
* Provides:
* - ValueType type set to false_type or true_type
* - value set to true or false
* - PixelType type to the underlying pixel type
*/
template <class T, class Enable = void> struct IsNeighborhood{};
/// Partial specialisation for scalar types
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>
template <class T> struct IsNeighborhood
{
using ValueType = std::false_type;
static constexpr bool value = false;
using PixelType = T;
};
/// Partial specialisation for itk::Neighborhood<T>
......@@ -53,37 +49,73 @@ template <class T> struct IsNeighborhood<itk::Neighborhood<T>>
{
using ValueType = std::true_type;
static constexpr bool value = true;
using PixelType = T;
};
/// Partial specialisation for const itk::Neighborhood<T> &
template <class T> struct IsNeighborhood<const itk::Neighborhood<T>&>
{
using ValueType = std::true_type;
static constexpr bool value = true;
};
/**
* \struct PixelTypeDeduction
* \brief Helper struct to derive PixelType from template parameter.
*
* T -> PixelType = T
* itk::Neighborhood<T> -> PixelTyoe = T
* const itk::Neighborhood<T>& -> PixelTyoe = T
*/
template <class T> struct PixelTypeDeduction
{
using PixelType = T;
};
/// Partial specialisation for itk::Neighborhood<T>
template <class T> struct PixelTypeDeduction<itk::Neighborhood<T>>
{
using PixelType = T;
};
/// Partial specialisation for const itk::Neighborhood<T> &
template <class T> struct PixelTypeDeduction<const itk::Neighborhood<T>&>
{
using PixelType = T;
};
/**
* \struct ImageTypeDeduction
* \brief Helper struct to derive ImageType from template parameter
*
* T -> ImageType = otb::Image<T>
* itk::VariableLengthVector<T> -> ImageType = otb::VectorImage<T>
* const T & -> ImageType = ImageTypeDeduction<T>::ImageType
*/
template <class T> struct ImageTypeDeduction
{
using ImageType = otb::Image<T>;
};
/// Partial specialisation for itk::VariableLengthVector<T>
template <class T> struct IsNeighborhood<itk::VariableLengthVector<T>>
template <class T> struct ImageTypeDeduction<itk::VariableLengthVector<T>>
{
using ValueType = std::false_type;
static constexpr bool value = false;
using PixelType = itk::VariableLengthVector<T>;
using ImageType = otb::VectorImage<T>;
};
/// Partial specialisation for const itk::VariableLengthVector<T> &
template <class T> struct IsNeighborhood<const itk::VariableLengthVector<T>&>
/// Partial specialisation for const T &
template <class T> struct ImageTypeDeduction<const T &>
{
using ValueType = std::false_type;
static constexpr bool value = false;
using PixelType = itk::VariableLengthVector<T>;
using ImageType = typename ImageTypeDeduction<T>::ImageType;
};
/**
* \struct InputImageTraits
* Struct allowing to derive input image types from operator()
* arguments
* \brief Struct allowing to derive input image types from operator()
* arguments
*
* Defines:
* - PixelType type to the underlying pixel type
* - ScalarType type to the underlying scalar type
......@@ -96,16 +128,14 @@ template<typename T>
struct InputImageTraits
{
using ArgumentType = T;
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;
using PixelType = typename PixelTypeDeduction<T>::PixelType;
using ImageType = typename ImageTypeDeduction<PixelType>::ImageType;
};
/**
* \struct OutputImageTraits
* Struct allowing to derive output image type from operator()
* \brief Struct allowing to derive output image type from operator()
*
* Defines:
* - ScalarType type to the underlying scalar type
* - ImageType type to the mocked up image type
......@@ -116,17 +146,15 @@ template<typename T>
struct OutputImageTraits
{
using ResultType = 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;
using ImageType = typename ImageTypeDeduction<T>::ImageType;
};
/**
* \struct FunctorFilterSuperclassHelper
* Struct allowing to derive the superclass prototype for the
* FunctorImageFilter class
* \brief Struct allowing to derive the superclass prototype for the
* FunctorImageFilter class
*
* Provides the following:
* - OutputImageType : type of the output image
* - FilterType : correct instanciation of VariadicInputsImageFilter from
......@@ -161,7 +189,7 @@ template <typename C, typename R, typename... T> struct FunctorFilterSuperclassH
};
/**
* This helper method builds a fully functional FunctorImageFilter from a functor instance
* brief This helper method builds a fully functional FunctorImageFilter from a functor instance
*
* Functor can be any operator() that matches the following:
* - Accepts any number of arguments of T,
......@@ -216,11 +244,11 @@ public:
using InputHasNeighborhood = typename FunctorFilterSuperclassHelper<TFunction>::InputHasNeighborhood;
/** Run-time type information (and related methods). */
/** Run-time type information (and related methods). */
itkTypeMacro(FunctorImageFilter, ImageToImageFilter);
/** Get the functor object. The functor is returned by reference.
/** Get the functor object. The functor is returned by reference.
* (Functors do not have to derive from itk::LightObject, so they do
* not necessarily have a reference count. So we cannot return a
* SmartPointer.) */
......@@ -230,7 +258,7 @@ public:
return m_Functor;
}
/** Get the functor object. The functor is returned by reference.
/** Get the functor object. The functor is returned by reference.
* (Functors do not have to derive from itk::LightObject, so they do
* not necessarily have a reference count. So we cannot return a
* SmartPointer.) */
......@@ -249,18 +277,18 @@ private:
void operator =(const Self&) = delete;
~FunctorImageFilter() = default;
/** Overload of ThreadedGenerateData */
virtual void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId) override;
/** Overload of ThreadedGenerateData */
void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId) override;
/**
* Pad the input requested region by radius
*/
virtual void GenerateInputRequestedRegion(void) override;
void GenerateInputRequestedRegion(void) override;
/**
* Will use the OutputSize() method if
*/
virtual void GenerateOutputInformation() override;
void GenerateOutputInformation() override;
// The functor member
......@@ -276,6 +304,7 @@ template <typename Functor> auto NewFunctorFilter(const Functor& f, itk::Size<2>
using PointerType = typename FilterType::Pointer;
PointerType p = new FilterType(f,radius);
p->UnRegister();
return p;
}
......@@ -283,7 +312,7 @@ template <typename Functor> auto NewFunctorFilter(const Functor& f, itk::Size<2>
template <typename F> struct NumberOfOutputBandsDecorator : F
{
public:
NumberOfOutputBandsDecorator(const F t, unsigned int nbComp) : F(t), m_NumberOfOutputComponents(nbComp) {}
constexpr NumberOfOutputBandsDecorator(const F t, unsigned int nbComp) : F(t), m_NumberOfOutputComponents(nbComp) {}
using F::operator();
constexpr size_t OutputSize(...) const
......
......@@ -36,6 +36,8 @@ namespace functor_filter_details
// This function sets the requested region for one image
template<class T> int SetInputRequestedRegion(const T * img, const itk::ImageRegion<2> & region, const itk::Size<2>& radius)
{
assert(img&&"Input image is a nullptr");
auto currentRegion = region;
currentRegion.PadByRadius(radius);
......@@ -53,15 +55,11 @@ template<class T> int SetInputRequestedRegion(const T * img, const itk::ImageReg
// build an exception
itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
std::ostringstream msg;
msg << "::SetInputRequestedRegion<>()";
e.SetLocation(msg.str());
e.SetLocation("::SetInputRequestedRegion<>()");
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)
......@@ -121,7 +119,7 @@ template <typename T> struct GetProxy{};
template <typename T> struct GetProxy<itk::ImageRegionConstIterator<T> >
{
static auto Get(const itk::ImageRegionConstIterator<T> & t)
static decltype(auto) Get(const itk::ImageRegionConstIterator<T> & t)
{
return t.Get();
}
......@@ -129,7 +127,7 @@ template <typename T> struct GetProxy<itk::ImageRegionConstIterator<T> >
template <typename T> struct GetProxy<itk::ConstNeighborhoodIterator<T> >
{
static auto Get(const itk::ConstNeighborhoodIterator<T> & t)
static decltype(auto) Get(const itk::ConstNeighborhoodIterator<T> & t)
{
return t.GetNeighborhood();
}
......@@ -183,9 +181,6 @@ void
FunctorImageFilter<TFunction>
::GenerateInputRequestedRegion()
{
// call the superclass' implementation of this method
Superclass::GenerateInputRequestedRegion();
// Get requested region for output
typename Superclass::OutputImagePointer outputPtr = this->GetOutput();
auto requestedRegion = outputPtr->GetRequestedRegion();
......
......@@ -26,17 +26,18 @@
#include <tuple>
#include <numeric>
#include <complex>
// Example functors
// N scalar images -> image
// This functor takes N scalar image (variadic N) and returns the sum
// of all pixels
template <typename O, typename ...T> struct VariadicAdd
template <typename TOut, typename ...TIns> struct VariadicAdd
{
auto operator()(T... ins) const
auto operator()(TIns... ins) const
{
std::vector<O> outVector{static_cast<O>(ins)...};
std::vector<TOut> outVector{static_cast<TOut>(ins)...};
return std::accumulate(outVector.begin(), outVector.end(),0);
}
......@@ -81,18 +82,18 @@ template <typename v1, typename v2, typename ...vn> void concatenateVectors(v1 &
// N images (all types) -> vector image
// This functor concatenates N images (N = variadic) of type
// VectorImage and or Image, into a single VectorImage
template<typename O, typename ...T> struct VariadicConcatenate
template<typename TOut, typename ...TIns> struct VariadicConcatenate
{
auto operator()(const T &... ins) const
auto operator()(const TIns &... ins) const
{
itk::VariableLengthVector<O> out;
itk::VariableLengthVector<TOut> out;
concatenateVectors(out, toVector(ins)...);
return out;
}
// Must define OutputSize because output pixel is vector
constexpr size_t OutputSize(const std::array<size_t, sizeof...(T)> inputsNbBands) const
constexpr size_t OutputSize(const std::array<size_t, sizeof...(TIns)> inputsNbBands) const
{
return std::accumulate(inputsNbBands.begin(),inputsNbBands.end(),0);
}
......@@ -102,20 +103,20 @@ template<typename O, typename ...T> struct VariadicConcatenate
// 1 VectorImage -> 1 VectorImage with a different size depending on a
// parameter of the functor
// This Functor
template<typename O, typename T> struct BandExtraction
template<typename TOut, typename TIn> struct BandExtraction
{
BandExtraction(unsigned int indices...) : m_Indices({indices})
{}
// TODO define a constructor to initialize m_Indices
auto operator()(const itk::VariableLengthVector<T> & in) const
auto operator()(const itk::VariableLengthVector<TIn> & in) const
{
itk::VariableLengthVector<O> out(m_Indices.size());
itk::VariableLengthVector<TOut> out(m_Indices.size());
size_t idx = 0;
for(auto v: m_Indices)
{
out[idx] = static_cast<O>(in[v]);
out[idx] = static_cast<TOut>(in[v]);
++idx;
}
......@@ -177,6 +178,27 @@ template<typename T> struct MaxInEachChannel
};
template<typename T> struct VectorModulus
{
itk::VariableLengthVector<double> operator()(const itk::VariableLengthVector<std::complex<T>> & in) const
{
itk::VariableLengthVector<double> out(in.Size());
for(auto band = 0u; band < out.Size(); ++band)
{
out[band] = std::abs(in[band]);
}
return out;
}
size_t OutputSize(const std::array<size_t,1> & nbBands) const
{
return nbBands[0];
}
};
// Tests of IsNeighborhood struct
using OImage = typename otb::Image<int>;
using Neig = typename itk::Neighborhood<int>;
......@@ -193,11 +215,15 @@ int otbFunctorImageFilter(int itkNotUsed(argc), char * itkNotUsed(argv) [])
// test functions in functor_filter_details namespace
using VectorImageType = VectorImage<double>;
using ImageType = Image<double>;
using ComplexVectorImageType = VectorImage<std::complex<double>>;
using ComplexImageType = Image<std::complex<double>>;
using RegionType = typename ImageType::RegionType;
using SizeType = typename RegionType::SizeType;
auto vimage = VectorImageType::New();
auto image = ImageType::New();
auto cvimage = ComplexVectorImageType::New();
auto cimage = ComplexImageType::New();
SizeType size = {{200,200}};
......@@ -207,11 +233,22 @@ int otbFunctorImageFilter(int itkNotUsed(argc), char * itkNotUsed(argv) [])
itk::VariableLengthVector<double> v(2);
v.Fill(0);
vimage->FillBuffer(v);
cvimage->SetRegions(size);
cvimage->SetNumberOfComponentsPerPixel(2);
cvimage->Allocate();
itk::VariableLengthVector<std::complex<double>> cv(2);
cv.Fill(0);
cvimage->FillBuffer(cv);
image->SetRegions(size);
image->Allocate();
image->FillBuffer(0);
cimage->SetRegions(size);
cimage->Allocate();
cimage->FillBuffer(0);
// Test VariadicInputsImageFilter
auto filter = otb::VariadicInputsImageFilter<VectorImageType,VectorImageType,ImageType>::New();
filter->SetVInput<0>(vimage);
......@@ -280,7 +317,18 @@ int otbFunctorImageFilter(int itkNotUsed(argc), char * itkNotUsed(argv) [])
auto maxInEachChannel = NewFunctorFilter(MaxInEachChannelType{},{{3,3}});
maxInEachChannel->SetVInputs(vimage);
maxInEachChannel->Update();
// Test FunctorImageFilter with Module (complex=
using ModulusType = VectorModulus<double>;
auto modulus = NewFunctorFilter(ModulusType{});
modulus->SetVInputs(cvimage);
modulus->Update();
auto LambdaComplex = [] (const std::complex<double> & in) {return std::arg(in);};
auto argFilter = NewFunctorFilter(LambdaComplex);
argFilter->SetVInputs(cimage);
argFilter->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