【发布时间】:2015-06-24 09:47:43
【问题描述】:
在最近的一组图像中,我的 OpenCV 代码停止寻找轮廓的正确区域。当轮廓未闭合时,这似乎会发生。我试图确保轮廓关闭无济于事。
编辑:问题是轮廓中有间隙。
背景: 我在通道中有一系列胶囊的图像,我想测量形状的面积以及时刻的质心。
问题: 当轮廓不闭合时,矩是错误的。
编辑:当我有间隙时,轮廓不是整个形状,因此区域不正确。
我的工作:
- 读取图像-> img =cv2.imread(fileName,0)
- 应用 Canny 过滤器 -> 边缘 = cv2.Canny(img,lowerThreshold,lowerThreshold*2)
- 查找轮廓 -> 轮廓,层次结构 = cv2.findContours(edges,cv2.cv.CV_RETR_LIST,cv2.cv.CV_CHAIN_APPROX_NONE)
- 找到最长的轮廓
- 确保轮廓闭合
- 寻找时刻 -> cv2.moments(cnt)
可以在here找到一个带有测试图像的工作示例。
有一个关于关闭轮廓的question,但这些建议都没有奏效。使用 cv2.approxPolyDP 不会改变结果,尽管它应该返回一个闭合的轮廓。添加轮廓的第一个点作为最后一个点,以使其闭合,也不能解决问题。
下面是带有轮廓的图像示例。在这里,该区域被确定为 85,而在几乎相同的图像中,它是 8660,这是它应该的。
任何建议都会被采纳。
代码:
img =cv2.imread(fileName,0)
edges = cv2.Canny(img,lowerThreshold,lowerThreshold*2)
contours, hierarchy = cv2.findContours(edges,cv2.cv.CV_RETR_LIST,cv2.cv.CV_CHAIN_APPROX_NONE) #cv2.cv.CV_CHAIN_APPROX_NONE or cv2.cv.CV_CHAIN_APPROX_SIMPLE
#Select longest contour as this should be the capsule
lengthC=0
ID=-1
idCounter=-1
for x in contours:
idCounter=idCounter+1
if len(x) > lengthC:
lengthC=len(x)
ID=idCounter
if ID != -1:
cnt = contours[ID]
cntFull=cnt.copy()
#approximate the contour, where epsilon is the distance to
#the original contour
cnt = cv2.approxPolyDP(cnt, epsilon=1, closed=True)
#add the first point as the last point, to ensure it is closed
lenCnt=len(cnt)
cnt= np.append(cnt, [[cnt[0][0][0], cnt[0][0][1]]])
cnt=np.reshape(cnt, (lenCnt+1,1, 2))
lenCntFull=len(cntFull)
cntFull= np.append(cntFull, [[cntFull[0][0][0], cntFull[0][0][1]]])
cntFull=np.reshape(cntFull, (lenCntFull+1,1, 2))
#find the moments
M = cv2.moments(cnt)
MFull = cv2.moments(cntFull)
print('Area = %.2f \t Area of full contour= %.2f' %(M['m00'], MFull['m00']))
【问题讨论】:
-
好:您搜索了上一个问题并找到了相关内容,并在您的问题中提到了这一点。不好:你只是说这些建议不起作用。为什么他们没有工作?你试过什么?现在,我给您的答案与上一个问题完全相同:确保您的轮廓围绕整个对象闭合,例如通过膨胀或凸包。如果边界中有间隙,则该区域将始终是错误的。另外,请附上一张解压和处理图像(即画出你的轮廓),以吸引最有潜力的回答者。
-
解决一些误解:findContours 将始终返回闭合轮廓。 ApproxPoly 或在末尾添加第一个点不会改变这一点。你的问题不是轮廓没有闭合,你的问题是轮廓闭合在错误的区域,即如果你将一个精巧的边缘图像传递给包含间隙的 findContours,找到的轮廓将被关闭,但它包含的区域将只是边缘本身,而不是内部。对于初学者,我会避免精明并在 findContours 之前使用简单的阈值。
-
重读上一个问题,我觉得这个问题有些误导。正如我所说,我很确定 findContours 返回一个封闭的轮廓。如果你放大你的图像,我想你会发现在错误的情况下,轮廓沿着对象的边界运行了两次,一次在外面,一次在里面,这样它就包含了你的对象的整个边界,但不是它的内部。如果精巧的边缘图像仅包含单个间隙,则对象上方的凸包将解决此问题。 Canny 边缘图像的扩张将关闭任意数量的小间隙。
-
@NegativeProbability 你可以将单个点绘制为单个像素而不是小圆圈吗?很难看出是否有缝隙。如果您改用“drawContours”(填充)函数,您将看到 openCV 如何解释轮廓,因此您可能会了解面积计算失败的原因。
-
@Micka 这里link HugoRune 是正确的,问题是轮廓中有间隙。我将修改问题以明确这一点。
标签: python opencv image-processing