对于多次迭代,具有固定内核的膨胀/侵蚀类似于使用更大尺寸的等效内核进行扩张/侵蚀

kid*_*abr 4 c++ opencv image-processing

在浏览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;
}
Run Code Online (Sandbox Code Playgroud)

Rob*_*Hsu 5

参考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
Run Code Online (Sandbox Code Playgroud)

然后应用两次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
Run Code Online (Sandbox Code Playgroud)

但这并不能直接回答你的问题.但是,我不能只使用"评论",因为格式化所有这些方程/解释非常困难(如果不是不可能).

实际上,对于较大的组合内核进行扩张的二进制图像(每个像素中仅值为0或1的图像)的证明很容易:

让我们将二元运算符定义为+扩张运算符,其中第一个操作数是内核,第二个操作数是要扩展的图像.所以,如果我们想I用内核对图像进行扩张K,我们写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
Run Code Online (Sandbox Code Playgroud)

然后

A U B = 0 1 1
        1 1 1
        1 1 0
Run Code Online (Sandbox Code Playgroud)

我们也定义U A(i), i=1, ..., n to be A(1) U A(2) U ... U A(n).

让我们K^n通过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
Run Code Online (Sandbox Code Playgroud)

现在是时候证明它了:

对于任何图像I,我们定义D(i), i = 1, ..., n为单点分解I,因此I = U D(i), i = 1, ..., n

根据二元扩张的定义,K + I == K + (U D(i)) == U (K+D(i)).(请记住,扩张是为了掩盖K每个像素上的内核I,并标记所有相应的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))
Run Code Online (Sandbox Code Playgroud)

现在,我们已经知道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)

这是很容易地看到,如果我们分解图像AB,并应用内核K上分解图像,这些共同点(即交点AB,或共同1的角度AB),将采用内核后有助于同一由此而来点K.通过扩张的定义,我们需要结合由A和B的每个分解图像贡献的所有点.因此定理1成立.

===更新===

关于kid.abr的评论"27个操作与7x7内核相比49个操作":一般来说,它不是27个操作.这取决于.例如,100x100像素的源图像,稀疏地分布有20个奇异点(1).对其应用3x3实心内核(即全1)3次需要对20个奇异点中的每一个进行以下步骤:

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

循环2:对于生成的9个点中的每一个,它需要9次操作=> 9×9 = 81步.它产生了25分

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

总计:9 + 81 + 225 = 315步.

请注意,当我们访问源图像中具有0值的像素时,我们不需要在该点上应用内核,对吧?

因此,应用较大内核的情况相同,需要7x7 = 49步.

然而,如果源图像具有1的大实心区域,则3步法获胜.