使用OpenCV

时间:2019-03-05 18:22:14

标签: python opencv

我正在尝试检测4个小节内的正方形。目的是比较它们的质心。在大多数情况下,我的方法(如下所述)可以正确识别大多数情况。在聚焦不良或光线太弱的图像中,处理后的图像的正方形破裂或断开,无法使用Canny检测到轮廓。这是常规方法流程:

  1. 使用模板匹配来查找“条”并创建投资回报率
  2. 通过ADAPTIVE_THRESH_MEAN_C在ROI上使用adaptiveThreshold
  3. 通过将ROI的边缘设置为255(白色)来隔离正方形
  4. 使用带有MORPH_OPEN和(8,8)MORPH_RECT作为结构元素的morphologyEx
  5. 通过imutils.auto_canny方法(由pyimagesearch.com的Adrian Rosebrock编写)使用经过优化的Canny来找到正方形
  6. 返回“条”和“正方形”的中心,并在原始图像上显示它们的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似乎运行良好。在所有这些处理之后,我都尝试过匹配“正方形”的模板,但是它经常失败。

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

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

虽然我希望有一种神奇的方法可以完全满足我的需求,但我已经花了几个时间来解决这个问题,并希望得到类似的答案。预先感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

在找到中心之前尝试填充正方形。我通过遍历行并连接最左边和最右边的黑色像素来完成此操作。

filling in square

# 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)