在OpenCV NumPy中找到轮廓的边界点

3

enter image description here我是一个OpenCV和NumPy的初学者。这是我的图片,这是我的代码:

import numpy as np
import cv2

im = cv2.imread('test.jpg')
imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
imgray = cv2.medianBlur(imgray, ksize=7)

ret, thresh = cv2.threshold(imgray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

print ("number of countours detected before filtering %d -> "%len(contours))
new = np.zeros(imgray.shape)

new = cv2.drawContours(im,contours,len(contours)-1,(0,0,255),18)

cv2.namedWindow('Display',cv2.WINDOW_NORMAL)
cv2.imshow('Display',new)
cv2.waitKey()

mask = np.zeros(imgray.shape,np.uint8)
cv2.drawContours(mask,[contours[len(contours)-1]],0,255,-1)
pixelpoints = cv2.findNonZero(mask)
cv2.imwrite("masked_image.jpg",mask)

print(len(pixelpoints))
print("type of pixelpoints is %s" %type(pixelpoints))

由于它包含轮廓覆盖的所有点,因此pixelpoints的长度接近200万。 但是,我只需要该轮廓的边界点。 我该怎么办? 我尝试了opencv文档中的几种方法,但总是出现元组和排序操作错误。 请...帮帮我?

我只需要轮廓的边界点:(


1
这份文档中,它清楚地说明了使用哪个参数来去除冗余点并获取端点。我无法相信你的说法,“我已经尝试了opencv文档中的几种方法”。 - Rick M.
请上传您用于查找轮廓的二进制图像,以及预期输出。 - ZdaR
@RickM.,我可能以某种方式得罪了你。我道歉。我知道你在谈论将cv2.CHAIN_APPROX_NONE更改为cv2.CHAIN_APPROX_SIMPLE,但是在没有直线的图片中应用它不起作用。我仍然得到200万个点。如果您查看文档,它强调减少线条点数,而不是弧线。我已经尝试过了。 - gluttony47
@MonirulIslam 尝试使用 approxPolyDP。你也可以尝试使用 connectedComponents - Rick M.
@RickM,到目前为止我有一种感觉,你只是随便说出脑海中的任何想法,不幸的是,你提出的所有建议都是无效的。还是谢谢你。 - gluttony47
显示剩余5条评论
1个回答

3

这是您所说的轮廓边界点吗?
(我使用了上面的图片进行尝试)

您看到的白色线条是我用白色标记在蓝色绘制的轮廓上的点。右下角有一个小点,因为我认为您的黑色背景可能并不真正是黑色,因此当我进行阈值处理和泛洪填充时,就像这样:
enter image description here

同一位置会出现微小的白色斑点。但如果您调整参数并进行更适当的阈值处理和泛洪填充,则不应该出现问题。 在OpenCV的drawContours函数中,cnts将包含轮廓列表,每个轮廓都包含一个点数组。每个点也是numpy.ndarray类型。如果您想将每个轮廓的所有点放在一个地方,以便返回边界点集(如上图中轮廓外围的白点),则可以将它们全部附加到列表中。您可以尝试这样做:

#rgb is brg instead
contoured=cv2.drawContours(black, cnts, -1, (255,0,0), 3)

#list of ALL points of ALL contours
all_pixels=[]

for i in range(0, len(cnts)):
    for j in range(0,len(cnts[i])):
        all_pixels.append(cnts[i][j])

当我尝试时

print(len(all_pixels))

它返回了2139个点。

如果您想为可视化目的标记出点数(例如,像我的白点一样),请执行以下操作:

#contouredC is a copy of the contoured image above
contouredC[x_val, y_val]=[255,255,255]

如果您想要更少的点,只需在迭代时使用阶跃函数来绘制白点。类似于这样:
enter image description here 在Python中,for循环速度较慢,因此我认为有更好的方法可以用np.where()函数或其他方式替换嵌套的for循环。如果/当我弄清楚了,我会更新这个内容。此外,这需要更好的阈值和二值化技术。洪水填充技术参考自:Python 2.7: Area opening and closing binary image in Python not so accurate
希望对您有所帮助。

代码无法运行,因为您使用了未定义的变量。请重新编写您的代码,以便人们可以真正重现结果,而不是像这样出现错误:“NameError:name 'x_val' is not defined”。 - Schütze
嗨,谢谢你的评论。我想我没有包含整个脚本,因为我还在编写其他东西(因此太长),当我参考其他stackoverflow答案时,似乎大多数答案都不显示整个代码。但是好建议,下次我会尝试包含更多代码。如果有帮助的话,我可以向您解释一下x_val是什么?所以x_val是我自己定义的,而contouredC是形成轮廓的点集。通过将这些点设置为白色([255 255 255]),我们可以可视化并查看它们。在我的最底部图片中,我使用了一个for循环(带步骤)。 - Reine_Ran_
生成间隔的白点。如果我能再次找到这个脚本,我会更新这个答案 :) - Reine_Ran_
@Ran_Reine_ 你是怎么找到 x_val 的?我需要边界上每个像素的颜色。 - Rishabh Gupta
1
@RishabhGupta,您实际上设置了边界中每个像素的颜色。在我上面的示例中,我将点设置为白色([255,255,255])。cv2.drawContours(black,cnts,-1,(255,0,0),3)用于绘制轮廓(因此获取图像中所有轮廓的点)(因为我将第三个参数设置为-1)。 - Reine_Ran_
显示剩余2条评论

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