C++ 在多次迭代中使用固定核的膨胀/侵蚀类似于使用更大尺寸的等效核的膨胀/侵蚀
在浏览OpenCV源代码时,我注意到,对于不止一次的迭代,它只会创建一个更大的内核并进行一次迭代 所以我的问题是,如果我们采用3x3大小的方形结构元素,并在三次迭代中对其进行扩展/腐蚀,它是否会与使用9x9内核对其进行一次扩展/腐蚀相同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
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))