'list(contour)'的结果表示什么?

时间:2012-01-30 06:40:30

标签: python opencv ipython contour

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

enter image description here

在轮廓查找后,我在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)]

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

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

enter image description here

我不明白这意味着什么。

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


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

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)

2 个答案:

答案 0 :(得分:3)

好的,我已经看过你的照片了,你 获取每个区域的顶点。我需要一段时间才能解决问题,因为我使用cv2界面而非cv界面。

一些事情:

  • 您的输入图像simple.jpeg除了0和255之外还有多个灰度值,很可能是由于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)

contours drawn

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

在矩形边缘和角落周围存在所有这些怪异的微小轮廓的原因是因为(我猜)通过将图像保存为JPEG而引入的压缩伪像,这是有损的。如果您使用无损格式(例如PNG或TIFF)保存正方形,则只能通过矩形的角定义一个轮廓。

经验教训:

  • cv.FindContours 给出每个轮廓的“顶点”
  • 您需要contours = contours.h_next()遍历每个轮廓
  • 如果你保存为JPEG期望人工制品!使用TIFF / PNG /无损的东西!

答案 1 :(得分:3)

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

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

New output of image in question

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

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

test-image-2

为此,我希望列出8个值,即T的8个角。

Output of image 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)以上示例仅找到一个轮廓。找到多个轮廓时会出现什么情况?我没有清楚地理解多链接序列的概念,如math.coffee所解释的那样。所以为了测试,我拍了第三张照片。

test image 3

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

要获得第二个顶点的列表,我们使用了contour.h_next函数(感谢mathematical.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)]

输出图像:

Output of image 3

所以你可以期待一个圆的输出,“它有很多顶点”。

嗯,现在一切都很简单。我无法掌握轮廓值。这就是为什么,所有这一切。感谢。

更新 - 1:

有关新cv2模块中轮廓的更多详细信息,请参见此处:Contours -1 : Getting Started

更新 - 2:

关于cv2.CHAIN_APPROX_SIMPLE,所有这些解释都是正确的。但是如果我们使用cv2.CHAIN_APPROX_NONE,我们将获得轮廓上的所有点。本文中的示例详细解释了这一点:Contours - 5 : Hierarchy