我只是试图理解轮廓的含义以及在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)]
第一个命令说,contour是一个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)
答案 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)
所以我们看到你原始问题中list(contours)
的第一个轮廓是正方形底部的小绿色条带,你得到的点对应于它的顶点。
在矩形边缘和角落周围存在所有这些怪异的微小轮廓的原因是因为(我猜)通过将图像保存为JPEG而引入的压缩伪像,这是有损的。如果您使用无损格式(例如PNG或TIFF)保存正方形,则只能通过矩形的角定义一个轮廓。
经验教训:
cv.FindContours
给出每个轮廓的“顶点”contours = contours.h_next()
遍历每个轮廓答案 1 :(得分:3)
我在list(contour)
的输出上做了更多的工作,以便根据math.coffee提供的答案了解轮廓。
1)我的测试图像出错了。我认为这是一个二进制图像,而实际上它也是一些带有其他颜色的灰度图像。 (感谢mathematical.coffee)。因此,我将图像更改为纯黑白图像,这样我只能获得一个轮廓并再次进行测试。这一次,list(contour)
给出了4个值的结果,当在图像上绘制时,该值是该框的四个角。
因此,当我们使用'cv.DrawContours'函数时,会绘制连接所有这些顶点的线条。所以我假设cv.FindContours存储轮廓顶点的位置,实际上是一个多边形。
2)为了再次测试,我拍摄了另一张T形图像。
为此,我希望列出8个值,即T的8个角。
`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所解释的那样。所以为了测试,我拍了第三张照片。
现在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)]
输出图像:
所以你可以期待一个圆的输出,“它有很多顶点”。
嗯,现在一切都很简单。我无法掌握轮廓值。这就是为什么,所有这一切。感谢。
更新 - 1:
有关新cv2
模块中轮廓的更多详细信息,请参见此处:Contours -1 : Getting Started
更新 - 2:
关于cv2.CHAIN_APPROX_SIMPLE,所有这些解释都是正确的。但是如果我们使用cv2.CHAIN_APPROX_NONE,我们将获得轮廓上的所有点。本文中的示例详细解释了这一点:Contours - 5 : Hierarchy