4

我只是想了解轮廓的含义以及当我们使用 OpenCV 中的 cv.FindContours 函数创建轮廓时存储的值是什么(我使用的是 OpenCV 2.3.1 和 Python)。我使用以下简单图像进行测试:

在此处输入图像描述

轮廓查找后,我在 ipython 中应用了以下命令:

In [8]: contour
Out[8]: <cv2.cv.cvseq at 0x90a31a0>

In [10]: list(contour)
Out[10]: 
 [(256, 190),
  (255, 191),
  (112, 191),
  (255, 191),
  (256, 190),
  (257, 191),
  (257, 190)]

第一个命令说,轮廓是一个 cvSeq 对象。

我在图像上标记了这些点,这给了我以下图像(红色标记的圆圈是点):

在此处输入图像描述

我不明白这是什么意思。

所以我的问题是第二个命令(即列表(轮廓))结果中的值表示什么?


编辑:以下是我使用的代码。

import cv
img = cv.LoadImage('simple.jpeg')
imgg = cv.LoadImage('simple.jpeg',cv.CV_LOAD_IMAGE_GRAYSCALE)
storage = cv.CreateMemStorage(0)
contours = cv.FindContours(imgg,storage,cv.CV_RETR_TREE,cv.CV_CHAIN_APPROX_SIMPLE,(0,0))
print list(contours)
for i in list(contours):
    cv.Circle(img,i,5,(0,0,255),1)
cv.ShowImage('img',img)
cv.WaitKey(0)
4

2 回答 2

4

根据 math.coffee 上面提供的答案,我在输出上做了一些工作,list(contour)以了解轮廓。

1)我在测试图像上犯了一个错误。我认为它是一个二值图像,而实际上它也是一个带有一些其他颜色的灰度图像。(感谢 math.coffee)。所以我将图像更改为纯黑白图像,这样我只会得到一个轮廓并再次测试。这一次,list(contour)给出了 4 个值的结果,当绘制在图像上时,它们是该框的四个角。

有问题的图像的新输出

因此,当我们使用 'cv.DrawContours' 函数时,会绘制连接所有这些顶点的线。所以我假设 cv.FindContours 存储实际上是多边形的轮廓顶点的位置。

2) 为了再次测试,我拍摄了另一张 T 形图像。

测试图像 2

为此,我期望一个包含 8 个值的列表,它们是 T 的 8 个角。

图像 2 的输出

`list(contour)' 打印以下包含 10 个值的列表。(2个额外的值可能是由于我的绘图错误)

[(92, 58), (92, 108), (174, 108), (175, 109), (175, 239), (225, 239), (225, 109), (226, 108), (285, 108), (285, 58)]

这意味着 cv.FindContours 创建 cvseq 对象。它里面存储了我上面假设的值。

3) 上面的例子只找到一个轮廓。找出多个轮廓时会出现什么情况?正如mathical.coffee 所解释的,我并没有清楚地理解多重链接序列的概念。所以为了测试,我拍了第三张照片。

测试图 3

现在 cv.FindContours 找到三个轮廓。请记住,每个轮廓都是框的 4 个角的列表。这三个列表存储在单个 cvseq 对象中,并且指针仅指向第一个轮廓,即仅第一个框的顶点列表。因此,使用上面的代码,只绘制了一个框的角。

为了获得第二个顶点的列表,我们使用了 contour.h_next 函数(感谢 math.coffee,直到现在我才知道它的函数)。现在它指向第二个盒子的轮廓。因此,我们遍历其中的所有列表。

所以我添加了一个简单的while循环,如下所示:

while contours:
   print list(contours)
   for i in list(contours):
       cv.Circle(img,i,5,(0,0,255),3)
   contours = contours.h_next()

我得到了三个对应于三个盒子角落的列表:

[(196, 237), (196, 279), (357, 279), (357, 237)]
[(141, 136), (141, 201), (346, 201), (346, 136)]
[(33, 39), (33, 92), (206, 92), (206, 39)]

和输出图像:

图像 3 的输出

因此,您可以预期“具有大量顶点”的圆会输出什么。

好吧,现在一切都很简单。我无法掌握轮廓值。这就是为什么,所有这些混乱。谢谢。

更新 - 1:

cv2此处提供了有关新模块中轮廓的更多详细信息:轮廓 -1:入门

更新 - 2:

对于 cv2.CHAIN_APPROX_SIMPLE,所有这些解释都是正确的。但是如果我们使用 cv2.CHAIN_APPROX_NONE 代替,我们会得到轮廓上的所有点。本文通过示例对其进行了详细说明:Contours - 5 : Hierarchy

于 2012-01-30T15:22:14.903 回答
4

好的,我看过您的图片,您正在获取每个区域的顶点。我花了一段时间才解决,因为我使用的cv2不是那个界面cv

一些东西:

  • 除了 0 和 255 之外,您的输入图像simple.jpeg中还有多个灰度值,这很可能是由于 jpeg 压缩。
  • 因此,对于不同的灰度级,您可以从 , 中获得多个区域。FindContours
  • cv.FindContours返回多个链接序列,您必须遍历它们以获取所有等高线。
  • 您为示例得出的轮廓是边界轮廓之一。

为了演示,让我们画出所有的轮廓。

contours = cv.FindContours(imgg,storage,cv.CV_RETR_TREE,cv.CV_CHAIN_APPROX_SIMPLE,(0,0))
colours = [ (0,255,0,0),   # green
            (255,0,0,0),   # blue
            (255,255,0,0), # cyan
            (0,255,255,0), # yellow
            (255,0,255,0), # magenta
            (0,0,255,0)]   # red 
i=0
while contours:
    cv.DrawContours(img, contours, colours[i], colours[i], 0, thickness=-1)
    i = (i+1) % len(colours)
    contours = contours.h_next() # go to next contour
cv.ShowImage('img',img)
cv.WaitKey(0)

绘制的轮廓

所以我们看到你list(contours)在原始问题中的第一个轮廓是正方形底部的绿色小条,你得到的点对应于它的顶点。

矩形边缘和角落周围有所有这些奇怪的微小轮廓的原因是(我猜)将图像保存为 JPEG 会引入压缩伪影,这是有损的。如果你用无损格式(比如 PNG 或 TIFF)保存你的正方形,你只会得到一个由矩形的角定义的轮廓。

得到教训:

  • cv.FindContours 确实给出了每个轮廓的“顶点”
  • 你需要contours = contours.h_next()遍历每个轮廓
  • 如果您保存为 JPEG 格式,请期待人工制品!改用 TIFF/PNG/无损的东西!
于 2012-01-30T09:05:56.617 回答