8

这是示例图像:

截屏

我使用opencv来检测轮廓:

>>> fc = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
>>> contours = fc[0]

为了检测闭合轮廓,我想检查 opencv 返回的每个轮廓中的起点和终点,而我注意到无论对象的形状如何,opencv 似乎都勾勒出每个对象,所以我得到了这个结果:

>>> for contour in contours:
>>>    print(contour[0,:,:], contour[-1,:,:])
[[246  38]] [[247  38]]
[[92 33]] [[93 33]]

或者每个找到的轮廓都有闭合路径。

我在函数中搜索了可用方法的其他常量findContour(),但似乎都返回封闭路径。

那么是否有一些通用的方法来检测找到的轮廓是否闭合?


我在问之前用谷歌搜索并没有得到结果,但我在右侧的类似问题中看到了很好的候选人:我如何知道轮廓在 opencv 中是打开还是关闭?建议我使用的地方cv2.isContourConvex(contour),但是:

>>> for contour in contours:
>>>    print(cv2.isContourConvex(contour))
False
False

另一个更新:contourArea看起来它可以提供答案(至少对于简单的轮廓),但我没有在上面的示例图像上进行任何其他测试:

>>> for contour in contours:
>>>     print(cv2.contourArea(contour))
0.0
12437.5
4

4 回答 4

6

我自己遇到了这个问题,我找到了解决方法......

经历这个..

for i in contours: print(cv2.contourArea(i), cv2.arcLength(i,True))

我注意到闭合轮廓(例如圆圈)的值contourArea高于arcLength,而开放轮廓(例如线条)的值contourArea低于arcLength,因此您可以过滤它们...

closed_contours = []
open_contours = []
for i in contours:
    if cv2.contourArea(i) > cv2.arcLength(i, True):
        closed_contours.append(i)
    else:
        open_contours.append(i)

我知道这是 3 年前提出的,但对于其他需要想法的人来说,这对我有用!

于 2019-05-25T18:39:27.613 回答
1

如果您的示例图像是位图,那么即使单个像素已经有一个区域,所以它也有一个轮廓。封闭的圆甚至有两个轮廓,一个在里面,一个在外面。半圈只有一个,跨越内外,并在末端掉头。

我猜您想将这两个圆视为确实没有面积且只有一个“轮廓”的曲线。然后圆将是闭合曲线,半圆将是开放的。如果是这种情况,您的新问题是将位图转换为曲线。这不是微不足道的,即使我们人类很容易感知那里的曲线,因为它需要定义一个算法和参数,将一个区域变成曲线。

我知道的一种方法是从位图派生一个骨架,它基本上会剥去外面的像素层,直到你只剩下一堆连接的点。我不熟悉opencv,但我可以想象它已经有一些实用程序。此外,搜索“curve line detect opencv”将opencv-identifying-lines-and-curves作为此处的第一个链接,以及许多其他点击。

于 2013-07-05T05:23:03.393 回答
0

根据定义,闭合轮廓将具有单独的内部轮廓。
看看 的hierarchy论点findContours()

hierarchy - 可选的输出向量,包含有关图像拓扑的信息。它具有与轮廓数一样多的元素。对于每个第 i 个轮廓 contours[i] ,元素 hierarchy[i][0] 、 hiearchy i、 hiearchy[i][2] 和 hiearchy[i][3] 被设置为轮廓中从 0 开始的索引同一层级的下一个和上一个轮廓,分别是第一个子轮廓和父轮廓。如果轮廓 i 没有下一个、上一个、父级或嵌套轮廓,则 hierarchy[i] 的相应元素将为负数。

于 2013-07-05T06:39:14.997 回答
0

这不完全是 python 的答案,可能为时已晚。根据我对 Emgu 的经验,任何面积为零的轮廓都不会闭合。您还可以将该区域与其周长进行比较作为额外检查,如果它非常小,那么它肯定没有关闭。不规则的形状有时在其轮廓的某处有一个很小的封闭区域。

轮廓区域可以从

cvContourArea

Emgu 中的轮廓周长定义为

cvArcLength(contour, CV_WHOLE_SEQ, 1);
于 2015-10-10T06:04:06.573 回答