## Add Functor module with FunctorImageFilter

#### Summary

This MR introduces a new `Functor`

module, which contains the `FunctorImageFilter`

.

It is the same as MR !268 (closed) with squashed commit and a better documentation.

For examples of use, please refer to the test of the class.

##### Accepted types in functor arguments and return type

Prototype for this filter is as follows : `FunctorImageFilter<TFunction,TNameMap = void>`

.

Where `TFunction`

can be any lambda, free function, or class member `operator()`

, with any number of arguments.

Let `R (T1 t1, T2 t2 ..., TN tn) (const)`

be `TFunction`

signature. `T1, T2, ...TN`

can be:

- A value, ref or const ref to the following,
- A scalar type (unsigned int, double),
- A std::complex
- An instance of
`itk::FixedArray`

,`itk::RGBPixel`

,`itk::RGBAPixel`

- A
`itk::VariableLengthVector`

- A
`itk::Neighborhood`

of any of the above

`R`

can be:

- A value, ref or const ref to the following,
- A scalar type (unsigned int, double),
- A std::complex
- An instance of
`itk::FixedArray`

,`itk::RGBPixel`

,`itk::RGBAPixel`

- A
`itk::VariableLengthVector`

Note that the following operator prototype is also supported: `void (R& return, T1 t1, T2 t2 ..., TN tn) (const)`

##### Setting the inputs

`FunctorImageFilter`

will automatically deduce the correct image type from return type and arguments of the function or `operator()`

, and will offer setters of the form `SetVariadicInput<N>(...)`

excepting the correct type for Nth input.
Note that one can also use the `SetVariadicInputs(in1, in2, in3 ...)`

variadic method to set all inputs at once.

#####
`VectorImage`

Correct allocation of ouptut when output image is If the `TFunction`

produces a `VariableLengthVector`

, then it should also provide a `OutputSize()`

method which will be called by `FunctorImageFilter`

to allocate the correct number of bands in output image.

Full prototype of `OutputSize()`

method is `constexpr size_t OutputSize(const std::array<size_t, N> inputsNbBands) const`

with N being the number of argument of the functor. `inputsNbBands`

will contain the number of bands for each input which can be used to derive the output number of bands. However, if the number of bands in input is not relevant to derive the number of output band, the following simpler signature can be used instead `constexpr size_t OutputSize(...) const`

.

If a lambda returning a `VariableLengthVector`

is used, one can not add the `OutputSize()`

method but the `NumberOfOutputBandsDecorator`

template class can be used to wrap the lambda and still use the filter.

Last, for the sake of backward compatibility, `SetInput1()`

, ..., `SetInput10()`

are also defined (if and only if the number of arguments in the functor is high enough).

##### Accessing the Functor

Functor can be retrieved with `GetFunctor()`

(returns a const reference) or `GetModifiableFunctor()`

(returns a non-const reference AND calls `Modified()`

on filter).

##### Naming inputs

In order to ease the use of the filter by users, it is possible to name input with tags instead of indices.

In that case `TNameMap`

is not void, but a `std::tuple`

of tags (i.e. empty classes):

```
struct tag1{};
struct tag2{};
```

If `TNameMap = std::tuple<tag1,tag2>`

then `FunctorImageFilter`

will also support settings input as follows : `SetVariadicNamedInput<tag1>(in)`

or `SetVariadicNamedInput(tag1{},in)`

... A good practice could be that this name mapping is provided by the functor itself.

##### Setting the Radius

If one of the arguments of the functor maps to `itk::Neighborhood`

the corresponding input will automatically be padded to the filter radius, which can be changed using `SetRadius()`

.

##### Easy creation of filters

The `FunctorImageFilter`

offers two free functions that make it very easy to create ready to use instances of the filter:

```
// Simple case
SimpleFunctor f1;
auto filter1 = NewFunctorFilter(f1);
filter1->SetVariadicInputs(in1,...,inN);
filter1->Update();
// Functor With Radius
FunctorWithRadius f2;
auto filter2 = NewFunctorFilter(f1 {{3,3}}); // passing the radius directly
filter2->SetVariadicInputs(in1,...,inN);
filter2->Update();
// Lambda returning a VariableLengthVector of 3 bands
auto lambdaWithVariableLengthVector = [](const double &){return itk::VariableLengthVector<double> res(3); return res;};
auto filter2 = NewFunctorFilter(lambdaWithVariableLengthVector,3); // passing the number of output bands directly
filter2->SetVariadicInputs(in1);
filter2->Update();
```

Of course one can also directly use `FunctorImageFilter`

typedef to create the filter through the classical `New()`

static method.

##### Using this for refactoring of existing functor based filters

- If functor outputs a
`VariableLengthVector`

:- change signature to
`void operator(TOut & out, ...) const`

(more efficient). - Implement the
`OutputSize()`

method if functor produces a`VariableLengthVector`

- change signature to
- If the functor is used in filter with custom setters (such as
`SetInputRed()`

,`SetInputMask()`

,`SetInputHH()`

...), create a set of corresponding tags somewhere (i.e.`struct red{};`

...) - Replace filter with template using:

```
template <typename TInputImage1, typename TInputImage2, typename TOuputImage>
using TheFunctorFilter = FunctorImageFilter< TheFunctor < typename TInputImage1::PixelType,
typename TInputImage2::PixelType,
typename TOutputImage::PixelType>,
std::tuple<tag1,tag2> >;
```

- Rewrite the tests and applications to replace (and add this to migration guide):
- calls to
`SetInputTag1()`

by`SetVariadicNamedInput<tag1>()`

- calls to
`SetAlpha()`

by`GetModifiableFunctor().SetAlpha()`

- calls to
- Remove/deprecate old code (the fun part)

#### Implementation Details

I tried to document the code as best as I could. If something is missing, please tell me I will fix it.

##### Tests

An extensive test suite has been added to cover all possible cases, with a lot of `static_assert`

. Most cases are also covered in the test with real functors.

#### Limitations

This will not work with:

- Functor with more than one
`operator()`

- Functor template
`operator()`

method - Something called polymorphic lambdas (not sure if this is even useful)

#### Copyright

The copyright owner is *CNES* and has signed the ORFEO ToolBox Contributor License Agreement.

Thanks to Jordi for helping starting this.

**Check before merging:**

- All discussions are resolved
- At least 2
👍 votes from core developers, no👎 vote. - The feature branch is (reasonably) up-to-date with the base branch
- Dashboard is green
- Copyright owner has signed the ORFEO ToolBox Contributor License Agreement