用BandMath和BandMathX实现图像的运算

使用BandMath的简单微积分

这个 BandMath 应用程序提供了一种简单而高效的方式来执行逐个像素的操作。它根据用户定义的数学表达式计算逐带运算。下面的代码计算两个图像的前两个带之间的绝对差值。

otbcli_BandMath -il input_image_1 input_image_2
                -exp "abs(im1b1 - im2b1)"
                -out output_image

命名约定“im” [x] B类 [y] “指定第X个输入图像的第y个频段。

这个 BandMath 应用程序嵌入了中列出的内置运算符和函数 muparser documentation 从而允许有大量可能的操作选择。

使用BandMathX的高级图像操作

的一个限制是 BandMath 应用是它只能输出单波段图像,因为u-parser库只支持标量表达式。相反, BandMathX 应用程序基于 mu-parserX 库可以输出单波段和多波段图像,并支持包含标量、向量和矩阵的表达式。下面的代码计算两个图像之间的差异:

otbcli_BandMathX -il input_image_1 input_image_2
                -exp "im1 - im2"
                -out output_image

此应用程序生成的输出图像具有与输入图像相同的条带数,并且每个生成的条带包含输入图像中相应条带之间的差异。

语法:第一个元素

变量及其说明:

变数 类型 描述
IM1 矢量 来自第一个输入的像素,由n个分量/波段组成(第一个图像以1为索引)
Im1bj 标量 来自第一个输入的像素的第j个分量(第一个波段以1为索引)
Im1bjNkxp 矩阵 来自第一个输入的第j个分量的像素的邻域(“N”),大小为kxp
Im1bjMini 标量 全局统计:来自第一个输入的第j个频段的最小值
Im1bjMaxi 标量 全局统计:从第一个输入开始的第j个频段的最大值
Im1bjMean 标量 全局统计:来自第一个输入的第j个频段的平均值
Im1bjSum 标量 全局统计:从第一个输入开始的第j个频段的总和
Im1bjVar 标量 全局统计:从第一个输入开始的第j个频段的方差
Im1PhyX和im1PhyY 标量 第一个输入在X和Y方向上的间距

此外,我们还有表示当前像素(标量)索引的泛型变量idxX和idxY。

请注意,使用全局统计将自动使过滤器(或应用程序)从相关输入图像请求尽可能大的区域,而无需用户干预。

例如,下面的公式(两个像素相加)

IM1+IM2

仅当两个第一个输入具有相同的波段数时才正确。此外,即使IM1表示仅由一个带组成的图像的一个像素,下列公式也不一致:

IM1+1

标量不能与向量相加。相反,正确的公式是(人们可以注意到 muParserX 允许动态定义向量):

Im1+{1}

Im1+{1,1,1,...,1}

如果IM1由n个成分组成。

另一方面,变量im1b1被表示为标量;因此我们有以下不同的可能性:

正确/不正确的表达方式:

表达式 状态
Im1b1+1 对,是这样
{im1b1}+{1} 对,是这样
Im1b1+{1} 不正确
{im1b1}+1 不正确
Im1+{im2b1,im2b2} 如果im1表示两个分量的像素(等效于im1+im2),则更正

乘除也可以做类似的说明,例如下面的公式是不正确的:

\{im2b1,im2b2\} * \{1,2\}

而这一条是正确的:

\{im2b1,im2b2\} * \{1,2\}'

或者更简单地说(仅当IM2包含两个组件时):

Im2*{1,2}‘

关于除法,该运算最初不是在两个向量之间定义的(见下一节 新的运算符和函数 )。

现在,让我们回到第一个公式:这个公式指定在频段之间添加两个图像。使用 muParserX LIB,我们现在可以只用一个公式来定义这样的运算,而不是用很多公式(和带数一样多)。我们将这一新功能称为 batch mode ,它直接产生于在 muParserX 框架。

使用邻里关系的行动

让我们简单介绍一下邻域变量。这些变量是为每个特定输入和每个特定频段定义的。最后两个数字kxp表示该社区的大小。所有邻域都居中:这意味着k和p只能是奇数。此外,k表示x方向上的维度(列数),p表示y方向上的维度(行数)。例如,im1b3N3x5表示以下邻域:

例如,下面的代码使用输入图像的第一个带区,将每个像素周围3x3邻域中的平均值减去像素值:

otbcli_BandMathX -il input_image_1 input_image_2
                -exp "im1b1 - mean(im1b1N3x3)"
                -out output_image

从根本上说,邻域表示为 muParserX 框架;因此,关于数学上定义明确的公式的评论仍然有效。

涉及位操作的操作

有时,操作位而不是实数很有用。例如,有时将多个二进制掩码一起存储在单波段整数图像中。

为了操作位,需要将其数据转换为整数(因为数据是以浮点数的形式读取的)。要做到这一点, muParserX 具有类型转换运算符:(Int)。为您的图像添加前缀将允许您执行此类操作。

示例:
  • (int)im1b1 & 0b00000001 (按位AND)
  • (int)im1b1 >> 1 (右移运算符)

新的运算符和函数

