这取决于内核类型。对于奇数平方内核的膨胀或腐蚀,增加大小或增加迭代没有区别(假设使用使它们相等的值)。例如:
>>> M = np.zeros((7,7), dtype=np.uint8)
>>> M[3,3] = 1
>>> k1 = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
>>> M1 = cv2.dilate(M, k1, iterations=2)
>>> k2 = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
>>> M2 = cv2.dilate(M, k2, iterations=1)
>>> M1
[[0 0 0 0 0 0 0]
[0 1 1 1 1 1 0]
[0 1 1 1 1 1 0]
[0 1 1 1 1 1 0]
[0 1 1 1 1 1 0]
[0 1 1 1 1 1 0]
[0 0 0 0 0 0 0]]
>>> M2
[[0 0 0 0 0 0 0]
[0 1 1 1 1 1 0]
[0 1 1 1 1 1 0]
[0 1 1 1 1 1 0]
[0 1 1 1 1 1 0]
[0 1 1 1 1 1 0]
[0 0 0 0 0 0 0]]
这是相当直观的。用于扩张的3x3 矩形内核将找到任何白色像素,并将相邻像素变为白色。所以很容易看出,这样做两次将使任何单个白色像素变成一个 5x5 的白色像素块。这里我们假设中心像素是被比较的像素——anchor——但这可能会改变,这可能会影响结果。例如,假设您将(2, 2) 内核的两次迭代与(3, 3) 内核的一次迭代进行比较:
>>> M = np.zeros((5, 5), dtype=np.uint8)
>>> M[2,2] = 1
>>> k1 = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))
>>> M1 = cv2.dilate(M, k1, iterations=2)
>>> k2 = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
>>> M2 = cv2.dilate(M, k2, iterations=1)
>>> M1
[[0 0 0 0 0]
[0 0 0 0 0]
[0 0 1 1 1]
[0 0 1 1 1]
[0 0 1 1 1]]
>>> M2
[[0 0 0 0 0]
[0 1 1 1 0]
[0 1 1 1 0]
[0 1 1 1 0]
[0 0 0 0 0]]
您可以看到,虽然它创建了形状(直观),但它们不在同一个地方(非直观)。那是因为(2, 2) 内核的锚点不能位于内核的中心——在这种情况下,我们看到在中心像素的情况下,膨胀的邻居只在右下角,因为它必须选择一个方向,因为它只能扩展单个像素以填充(2, 2) 正方形。
使用非矩形形状的内核变得更加棘手。例如:
>>> M = np.zeros((5, 5), dtype=np.uint8)
>>> M[2,2] = 1
>>> k1 = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
>>> M1 = cv2.dilate(M, k1, iterations=2)
>>> k2 = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))
>>> M2 = cv2.dilate(M, k2, iterations=1)
>>> M1
[[0 0 1 0 0]
[0 1 1 1 0]
[1 1 1 1 1]
[0 1 1 1 0]
[0 0 1 0 0]]
>>> M2
[[0 0 1 0 0]
[0 0 1 0 0]
[1 1 1 1 1]
[0 0 1 0 0]
[0 0 1 0 0]]
M1 的第一遍创建一个高 3 像素、宽 3 像素的小十字。但随后这些像素中的每一个都会在其所在位置创建一个十字,这实际上创建了一个菱形图案。
所以总结一下基本的形态学运算,对于矩形内核,至少是奇维内核,结果是相同的——但对于其他内核,结果是不同的。您可以将其他形态学运算应用到像这样的简单示例中,以了解它们的行为方式以及您应该使用哪些以及如何增加它们的效果。