我有一个看起来像一个相当简单的问题 - 我有一个图像,我可以使用以下代码从中提取轮廓 -
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个参数,但不起作用。
修改:添加示例图像 - 左侧圆圈应绘制为空,而右侧方框应绘制为完整。
无论如何,你知道吗?
谢谢!
丹
答案 0 :(得分:2)
如果某人有一天需要做类似的事情,这就是我最终使用的代码。效率不高,但效果很好,时间不是这个项目的一个因素(注意我在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]
答案 1 :(得分:0)
您可以检查层次结构参数以检查轮廓是否具有子(未填充)或未填充(填充),
例如,
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没有下一个,前一个,父级或嵌套轮廓,则层次结构[i]的相应元素将为负数。因此,对于每个轮廓,您必须检查是否有孩子,
并且
如果儿童轮廓 - >;绘制厚度= 1的轮廓;
如果没有儿童轮廓 - >绘制厚度= CV_FILLED;
我认为此方法适用于您发布的图片。
另请参阅答案here可能会有所帮助。
答案 2 :(得分:0)
这是你如何创建一个蒙版图像(即填充的轮廓)然后&#34;过滤&#34;带有该掩码的源图像以获得结果。
在这个被剪切的&#34;&#34;是阈值图像(单通道)
#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))传递给它。