Python OpenCV:在特定轮廓内绘制外部轮廓

Posted

技术标签:

【中文标题】Python OpenCV:在特定轮廓内绘制外部轮廓【英文标题】:Python OpenCV: draw outer contours inside a specific contour 【发布时间】:2019-01-25 22:33:17 【问题描述】:

我是 OpenCV 新手,我正在尝试在特定轮廓内绘制外部轮廓。这是我用来澄清的图像(已经灰度化、阈值化等)

我想要的是在外部矩形内找到所有圆的轮廓(总共 120 个)。

contours =  cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

所以我基本上为此使用了RETR_EXTERNAL,但它只返回外部矩形。我尝试使用RETR_TREE,但在这种情况下,它返回的轮廓比圆圈多,出于某种我不明白的原因。澄清一下:我只想要每个圆圈 1 个轮廓。

如何使用RETR_EXTERNAL 并忽略外轮廓(矩形),使其只返回圆圈?

【问题讨论】:

这个案例需要用到层次的概念。 【参考方案1】:

按区域过滤轮廓:

我按区域过滤轮廓以隔离圆圈。我认为您可能需要在thresholding 图像上多做一些工作,以帮助从图像中的边界划定圆圈。我使用了以下代码:

import cv2
import numpy as np

img = cv2.imread("/your/path/C03eN.jpg")

def find_contours_and_centers(img_input):

    img_gray = cv2.cvtColor(img_input, cv2.COLOR_BGR2GRAY)
    img_gray = cv2.bilateralFilter(img_gray, 3, 27,27)
    #(T, thresh) = cv2.threshold(img_input, 0, 100, 0)
    _, contours_raw, hierarchy = cv2.findContours(img_gray, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    contours = [i for i in contours_raw if cv2.contourArea(i) > 20]
    contour_centers = []

    for idx, c in enumerate(contours):
        M = cv2.moments(c)
        cX = int(M["m10"] / M["m00"])
        cY = int(M["m01"] / M["m00"])
        samp_bounds = cv2.boundingRect(c)
        contour_centers.append(((cX,cY), samp_bounds))

    print("0 contour centers and bounds found".format(len(contour_centers)))

    contour_centers = sorted(contour_centers, key=lambda x: x[0])

    return (contours, contour_centers)

conts, cents = find_contours_and_centers(img.copy())

circles = [i for i in conts if np.logical_and((cv2.contourArea(i) > 650),(cv2.contourArea(i) < 4000))]

cv2.drawContours(img, circles, -1, (0,255,0), 2)

cv2.imwrite("/your/path/tester.jpg", img)

结果:

编辑:

如果您只想提取较大外矩形内的图像部分,请使用cv2.RETR_EXTERNAL,让您专注于内圈,您可以执行以下操作:

import cv2
import numpy as np

img = cv2.imread("/your/path/C03eN.jpg")

def find_contours_and_centers(img_input):

    img_gray = cv2.cvtColor(img_input, cv2.COLOR_BGR2GRAY)
    img_gray = cv2.bilateralFilter(img_gray, 3, 27,27)
    #(T, thresh) = cv2.threshold(img_input, 0, 100, 0)
    #_, contours_raw, hierarchy = cv2.findContours(img_gray, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    _, contours_raw, hierarchy = cv2.findContours(img_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    contours = [i for i in contours_raw if cv2.contourArea(i) > 20]
    contour_centers = []

    for idx, c in enumerate(contours):
        M = cv2.moments(c)
        cX = int(M["m10"] / M["m00"])
        cY = int(M["m01"] / M["m00"])
        samp_bounds = cv2.boundingRect(c)
        contour_centers.append(((cX,cY), samp_bounds))

    print("0 contour centers and bounds found".format(len(contour_centers)))

    contour_centers = sorted(contour_centers, key=lambda x: x[0])

    return (contours, contour_centers)

conts, cents = find_contours_and_centers(img.copy())

x,y,w,h = cv2.boundingRect(conts[0])

cropped = img[y+10:y+(h-10),x+10:x+(w-10)]

cv2.imwrite("/your/path/cropped.jpg", cropped)

结果:

【讨论】:

谢谢你的回复,但是为什么绿色的“圆圈”形状那么糟糕?当我画我的圆圈时,它们看起来不错,但问题是每个圆圈有不止 1 个轮廓,这是我不想要的……理想情况下,我想删除外部矩形,这样我就可以使用 RETR_EXTERNAL,效果很好。有什么办法吗? 不确定,我刚刚下载了图像并尝试了它,也许你的分辨率更好,我的测试图像分辨率低 你问题的最后一部分是:“我怎样才能使用 RETR_EXTERNAL 并忽略外轮廓(矩形),以便它只返回圆圈?”我只是将其作为您的预期解决方案,并尝试仅返回圆圈。 好的,我明白了,但是没有更简单的方法可以使外部矩形变黑(就像背景一样),这样我就可以使用RETR_EXTERNAL了吗? 是的,您可以使用它来返回外框的轮廓,然后您可以创建蒙版,绘制黑色轮廓以隐藏圆圈,或完全提取图像的该部分以隔离您的区域感兴趣的

以上是关于Python OpenCV:在特定轮廓内绘制外部轮廓的主要内容,如果未能解决你的问题,请参考以下文章

Opencv和python获取文档正确的轮廓并在图像上绘制

为确定的地标点绘制轮廓( OpenCvForUnity )

如何使用opencv绘制轮廓内的区域? (图片是从 dxf 文件导出的)[关闭]

如何隔离轮廓内的所有内容,对其进行缩放并测试与图像的相似性?

python --opencv图像处理轮廓(寻找轮廓绘制轮廓)详解

26opencv入门轮廓查找与绘制——正外接矩形