如何使用OpenCV Python准确检测空心圆(环)的位置?

5
我希望能够确定这张(视频截图)中注射器尖端的中心位置。这些尖端名义上是圆形的,大小和数量已知。
我目前正在尝试在尖端上放置红色油墨,使其更容易被检测到。不过如果不加入红色油墨,则检测很难进行。是否有人能接受这个挑战?
我最初尝试了SimpleBlobDetector,因为它有一些不错的过滤功能。但有一件事我无法解决,那就是如何让SimpleBlobDetector检测到空心圆(环)?
然后我尝试使用canny + hough,但圆形检测太不稳定,位置会跳动。
我目前正在使用findContours + minEnclosingCircle,它可以工作,但仍然相当不稳定。掩膜看起来像这样结果如图。您可以看到准确性还不够好:

Gif

我简要地看了一下RANSAC,但我找不到一个可以检测多个圆的Python示例,而且边缘检测也很棘手。
我的当前代码:
# https://dev59.com/HFwY5IYBdhLWcg3wh4Iq
frame_inv = ~frame0
# Convert BGR to HSV
hsv = cv2.cvtColor(frame_inv, cv2.COLOR_BGR2HSV)
blur = cv2.GaussianBlur(hsv, (5, 5), 0)
# define range of color in HSV
lower_red = np.array([90 - 10, 70, 50])
upper_red = np.array([90 + 10, 255, 255])
# Threshold the HSV image to get only red colors
mask = cv2.inRange(hsv, lower_red, upper_red)
# cv2.imshow('Mask', mask)
kernel = np.ones((5, 5), np.uint8)
dilate = cv2.dilate(mask, kernel)
# cv2.imshow('Dilate', dilate)
contours = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]

tipXY = []
for c in contours:
    area = cv2.contourArea(c)
    if area > 200:
        (x, y), r = cv2.minEnclosingCircle(c)
        center = (int(x), int(y))
        r = int(r)
        shift = 2
        factor = 2 ** shift
        cv2.circle(frame0, (int(round((x) * factor)), int(round((y) * factor))),
                       int(round(10 * factor)), (0, 255, 0), 2, shift=shift)
        tipXY.append(center)

有没有建议来提高位置检测的准确性和稳定性?

1
霍夫圆变换很不错。根据您当前的光照设置,可能难以找到那些没有标记为红色的尖端。如果您能从未标记的尖端中获得更多对比度,也许可以使用一些边缘增强/检测技术。 - bfris
1
我的理解是,如果你不确定你的图像是否包含圆形,霍夫圆可能是很好的选择。但是,如果你知道有圆形存在,其他方法可能更容易调整。当然,我发现霍夫圆对参数非常敏感。 - Anthony
1个回答

1

这里有一种更好的方法,可以使用第二张图像作为输入来分割红色。

思路:

由于红色比较突出,我尝试将其转换为其他已知颜色空间(LAB和YCrCb),并查看它们的各个通道。从YCrCb中的Cr表达了红色更为突出。根据此链接Cr通道表示红色和亮度之间的差异,使颜色更加突出。

代码:

img = cv2.imread('stacked_rings.jpg')

ycc = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
cr_channel = ycc[:,:,1]

enter image description here

虽然可以看到空心的圆环,但像素强度范围仅限于[109-194]。让我们拉伸一下这个范围:
dst = cv2.normalize(cr_channel, dst=None, alpha=0, beta=255,norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)

enter image description here

这句话的意思是:“圆圈更加突出。希望这个预处理步骤能够帮到你。”

这非常有用,谢谢。顺便问一下,对于图像分割来说,哪种颜色最合适?我用红色因为那是我手边有的印泥。 - Anthony
@Anthony 像红色、绿色、蓝色和黄色这样的主要颜色可以根据颜色空间相当容易地进行分割。在这个答案中,我展示了如何从LAB颜色空间的'A'通道中分割出绿色。通过分析'A'通道,可以分割红色。同样,蓝色和黄色可以使用'B'通道进行分割,因为它们位于'B'轴的两端。 - Jeru Luke
我一直在尝试这个,结果参差不齐。你能建议我下一步该怎么做来找到每个环的中心吗? - Anthony
@Anthony 你需要将图像二值化,使用适当的阈值使得圆形呈现为白色,而其他部分则为黑色。接下来,在这个二值化图像上找到轮廓,并找到每个轮廓的质心。 - Jeru Luke
啊,明白了。我会花些时间研究阈值。谢谢。 - Anthony

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接