C++ 在多次迭代中使用固定核的膨胀/侵蚀类似于使用更大尺寸的等效核的膨胀/侵蚀

C++ 在多次迭代中使用固定核的膨胀/侵蚀类似于使用更大尺寸的等效核的膨胀/侵蚀,c++,opencv,image-processing,C++,Opencv,Image Processing,在浏览OpenCV源代码时,我注意到,对于不止一次的迭代,它只会创建一个更大的内核并进行一次迭代 所以我的问题是,如果我们采用3x3大小的方形结构元素,并在三次迭代中对其进行扩展/腐蚀,它是否会与使用9x9内核对其进行一次扩展/腐蚀相同 if( iterations > 1 && countNonZero(kernel) == kernel.rows*kernel.cols ) { anchor = Point(anchor.x*iterations, anchor

在浏览OpenCV源代码时,我注意到,对于不止一次的迭代,它只会创建一个更大的内核并进行一次迭代

所以我的问题是,如果我们采用3x3大小的方形结构元素,并在三次迭代中对其进行扩展/腐蚀,它是否会与使用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;
}

简短回答:有一个正方形的结构元素,是的

长回答:你需要考虑腐蚀/膨胀操作。例如,膨胀将内核移动到图像上,并在其任何网格位置为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

当然,如果我们将plus的缩放版本定义为一个没有角的正方形(通常是这样),这是可行的。我认为,一般来说,当大小为k+1的内核是大小为k的内核的扩展版本时,这种快捷方式有效,但我没有证据证明这一点。

参考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
进行膨胀,我们就写
displatedimage=K+I

让我们将二进制运算符
U
定义为并集运算符,或者换句话说,每个像素的二进制“或”运算符,其中
U
的两个操作数必须是相同维度的二进制图像。例如:
A U B
表示在A和B的每个对应像素上执行或:

A= 0 0 1   B= 0 1 1
   1 0 1      1 1 1
   1 1 0      0 1 0
然后

我们还将
ua(i),i=1,…,n定义为A(1)ua(2)U。。。U A(n)

让我们将
K^n
定义为通过在单个中心点图像上应用n倍的内核
K
来扩展样式的较大内核

请注意,任何图像
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=ud(I),I=1,…,n

根据二进制膨胀的定义,
K+I==K+(ud(I))==U(K+D(I))
。 (记住,膨胀是在
I
的每个像素上屏蔽内核
K
,并标记所有对应的1)

现在,让我们看看什么是
K+(K+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+B)=(K+A)U(K+B)

很容易看出,如果我们分解图像
A
B
,并在分解后的图像上应用内核
K
,这些公共点(即
A
B
的交点,或
A
B
的公共1点),在应用内核
K
后,将贡献相同的结果点。根据膨胀的定义,我们需要合并A和B的每个分解图像贡献的所有点。因此定理1成立

==更新===

关于kid.abr的评论“27个操作与7x7内核49个操作相比”: 一般来说,它不是27个操作。视情况而定。例如,100x100像素的源图像, 20个奇点(1)稀疏分布。在其上应用3x3实心内核(即所有1)3次 对于20个奇点中的每一个,需要执行以下步骤:

循环1:9个操作,生成9个点

循环2:对于生成的9个点中的每一个,都需要9个操作=>9x9=81个步骤。它产生25分

循环3:对于生成的25个点中的每一个,它需要9个操作=>25 x 9=225个步骤

总计:9+81+225=315步

请注意,当我们访问源图像中值为0的像素时,我们不需要应用内核 在那一点上,对吗

因此,与应用更大内核的情况相同,它需要7x7=49个步骤


然而,如果源图像有一个大的1的实体区域,则三步方法获胜。

对于一般内核的简短回答:对于膨胀/侵蚀,是的,但不一定使用等效内核

来自维基百科:

  • :(A)⊕(B)⊕C=A⊕(B)⊕(C)
  • :(A)⊖(B)⊖C=A⊖(B)⊕(C)
在哪里⊕ 表示形态扩张
    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
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))