【问题标题】:OpenCV - Drawing contours as they areOpenCV - 按原样绘制轮廓
【发布时间】:2014-05-25 14:39:45
【问题描述】:

我有一个看起来很简单的问题 - 我有一张图像,我正在使用以下代码从中提取轮廓 -

import numpy as np
import cv2

def findAndColorShapes(inputFile):
    # Find contours in the image
    im = cv2.imread(inputFile)
    imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
    ret,thresh = cv2.threshold(imgray,127,255,0)
    contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)

这很好地找到了图像中的轮廓,然后我使用 -

绘制它们
cv2.drawContours(fullIm, [con], -1, (0,255,0), 2)

有些形状是空心的(例如,有轮廓的圆形),而有些则是填充的。我想以原始图像中出现的方式绘制轮廓。例如,如果轮廓是一个实心圆,它应该用它的填充来绘制,如果它只是一个轮廓 - 作为一个轮廓。

我尝试了很多方法(其中包括将 findContours 中的模式更改为 CHAIN_APPROX_NONE 而不是 CHAIN_APPROX_SIMPLE),并更改了 drawContours 中的第 5 个参数,但没有成功。

编辑:添加示例图像 - 左圆应绘制为空,而右方应绘制完整。

你知道无论如何都可以做到吗?

谢谢!

【问题讨论】:

  • 你能发布一些示例图片吗?

标签: python opencv


【解决方案1】:

如果有一天有人需要做类似的事情,这就是我最终使用的代码。它效率不高,但效果很好,并且时间不是这个项目的一个因素(注意我在cv2.threshold(imgray,220,255,0) 中使用红色和绿色作为轮廓阈值。你可能想要改变它)-

def contour_to_image(con, original_image):
    # Get the rect coordinates of the contour
    lm, tm, rm, bm = rect_for_contour(con)

    con_im = original_image.crop((lm, tm, rm, bm))

    if con_im.size[0] == 0 or con_im.size[1] == 0:
        return None

    con_pixels = con_im.load()

    for x in range(0, con_im .size[0]):
        for y in range(0, con_im.size[1]):
            # If the pixel is already white, don't bother checking it
            if con_im.getpixel((x, y)) == (255, 255, 255):
                continue

            # Check if the pixel is outside the contour. If so, clear it
            if cv2.pointPolygonTest(con, (x + lm, y + tm), False) < 0:
                con_pixels[x, y] = (255, 255, 255)

    return con_im

def findAndColorShapes(input_file, shapes_dest_path):
    im = cv2.imread(input_file)
    imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
    ret, thresh = cv2.threshold(imgray, 220, 255, 0)
    contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

    i = 0

    for con in contours:
        con_im = contour_to_image(con, Image.open(input_file))
        if con_im is not None:
            con_im.save(shapes_dest_path + "%d.png"%i)
            i += 1

np_to_int()rect_for_contour() 是 2 个简单的辅助函数 -

def np_to_int(np_val):
    return np.asscalar(np.int16(np_val))

def rect_for_contour(con):
    # Get coordinates of a rectangle around the contour
    leftmost = tuple(con[con[:,:,0].argmin()][0])
    topmost = tuple(con[con[:,:,1].argmin()][0])
    bottommost = tuple(con[con[:,:,1].argmax()][0])
    rightmost = tuple(con[con[:,:,0].argmax()][0])

    return leftmost[0], topmost[1], rightmost[0], bottommost[1]

【讨论】:

    【解决方案2】:

    您可以检查层次参数来检查轮廓是否有子(未填充)或没有(填充),

    例如,

    vector< Vec4i > hierarchy
    

    第 i 个轮廓的位置

    hierarchy[i][0] = next contour at the same hierarchical level
    hierarchy[i][1] = previous contour at the same hierarchical level
    hierarchy[i][2] = denotes its first child contour
    hierarchy[i][3] = denotes index of its parent contour
    

    如果轮廓 i 没有下一个、上一个、父级或嵌套的轮廓,则相应的 hierarchy[i] 元素将为负数。因此,对于每个轮廓,您必须检查是否有孩子,

    还有

    如果子轮廓-> 绘制厚度=1的轮廓;
    如果没有子轮廓-> 用厚度=CV_FILLED 绘制轮廓;

    我认为这种方法适用于您发布的图像。

    另请参阅答案here 可能会有所帮助。

    【讨论】:

    • 这似乎只是在某些情况下。有没有办法告诉openCV绘制它与轮廓相关的所有像素?
    • 如果一定要按原样画轮廓,那为什么要找轮廓。如果您尝试绘制特定轮廓,则使用找到的轮廓创建蒙版并使用蒙版从源复制。
    【解决方案3】:

    这就是您创建蒙版图像(即填充轮廓)然后使用该蒙版“过滤”源图像以获得结果的方式。

    在这个截取的“th”是阈值图像(单通道)

    #np comes from import numpy as np
    mask = np.zeros(th.shape, np.uint8)  # create a black base 'image'
    mask = cv2.drawContours(mask, contours, -1, 255, cv2.FILLED)  # set everything to white inside all contours
    
    result = np.zeros(th.shape, np.uint8)  
    result = np.where(mask == 0, result, th)  # set everything where the mask is white to the value of th
    

    注意:findContours 操作给定的图像!如果您想在其他地方使用阈值图像,您可能需要将副本 (np.copy(th)) 传递给它。

    【讨论】:

      猜你喜欢
      • 2021-09-07
      • 2021-01-17
      • 1970-01-01
      • 2019-01-25
      • 2019-02-12
      • 2019-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多