【问题标题】:How to fill a circle contour at the edge of an image?如何在图像边缘填充圆形轮廓?
【发布时间】:2020-05-23 07:57:04
【问题描述】:

在上图中,我希望最终能够填充彩色圆圈的轮廓。不幸的是,底部的黄色圆圈正好在图像的边缘,所以cv2.findContours()不起作用:

_, green_contours, _ = cv2.findContours(green_seg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

有谁知道我如何以某种方式填充黄色圆圈轮廓,即使它位于图像的边缘?由于它位于图像的边缘,因此图像底部边缘的像素值没有完成圆,如果有意义的话,它的值不是 255。

我在网上看了,有人说可以在图像周围画一个大框然后做轮廓,但是如果我这样做,那么opencv只会在整个图像周围绘制大轮廓而不是圆圈。

任何其他想法将不胜感激!

编辑:我上面显示的图像只是我正在考虑的一种情况。我正在尝试如何使这个足够通用,以便对于边界边缘的任何轮廓,我仍然可以使用 cv2.drawContour() 填充轮廓。

【问题讨论】:

  • 手动画线。找到轮廓边缘的黄色轮廓点,用cv2.line()画一条线?
  • @Ahmet 感谢您的回复!但是我需要能够使用代码自动执行此操作,因为这种情况很多。
  • 您确定填充不起作用吗?可以发原图让我试试吗?
  • 你完全可以在面具周围画一个框!您只需要绘制黑色边框,而不是白色边框!如果它是白色的,它将成为轮廓的一部分。如果它是黑色的,它不会是。简单如:)。只需使用copyMakeBorder()
  • 将蒙版图像保存为 PNG(因此它是纯黑白的)并用它编辑您的帖子。应该够了!不要画在你的图像上,用额外的边框填充图像(即你的图像会稍微大一点)。然后您需要移动轮廓结果的位置,因为您的填充图像将在 x 和 y 中添加 1 个像素到每个轮廓点。

标签: python opencv


【解决方案1】:

如果你有(或多或少)凸多边形,你实际上可以使用cv2.findContours。有了轮廓,尝试找到质心,例如使用cv2.moments,然后将其用作cv2.floodFill中的种子点。

请看下面的代码sn-p。我假设,您可以通过颜色识别多边形。此外,我没有对质心进行一些高级发现,而是使用了每个轮廓的边界矩形的中心点。也许,这对您的用例也足够了!?

import cv2
import numpy as np

# Set up test image
colors = [(0, 255, 0), (0, 0, 255)]
input = np.zeros((400, 400, 3), np.uint8)
cv2.circle(input, (100, 100), 50, colors[0], 10)
cv2.circle(input, (150, 350), 75, colors[1], 10)
output = input.copy()

# Iterate all colors...
for i, c in enumerate(colors):

    # Mask color
    img = np.all(output == c, axis=2).astype(np.uint8) * 255

    # Find contours with respect to OpenCV version
    cnts = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]

    # Get bounding rectangles; derive seed points for flood filling; flood fill
    rects = [cv2.boundingRect(c) for c in cnts]
    seeds = [(np.int32(r[0] + r[2] / 2), np.int32(r[1] + r[3] / 2)) for r in rects]
    [cv2.floodFill(output, mask=None, seedPoint=s, newVal=c) for s in seeds]

cv2.imshow('input', input)
cv2.imshow('output', output)
cv2.waitKey(0)
cv2.destroyAllWindows()

这是输入:

这就是输出:

希望有帮助!

----------------------------------------
System information
----------------------------------------
Platform:    Windows-10-10.0.16299-SP0
Python:      3.8.1
NumPy:       1.18.1
OpenCV:      4.1.2
----------------------------------------

【讨论】:

  • 非常感谢您的评论!我真的很抱歉我忘了提及,但我所拥有的图像不一定都在底部。它们可能位于左侧、右侧或顶部。所以,按照我的看法,floodfill 不起作用,因为我必须实际查看它才能看到轮廓在哪里。
  • @cmed123 这个答案是说从轮廓中心使用洪水填充,而不是从边界,所以你的评论无关紧要。但是,此评论确实假设轮廓是凸的。否则,不能保证质心实际上在轮廓内,所以这仍然不是一个通用的解决方案。
【解决方案2】:

一个简单的方法,也许不是那么精确,是计算每个轮廓的凸包并用填充颜色绘制内部:

import cv2
import numpy as np
import sys

# load input image from the cmd-line
img = cv2.imread('test_images/partial_contour.png')
if (img is None):
    print('!!! Failed imread')
    sys.exit(-1)

output_img = img.copy()

# isolate just the colored drawings
ret, thres_bgr = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY)
thres_bgr[np.where((thres_bgr == [255,255,255]).all(axis=2))] = [0,0,0] # replace white pixels for black

# convert from 3-channels (BGR) to a single channel (gray)
gray_img = cv2.cvtColor(thres_bgr, cv2.COLOR_BGR2GRAY)

# this loop processes all the contours found in the image
contours, hierarchy = cv2.findContours(gray_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contourIdx, cnt in enumerate(contours):
    # compute a convex hull
    hull = cv2.convexHull(cnt)

    # fill the inside with red
    cv2.fillPoly(output_img, pts=[hull], color=(0, 0, 255))

cv2.imshow('output_img', output_img)
cv2.imwrite('fill_partial_cnt_output.png', output_img)
cv2.waitKey(0)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-26
    • 1970-01-01
    • 1970-01-01
    • 2013-12-29
    • 1970-01-01
    • 2013-11-17
    • 2021-03-17
    • 1970-01-01
    相关资源
    最近更新 更多