除了中提供的运算符和函数外 muParserX 已在(https://beltoforion.de/article.php?a=muparserx),内部实施了新的OTB。这些问题可分为两类:

  • 对原来没有为向量和矩阵定义的现有运算符/函数的改编(例如cos、sin等)。这些新的运算符/函数保留了原来的名称,我们在其中添加了向量(vcos、vsin等)的前缀“v”。
  • 真正的新运算符/函数。

关于最后一个类别,下面是已实现的运算符或函数的列表(它们都在otbParserXPlugins.h/.cxx文件中实现 OTB/Modules/Filtering/MathParserX ):

Operators div and dv: 第一个运算符允许定义两个向量(甚至矩阵)的按元素除法,前提是它们具有相同的维度。第二种方法允许定义向量/矩阵除以标量(分量除以相同的唯一值)。例如:

Im1~div~im2

Operators mult and mlt: 这些运算符是前几个运算符的对偶。例如:

IM1~MULT~IM2

Operators pow and pw: 第一个运算符允许定义两个向量(甚至是矩阵)的按元素求幂,前提是它们具有相同的维度。第二种方法允许定义向量/矩阵除以标量(分量以相同的唯一值为指数)。例如:

IM1~电源~IM2

IM1~PW~2.0

请注意,可以使用运算符‘*’而不是‘pw’。但是‘pw’稍微宽容一些,它可以将一维向量作为正确的操作数。

Function bands: 此功能允许从图像中选择特定的波段,和/或以新的矢量重新排列它们;例如:

频段(IM1,{1,2,1,1})

从第一个输入中生成由带1、带2、带1和带1值组成的4个分量的向量。请注意,必须使用花括号才能选择所需的波段索引。

Function dotpr: 此函数允许两个向量或矩阵(实际上在我们的例子中是一个核和一个像素邻域)之间的点积:

sum_{(i,j)}m_1(i,j)*m_2(i,j)

例如:

Dotpr(内核1,im1b1N3x5)

如果kernel1和im1b1N3x5具有相同的维度,则是正确的。

Function mean: 此函数允许计算给定向量或邻域的平均值(该函数可以接受所需的任意多个输入;每个输入计算一个平均值)。例如:

平均值(im1b1N3x3、im1b2N3x3、im1b3N3x3、im1b4N3x3)

注意:来自muparserX本身的限制使得使用唯一变量传递所有这些邻居是不可能的。

Function var: 该函数计算给定向量或邻域的方差(该函数可以接受所需的任意多个输入;每个输入计算一个变量值)。例如:

Var(Im1b1N3x3)

Function median: 此函数计算给定矢量或邻域的中值(该函数可以接受所需的任意多个输入;每个输入计算一个中值)。例如:

中位数(Im1b1N3x3)

Function corr: 此函数计算相同维度的两个向量或矩阵之间的相关性(此函数接受两个输入)。例如:

Corr(im1b1N3x3,im1b2N3x3)

Function maj: 此函数计算向量或矩阵中表示最多的元素(该函数可以接受所需的任意多个输入;每个输入计算一个主要元素值)。例如:

Maj(im1b1N3x3,im1b2N3x3)

Function vmin and vmax: 这些函数计算给定向量或邻域的最小或最大值(只有一个输入,输出是一个1x1矩阵)。例如:

(vmax(Im3b1N3x5)+vmin(Im3b1N3x5))~div~{2.0}

Function cat: 该函数将多个表达式的结果连接到一个多维向量中,而不管它们各自的维度(该函数可以接受所需的任意多个输入)。例如:

CAT(im3b1、vmin(Im3b1N3x5)、中位数(Im3b1N3x5)、Vmax(Im3b1N3x5))

注意:在设置表达式时,用户应优先使用分号(;),而不是直接使用此功能。过滤器或应用程序将自动调用函数‘cat’。例如:

Im3b1;vmin(Im3b1N3x5);中位数(Im3b1N3x5);vmax(Im3b1N3x5)

Function ndvi: 该函数实现了经典的归一化差异植被指数;它接受两个输入。例如:

NDVI(im1b1、im1b4)

第一个参数与可见的红色波段有关,第二个参数与近红外波段有关。

下表总结了不同的函数和运算符。

函数和运算符摘要:

变数 备注
NDVI 两个输入
谱带 两个输入;第二个矢量输入的长度给出输出的尺寸
点对点树 多个输入
多个输入
小气 多个输入
变量 多个输入
中位数 多个输入
麦吉 多个输入
柯尔 两个输入
Div和dv 操作员
MULT和MLT 操作员
战俘和战俘 操作员
VNorm 使现有函数适应向量:一个输入
真空吸尘器 使现有函数适应向量:一个输入
Vmin 使现有函数适应向量:一个输入
VMAX 使现有函数适应向量:一个输入
VCoS 使现有函数适应向量:一个输入
VSIN 使现有函数适应向量:一个输入
VTAN 使现有函数适应向量:一个输入
Vtanh 使现有函数适应向量:一个输入
Vsinh 使现有函数适应向量:一个输入
VCOSH 使现有函数适应向量:一个输入
vlog 使现有函数适应向量:一个输入
Vlog10 使现有函数适应向量:一个输入
凸起 使现有函数适应向量:一个输入
VSQRT 使现有函数适应向量:一个输入
向量2比例 一维向量到标量

上下文和常量

多亏了 -incontext 可以将常量值传递给应用程序,以便在表达式中使用它。对于常量的定义,必须遵循以下模式:#type name value。例如:

#F expo 1.1 #M kernel1 { 0.1 , 0.2 , 0.3 ; 0.4 , 0.5 , 0.6 ; 0.7 , 0.8 , 0.9 ; 1 , 1.1 , 1.2 ; 1.3 , 1.4 , 1.5 }

正如我们所看到的,#I/#F允许定义整型/浮点型常量,而#M允许定义向量/矩阵。还可以在同一个文本文件中使用模式#E Expr定义表达式。例如:

#F expo 1.1 #M kernel1 { 0.1 , 0.2 , 0.3 ; 0.4 , 0.5 , 0.6 ; 0.7 , 0.8 , 0.9 ; 1 , 1.1 , 1.2 ; 1.3 , 1.4 , 1.5 } #E dotpr(kernel1,im1b1N3x5)