【问题标题】:Detecting a broken shape using OpenCV使用 OpenCV 检测损坏的形状
【发布时间】:2019-07-27 07:12:07
【问题描述】:

我正在尝试检测 4 条内的正方形。目标是比较它们的质心。在大多数情况下,我的方法(如下所述)正确识别了大多数情况。在焦点不好或光线太低的图像中,处理后的图像有一个破碎或断开的正方形,其轮廓无法使用 Canny 检测到。下面是一般的方法流程:

  1. 使用模板匹配查找“条”并创建 ROI
  2. 在 ROI 上使用 AdaptiveThreshold 和 ADAPTIVE_THRESH_MEAN_C
  3. 通过将 ROI 的边缘设置为 255(白色)来隔离正方形
  4. 使用带有 MORPH_OPEN 和 (8,8) MORPH_RECT 作为结构元素的morphologyEx
  5. 通过 imutils.auto_canny 方法(由 Adrian Rosebrock 在 pyimagesearch.com 编写)使用优化的 Canny 来查找正方形
  6. 返回 'bars' 和 'square' 的中心并在原始图像上显示它们的 minAreaRect

这是一个典型的成功示例:thresholded ROI'bars' removedmorphology appliedoriginal with detected shapes

下面是一个损坏的、无法检测到的“正方形”示例: thresholded ROI'bars' removedmorphology appliedoriginal with detected shapes

我尝试过的事情:

在第 2 步:

methods = ['cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)[1]',
           'cv2.threshold(cv2.GaussianBlur(gray, (5, 5), 0), 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]',
           'cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 51, 2)',
           'cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 51, 2)']

全局阈值处理无法解释图像之间的不同亮度。 ADAPTIVE_THRESH_MEAN_C 的成功率高于 ADAPTIVE_THRESH_GAUSSIAN_C。两者中的“51”都是任意的。通过测试,似乎更高的数字会产生更清晰的形状。

在第 4 步:

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (8, 8))
roi = cv2.morphologyEx(roi, cv2.MORPH_OPEN, kernel)

对于结构化元素,我使用了各种尺寸的 RECT、ELLIPSE 和 CROSS。如果它们变得太大,我最终会在 auto.canny 更喜欢检测的“正方形”内创建形状,并且无法再找到外部“正方形”。使用 RETR_EXTERNAL 代替 RETR_LIST、RETR_CCOMP 或 RETR_TREE 不能解决此问题。对于形态学操作,我尝试过分别使用 MORPH_OPEN 和扩张/腐蚀作为在轮廓检测之前闭合破碎的“正方形”形状的一种方法。

在第 5 步:

auto_canny 似乎运作良好。在所有这些处理之后,我已经尝试过匹配“正方形”的模板,但它经常失败。

我正在寻找一个单一的解决方案,它既能捕捉当前的成功,也能捕捉到一些更“可实现”的失败。我愿意接受你提供的任何智慧。我目前正在考虑的新方向:

  • 在侧面使用线检测并找到它们的连接位置
  • 我可以使用 approxPolyDP 来近似正方形吗?
  • 为“正方形”编写我自己的检测算法。它需要找到 numpy 数组中的角,在这些点之间创建一个正方形,然后稍微扩展它。

虽然我希望有一种神奇的方法可以完全满足我的要求,但我已经花费了几个单位的时间来解决这个问题,并期望得到同样困难的答案。提前感谢您的帮助!

【问题讨论】:

    标签: python opencv


    【解决方案1】:

    在找到中心之前尝试填充正方形。我通过遍历行并连接最左边和最右边的黑色像素来做到这一点。

    # Iterate through each row in the image
    for row in range(img.shape[0]):
        # Find the left-most and right-most pixel in the sqare
        start, stop = 0, 0
        for col in range(img.shape[1]):
            # Find the left-most
            if img[row,col] != 255 and start == 0: start = col, row
            # Find the right-most
            if img[row,col] != 255: stop = col, row
        # If there was a pixel in that row, connect them with a line
        if start != 0:
            cv2.line(img, start, stop, 0, 1)
    

    【讨论】:

    • 谢谢,这很好用!至于更广泛的含义,您对这种方法的 O() 有感觉吗?谢天谢地,我的投资回报率很小(~160x160 像素);我应该担心更大图像集的计算时间吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-25
    • 2013-05-16
    相关资源
    最近更新 更多