我一直在使用变体。在OpenCV中打开以通过opencv降低图像ROI之外的噪音,直到现在,每当我需要更高程度的降噪时,我只是随机增加内核大小或增加迭代次数,直到我开心。但结果是否存在显着差异,具体取决于您增加的数量/在给定情况下您将如何决定改变哪些?我试图想出一个更好的方法,除了猜测和检查之外我更改哪个参数(多少)。
答案 0 :(得分:8)
这取决于内核类型。对于使用奇数平方内核进行扩张或侵蚀,无论是增大大小还是增加迭代都没有区别(假设使用了使它们相等的值)。例如:
>>> 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的白色像素块。在这里我们假设中心像素是被比较的那个 - 锚 ---但是这可能会改变,这可能会影响结果。例如,假设您将(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像素。但是这些像素中的每一个都会在它们的位置创建一个十字形,这实际上会创建一个菱形图案。
总而言之,对于基本的形态运算,矩形内核,至少是奇数维的,结果是相同的 - 但对于其他内核,结果是不同的。您可以将其他形态学操作应用于这样的简单示例,以了解它们的行为以及您应该使用哪些以及如何增加它们的效果。