在浏览OpenCV源代码时,我注意到对于多个迭代,它只是创建一个更大大小的内核并执行一次迭代。
所以我的问题是,如果我们采用 3x3 大小的 SQUARE 结构元素并在三次迭代中膨胀/侵蚀它,它是否与用 9x9 内核膨胀/侵蚀它相同一次。
if( iterations > 1 && countNonZero(kernel) == kernel.rows*kernel.cols )
{
anchor = Point(anchor.x*iterations, anchor.y*iterations);
kernel = getStructuringElement(MORPH_RECT,
Size(ksize.width + (iterations-1)*(ksize.width-1),
ksize.height + (iterations-1)*(ksize.height-1)),
anchor);
iterations = 1;
}
参考Jordi的回答:
[引用] ...但是请注意,这并不适用于所有结构元素......
事实上,它以以下方式成立(不是在Jordi的例子中(:
第一步,在单个中心点 5x5 源图像上的 3x3 核中通过膨胀两次计算 5x5 核:
00000 00000 00100
00000 010 00100 010 01110
00100 + 111 -> 01110 + 111 -> 11111 ===> this is the equivalent 5x5 kernel for 2x 3x3 dilation
00000 010 00100 010 01110
00000 00000 00100
然后应用 3x3 原始膨胀核的两次相当于在更大的图像上应用这个 5x5 膨胀核。例如:
0000000000 0000000000 00100
0000000000 010 010 0000000000 01110
0011100000 + 111 + 111 === 0011100000 + 11111
0000001000 010 010 0000001000 01110
0000000000 0000000000 00100
0000000000 0000000000
不过,这并不能直接回答您的问题。 但是,我不能只使用"注释",因为格式化所有这些方程/解释非常困难(如果不是不可能的话(。
事实上,对于用于膨胀的较大组合内核的二进制图像(每个像素中只有值 0 或 1 的图像(的证明很容易:
让我们将二元运算符+
定义为膨胀运算符,其中第一个操作数是内核,第二个操作数是要膨胀的图像。 因此,如果我们想使用内核K
对图像I
进行膨胀,我们编写dilated-image = K + I
让我们将二元运算符U
定义为联合运算符,或者换句话说,每个像素的二进制"OR"运算符,其中U
的两个操作数必须是同一维度中的二进制图像。 例如:A U B
表示在 A 和 B 的每个相应像素上执行 -OR-:
A= 0 0 1 B= 0 1 1
1 0 1 1 1 1
1 1 0 0 1 0
然后
A U B = 0 1 1
1 1 1
1 1 0
我们还定义U A(i), i=1, ..., n to be A(1) U A(2) U ... U A(n)
。
让我们通过在单个中心点图像上应用 n 次核K
来定义K^n
膨胀风格的较大内核。
注意,任何图像I
,我们可以将其分解为单点图像的并集。 例如
0 1 0 0 1 0 0 0 0 0 0 0
I = 0 0 0 === 0 0 0 U 0 0 0 U 0 0 0
1 0 1 0 0 0 1 0 0 0 0 1
现在是时候证明这一点了:
对于任何图像I
,我们定义D(i), i = 1, ..., n
是I
的单点分解,从而I = U D(i), i = 1, ..., n
根据二元膨胀的定义,K + I == K + (U D(i)) == U (K+D(i))
.(请记住,膨胀是为了掩盖I
的每个像素上的核K
,并标记所有相应的 1(。
现在,让我们看看K + (K + I)
是什么:
K + (K + I) == K + U (K + D(i))
== U(K + (K + D(i))) (Note: this is tricky. see Theorem 1 below)
== U (K^2 + D(i)) (by definition of K^2)
== K^2 + U D(i) (by definition of the dilation)
== K^2 + I (since I = U D(i))
现在,我们已经知道了K + (K + I) == K^2 + I
,并且很容易应用数学归纳法来证明K + K + K .. + K + I = K^n + I
(注意:请应用右关联,因为我已经删除了括号(。
定理1:从K + U (K + D(i))
到U(K + (K+D(i)))
的推论证明
只要证明对于同一维度中的任何两个二进制图像 A 和 B 就足够了, K + (A U B) = (K+A) U (K+B)
很容易看出,如果我们分解图像A
和B
,并在分解的图像上应用核K
,这些公共点(即A
和B
的交点,或公共 1 的 A
和 B
点(在应用核K
后将贡献相同的结果点。 根据膨胀的定义,我们需要联合 A 和 B 的每个分解图像贡献的所有点。 因此定理 1 成立。
=== 更新 ===
关于kid.abr的评论"27个操作与7x7内核的49个操作":一般来说,它不是 27 个操作。 这要看情况。 例如,100x100 像素的源图像,具有 20 个奇异点 (1( 稀疏分布。 在其上应用 3x3 实体内核(即所有 1 个(3 次对于 20 个奇异点中的每一个,都需要执行以下步骤:
循环 1:9 次操作,并生成 9 个点。
循环 2:对于生成的 9 个点中的每一个,它需要 9 个操作 => 9 x 9 = 81 个步骤。它产生 25 分
循环 3:对于生成的 25 个点中的每一个,它需要 9 个操作 => 25 x 9 = 225 个步骤。
总计:9 + 81 + 225 = 315 步。
请注意,当我们访问源图像中值为 0 的像素时,我们不需要应用内核在这一点上,对吧?
因此,在应用较大内核的情况下,它需要 7x7 = 49 个步骤。
但是,如果源图像具有较大的实心区域(1(,则3步法获胜。
简短的回答:带有方形结构元素,是的。
长答案:您需要考虑侵蚀/膨胀操作的作用。 例如,膨胀将内核移动到图像上,并在它的任何网格位置为 1 时将其中心设置为 1(我假设二进制图像,它对灰度的工作方式相同(。增加结构元素中心与其边缘之间的距离与增加内核的大小相同。
但请注意,这并不适用于所有结构元素。假设你拿一个只是拉伸加号的结构元素,显然用 3 码扩张两次与用 5 码扩张一次是不一样的:
00000 00000 00100
00000 010 00100 010 01110
00100 + 111 -> 01110 + 111 -> 11111
00000 010 00100 010 01110
00000 00000 00100
00000 00100 00100
00000 00100 00100
00100 + 11111 -> 11111
00000 00100 00100
00000 00100 00100
当然,如果我们将加号的缩放版本定义为没有角的正方形(通常如此(,这确实有效。我认为一般来说,当大小为 k+1 的内核是大小为 k 的内核的膨胀版本时,此快捷方式有效,但我没有证据证明这一点。
一般内核的简短回答:膨胀/侵蚀是的,但不一定是等效内核。
来自维基百科:
- 膨胀: (A⊕B(⊕C
- = A⊕(B⊕C( 侵蚀: (A⊖B(⊖C
- = A⊖(B⊕C(
其中⊕表示形态膨胀,⊖表示形态侵蚀。
基本上,使用内核 B 对映像 A 执行侵蚀/膨胀,然后使用内核 C 对映像 C 执行侵蚀/扩张等效于使用用 C 扩张 B 获得的内核对映像 A 执行侵蚀/扩张。这可以很容易地扩展到任意数量的侵蚀/扩张。