在OpenCV中检测圈子

时间:2019-03-22 22:23:10

标签: opencv image-recognition hough-transform

尽管我意识到OpenCV的HoughCircles没有“一刀切”的设置,但即使找到一组合理的参数,我也遇到了很多麻烦。

我的输入图像是下面的照片,其中包含一些非常明显的大黑圈以及周围的一些噪点:

Original input photo

我尝试使用p1p2参数,以尝试准确地检测到四个黑圈(以及可选的顶部胶带卷-不需要,但是我不需要介意它是否匹配)。

import numpy as np
import cv2

gray = frame = cv2.imread('testframe2.png')

gray = cv2.cvtColor(gray, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray,(5,5),0)
# gray = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 5, 2)

p1 = 200
p2 = 55

while True:
    out = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)

    circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 10, param1=p1, param2=p2, minRadius=10, maxRadius=0)

    if circles is not None:
        for (x, y, r) in circles[0]:
            cv2.rectangle(out, (int(x - r), int(y - r)), (int(x + r), int(y + r)), (255, 0, 0))
            cv2.putText(out, "r = %d" % int(r), (int(x + r), int(y)), cv2.FONT_HERSHEY_SIMPLEX, 0.3, (255, 0, 0))

    cv2.putText(out, "p: (%d, %d)" % (p1, p2), (0, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 4)
    cv2.imshow('debug', out)

    if cv2.waitKey(0) & 0xFF == ord('x'):
        break
    elif cv2.waitKey(0) & 0xFF == ord('q'):
        p1 += 5
    elif cv2.waitKey(0) & 0xFF == ord('a'):
        p1 -= 5
    elif cv2.waitKey(0) & 0xFF == ord('w'):
        p2 += 5
    elif cv2.waitKey(0) & 0xFF == ord('s'):
        p2 -= 5

cv2.destroyAllWindows()

似乎我能做的最好的事情是多次检测到一个大圆圈,但根本检测不到一个小圆圈,会得到很多误报:

Best parameter setting: detects big circle multiple times but not the small one

我已经阅读了F **手册,但是它对我没有进一步的帮助:如何在某种程度上可靠地检测出圆圈,而这张图中的圆圈除外?

1 个答案:

答案 0 :(得分:0)

使用HoughCircles参数进行了一些手动调整,但这可以提供您想要的结果。我使用了OpenCV Wrapper library,它只是简化了一些事情。

import cv2
import opencv_wrapper as cvw
import numpy as np

frame = cv2.imread("tape.png")

gray = cvw.bgr2gray(frame)
thresh = cvw.threshold_otsu(gray, inverse=True)
opened = cvw.morph_open(thresh, 9)

circles = cv2.HoughCircles(
    opened, cv2.HOUGH_GRADIENT, 1, 10, param1=100, param2=17, minRadius=5, maxRadius=-1
)

if circles is not None:
    circles = np.around(circles).astype(int)
    for circle in circles[0]:
        cv2.floodFill(thresh, None, (circle[0], circle[1]), 155)

only_circles = thresh.copy()
only_circles[only_circles != 155] = 0

contours = cvw.find_external_contours(only_circles)
cvw.draw_contours(frame, contours, (255, 0, 255), thickness=2)

cv2.imwrite("tape_result.png", frame)

根据documentation注释中的建议,我使用HoughCircles仅查找中心。

然后我用floodFill填充了圆圈。请注意,最左边的圆非常靠近边缘。如果图像模糊,则洪水填充将进入背景。

披露:我是OpenCV Wrapper的作者。尚未添加霍夫环和洪水填充。