FunctorImageFilter

在图像处理和遥感中,在一个或多个共同配准的图像之间编写基于像素或基于邻域的自定义操作是非常常见的。从OTB 7.0开始,现在有了一个独特的过滤器 otb::FunctorImageFilter 这将处理大多数情况:

  • 任意数量的输入图像,可以是 ImageVectorImage 或者两者兼而有之,
  • 一个 ImageVectorImage 输出
  • 基于像素、邻域或两者的混合进行操作,
  • 函数类、函数、lambdas。

使用 otb::FunctorImageFilter 您只需要编写想要执行的操作,筛选器将处理所有事情(包括多线程和流)。

快速入门

定义要执行的操作

要执行的操作可以定义为自由函数:

double myFreeFunction(const double& in) {...}

也可以将其定义为函数器(即定义 operator()

class MyFunctor
{
public:
    double operator()(const double& in) {...}
};

它也可以定义为lambda:

auto myLambda = [](const double& in) -> double {...}

创建一个 FunctorImageFilter

一旦实现了要执行的操作,就很容易获得 FunctorImageFilter 从中可以看到:

auto filterFromFreeFunction = NewFunctorFilter(myFreeFunction);
auto filterFromFunctor      = NewFunctorFilter(MyFunctor());
auto filterFromLambda       = NewFunctorFilter(myLambda);

您可以像使用任何其他过滤器一样使用它:

filterFromLambda->SetInput(upStreamFilter->GetOutput());
downstreamFilter->SetInput(filterFromLambda->GetOutput());

您还可以直接定义 FunctorImageFilter 使用内置的数学函数:

using CosType  = double(double);
auto filterCos = NewFunctorFilter(static_cast<CosType*>(std::cos));

请注意, static_cast 特技,它允许在不同的原型之间分离 cos 功能。

自动类型扣除

您可能注意到,与ITK和OTB中的其他过滤器相反,不需要指定输入和输出图像类型。这是因为 FunctorImageFilter 使用C++元编程从自由函数、函数器或lambda自动派生输入和输出图像类型,规则如下。

让我们 R (T1 t1, T2 t2 ..., TN tn) 是自由函数的签名, operator() 或者是Lambda。请注意,筛选器反过来支持按值传递 TN tn 或通过常量引用 const TN & tn

首先,让我们定义基本类型:

  • 标量类型(双精度、浮点型、无符号整型、短型...)
  • std::complex<T> 带T的标量类型
  • itk::FixedArray<T,N>itk::RGBPixel<T>itk::RGBAPixel<T> 带T的标量类型

自动输入型扣减

在基本类型中,适用以下扣减规则:

  • 如果 TN 是如上所述的基本类型,则第N个输入将为 otb::Image<TN>
  • 如果 TN 是一种 itk::VariableLengthVector<T> 如果T是如上所述定义的基本类型,则第N个输入将为 otb::VectorImage<T>
  • 如果 TN 是一种 const itk::ConstNeighborhoodIterator<otb::Image<T>> & 如果T是如上所述定义的基本类型,则第N个输入将为 otb::Image<TN>
  • 如果 TN 是一种 const itk::ConstNeighborhoodIterator<otb::VectorImage<T>> & 如果T是如上所述定义的基本类型,则第N个输入将为 otb::VectorImage<TN>

请注意,这将适用于任何数量的输入。

自动输出式扣除

输出类型演绎规则更简单:-IF R 是基本类型,则筛选器的输出将为 otb::Image<R> -如果 R 是一种 itk::VariableLengthVector<T> 如果T是如上所述的基本类型,则过滤器的输出将为 otb::VectorImage<R>

请注意,如果 R 是一种 itk::VariableLengthVector<T> ,您需要额外的步骤,以便过滤器可以分配正确数量的输出波段,如中所述 NumberOfOutputBands 一节。

性能的替代原型

自动类型推断也适用于以下签名: void (R&, T1 t1, T2 t2 ..., TN tn)

这将在以下情况下更有效率 R 是一种 itk::VariableLengthVector<T> 在这种情况下应该是首选的。

自动类型演绎示例

请考虑以下免费函数:

itk::VariableLengthVector<double> myFreeFunction(unsigned char a,
                                                 const std::complex<float>& b,
                                                 const itk::VariableLengthVector<short>& c,
                                                 const itk::ConstNeighborhoodIterator<otb::Image<double>>& d) {...}

当一个 FunctorImageFilter 是从该函数构建的,则将推导出以下类型:

  • 第一个输入(对应于a)的类型为 otb::Image<unsigned char>
  • 第二个输入(对应于b)的类型为 otb::Image<std::complex<float>>
  • 第三个输入(对应于c)的类型为 otb::VectorImage<short>
  • 第四个输入(对应于d)的类型为 otb::Image<double>
  • 输出类型将为 otb::VectorImage<double>

严格来说,这相当于:

void myFreeFunction(itk::VariableLengthVector<double> & out ,
                    unsigned char a,
                    const std::complex<float> & b,
                    const itk::VariableLengthVector<short> &c,
                    const itk::ConstNeighborhoodIterator<otb::Image<double>> & d) {...}

由于输出类型为 itk::VariableLengthVector<T> ,则应首选后者。

使用滤镜

设置输入

可使用模板设置第N个参数 SetInput() 方法:

myFilter->SetInput<N>(imageN);

您还可以使用 SetInputs() 方法:

myFilter->SetInputs(image0,...,imageN);

如果您只有一个输入,您可以简单地调用:

myFilter->SetInput(image);

当然,输入类型必须与从运算符()、自由函数或lambda中推导出来的类型匹配!

访问该功能

如果 FunctorImageFilter 是从函数器类构建的,此类可能具有您希望更改或读取的参数。

你可以打电话给 GetFunctor() 要访问对函数的常量引用以读取参数值,请执行以下操作:

auto a = myFilter->GetFunctor().GetParameterA();

如果希望修改函数器的参数,则必须调用 GetModifiableFunctor() ,它将返回对函数器的非常数引用,并确保筛选器将在更新时重新运行。

设置邻域半径

如果你有 itk::ConstNeighborhoodIterator<otb::Image<T>>itk::ConstNeighborhoodIterator<otb::VectorImage<T>> 作为输入类型,您可以在构建滤镜实例时设置邻域半径,具体如下:

auto filterFromFunctor = NewFunctorFilter(MyFunctor,{{3,3}});

高级用途

输出波段数

如果是类型 itk::VariableLengthVector<T> ,那么函数器类应该提供一个 OutputSize() 方法如下所示。

如果输出波段数是固定的:

class MyFunctor {
public:
...
constexpr size_t OutputSize(...) const
{
  // Return the number of output bands
  return 3;
}
};

如果输出波段数取决于一个或多个输入图像中的波段数:

class MyFunctor {
public:
...
size_t OutputSize(const std::array<size_t,N> & nbBands) const
{
  // N Is the number of inputs
  // nbBands is an array containing the number of bands for each input
  ...
  return outputNumberOfBands;
}
};

在这种情况下,您可以使用 nbBands 参数,该参数包含每个输入的波段数,以派生并返回输出波段数。

如果您使用的是lambda、自由函数或不提供 OutputSize() 方法,您仍然可以使用 FunctorImageFilter 但您需要在构造滤镜实例时提供频段数:

// Specify that the lambda output has 3 bands
auto filterFromLambda       = NewFunctorFilter(myLambda,3);