【问题标题】:Iterations vs. Kernel Size in Morphological Operations (OpenCV)形态学运算中的迭代与内核大小 (OpenCV)
【发布时间】:2017-12-17 14:37:08
【问题描述】:

我一直在 OpenCV 中使用 morph opening 来通过 opencv 减少图像中 ROI 之外的噪声,直到现在,每当我需要更高程度的降噪时,我只是随机增加内核大小或增加迭代直到我满意为止。结果是否存在显着差异,具体取决于您增加哪个/在给定情况下您将如何决定更改哪个?除了猜测和检查之外,我正在尝试提出一种更好的方法来更改(更改多少)参数。

【问题讨论】:

    标签: opencv mathematical-morphology


    【解决方案1】:

    这取决于内核类型。对于奇数平方内核的膨胀或腐蚀,增加大小或增加迭代没有区别(假设使用使它们相等的值)。例如:

    >>> 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 像素的小十字。但随后这些像素中的每一个都会在其所在位置创建一个十字,这实际上创建了一个菱形图案。

    所以总结一下基本的形态学运算,对于矩形内核,至少是奇维内核,结果是相同的——但对于其他内核,结果是不同的。您可以将其他形态学运算应用到像这样的简单示例中,以了解它们的行为方式以及您应该使用哪些以及如何增加它们的效果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-11
      • 2020-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-31
      • 1970-01-01
      相关资源
      最近更新 更多