cv2.findConours( )
简介
cvFindContours可以从二值图像中检索轮廓,并返回检测到的轮廓的个数。first_contour的值由函数填充返回,它的值将为第一个外轮廓的指针,当没有轮廓被检测到时为NULL。其它轮廓可以使用h_next和v_next连接,从first_contour到达。
[cpp] view plaincopy
int cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour,
int header_size=sizeof(CvContour), int mode=CV_RETR_LIST,
int method=CV_CHAIN_APPROX_SIMPLE, CvPoint offset=cvPoint(0,0) );
image: 8比特单通道的源二值图像,灰度图像。非零像素作为1处理,0像素保存不变。从一个灰度图像得到二值图像的函数有:cvThreshold,cvAdaptiveTh reshold和cvCanny。
storage:返回轮廓的容器。
first_contour:输出参数,用于存储指向第一个外接轮廓。
header_size:header序列的尺寸.如果选择method = CV_CHAIN_CODE, 则header_size >= sizeof(CvChain);其他,则header_size >= sizeof(CvContour)。
mode:检索模式,可取值如下: CV_RETR_EXTERNAL:只检索最外面的轮廓; CV_RETR_LIST:检索所有的轮廓,并将其放入list中; CV_RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界; CV_RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次。
method:边缘近似方法(除了CV_RETR_RUNS使用内置的近似,其他模式均使用此设定的近似算法)。可取值如下: CV_CHAIN_CODE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。 CV_CHAIN_APPROX_NONE:将所有的连码点,转换成点。 CV_CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。 CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS:使用the flavors of Teh-Chin chain近似算法的一种。 CV_LINK_RUNS:通过连接水平段的1,使用完全不同的边缘提取算法。使用CV_RETR_LIST检索模式能使用此方法。
offset:偏移量,用于移动所有轮廓点。当轮廓是从图像的ROI提取的,并且需要在整个图像中分析时,这个参数将很有用。
讨论部分cvDrawContours中的案例显示了任何使用轮廓检测连通区域。轮廓可以用于形状分析和目标识别——可以参考文件夹OpenCV sample中的squares.c。
- 第一个,也是最坑爹的一个,它返回了你所处理的图像
- 第二个,正是我们要找的,轮廓的点集
- 第三个,各层轮廓的索引
函数原型
cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])
参数
1、 image:第一个参数是寻找轮廓的图像
2、 mode:第二个参数表示轮廓的检索模式,有四种:
(1)cv2.RETR_EXTERNAL:表示只检测外轮廓
(2)cv2.RETR_LIST:检测的轮廓不建立等级关系
(3)cv2.RETR_CCOMP:建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层
(4)cv2.RETR_TREE:建立一个等级树结构的轮廓
3、mode:第三个参数method为轮廓的近似办法
(1)cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
(2)cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
(3)cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
返回值
cv2.findContours()函数返回两个值,一个是轮廓本身(contours),还有一个是每条轮廓对应的属性(hierarchy)。
contour返回值
cv2.findContours()
函数首先返回一个list,list中每个元素都是图像中的一个轮廓,用numpy中的ndarray表示。通过下面的代码验证一下:
# 验证上面的图片有多少个图像轮廓
print (type(contours))
print (type(contours[0]))
print (len(contours))
返回结果
<class 'list'>
<class 'numpy.ndarray'>
4
上面测试的图片有4条轮廓,包括乖字的三部分及边框,每个轮廓是一个ndarray,每个ndarray是轮廓上的点的集合。
由于我们知道返回的轮廓有4个,因此可通过:
cv2.drawContours(img, contours, 0, (0,0,255), 3)
cv2.drawContours(img, contours, 1, (0,0,255), 3)
cv2.drawContours(img, contours, 2, (0,0,255), 3)
cv2.drawContours(img, contours, 3, (0,0,255), 3)
这四条命令获取不同图片部分的轮廓,当第三个参数设置成 -1 时,则获取的就是所有图像的轮廓信息。
hierarchy返回值
此外,该函数还可返回一个可选的hiararchy结果,这是一个ndarray,其中的元素个数和轮廓个数相同,每个轮廓contours[i]对应4个hierarchy元素hierarchy[i][0] ~hierarchy[i][3],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为负数。
此外,该函数还可返回一个可选的hiararchy结果,这是一个ndarray,其中的元素个数和轮廓个数相同,每个轮廓contours[i]对应4个hierarchy元素hierarchy[i][0] ~hierarchy[i][3],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为负数。
print (type(hierarchy))
print (hierarchy.ndim)
print (hierarchy[0].ndim)
print (hierarchy.shape)
结果
<class 'numpy.ndarray'>
3
2
(1, 4, 4)
实例
improve cv2
improve numpy as np
img=cv2.imread('test.jpg')
imgray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh=cv2.thrshold(imgray,127,255,0)
image,cnts,hierarchy=cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.imshow('imageshow',image) # 显示返回值image,其实与输入参数的thresh原图没啥区别
cv2.waitKey()
print(np.size(cnts)) # 得到该图中总的轮廓数量
print(cnts[0]) # 打印出第一个轮廓的所有点的坐标, 更改此处的0,为0--(总轮廓数-1),可打印出相应轮廓所有点的坐标
print(hierarchy) #打印出相应轮廓之间的关系
img=cv2.drawCountours(img,[cnts[0]],-1,(0,255,0),10) #标记处编号为0的轮廓
cv2.imshow('drawimg',img)
cv2.waitKey()
输出结果
5 ###说明总轮廓是为5
[[[272 421]] #编号为0的轮廓的一系列坐标值
[[270 423]]
......
......
[[274 421]]
下面具体解释下hierarchy输出的矩阵参数的意义 其输出矩矩阵大小为NXM, 其中N为轮廓的个数,M恒等于4,也就是说每一行的4个数,能够表示出轮廓间的相互关系,那么具体是怎样表示的呢
第一个数:表示同一级轮廓的下个轮廓的编号,如果这一级轮廓没有下一个轮廓,一般是这一级轮廓的最后一个的时候,则为-1 第二个数:表示同一级轮廓的上个轮廓的编号,如果这一级轮廓没有上一个轮廓,一般是这一级轮廓的第一个的时候,则为-1 第三个数:表示该轮廓包含的下一级轮廓的第一个的编号,假如没有,则为-1 第四个数:表示该轮廓的上一级轮廓的编号,假如没有上一级,则为-1 废话不多说,直接上图,标记处各轮廓间层次关系及编号
[[[ 1 -1 -1 -1] #轮廓0
[ 4 0 2 -1] #轮廓1
[-1 -1 3 1] #轮廓2
[-1 -1 -1 2] #轮廓3
[-1 1 -1 -1]]] #轮廓4
轮廓0
-
它的同级下一个的编号为1,第一个参数为1;
-
因为这一级别的第一个,第二个参数-1;
-
因为不包含子轮廓,所以第三个参数-1;
-
因为处于第一级,其不属于任何别的级别,所以第四个参数为-1
轮廓1
-
它的同级下一个的编号为4,第一个参数为4;
-
因为这一级别的上一个的编号为0,第二个参数0;
-
因为包含子轮廓,且子轮廓的第一个编号(当然只包含一个,多个也是同样的道理)为2,所以第三个参数2;
-
因为处于第一级,其不属于任何别的级别,所以第四个参数为-1
轮廓2
-
它是第二级的最后一个(因为只有一个),所以第一个参数为-1;
-
它也是第二级的第一个,所以第二个参数为-1;
-
因为包含子轮廓,且子轮廓的第一个编号(当然只包含一个,多个也是同样的道理)为3,所以第三个参数3;
-
因为处于第二级,其属于上一级的轮廓1,所以第四个参数为1 依次类推 。。。。。轮廓3
轮廓4
-
它是同一级(第一级)的最后一个,因此第一个参数为-1;
-
因为这一级别的上一个的编号为1,第二个参数1;
-
因为不包含子轮廓,所以第三个参数-1;
-
因为处于第一级,其不属于任何别的级别,所以第四个参数为-1
cv2.contourArea( )
简介
可以计算面积
cv2.drawContours( )
简介
进行轮廓的绘制
cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset ]]]]])
- 第一个参数是指明在哪幅图像上绘制轮廓;
- 第二个参数是轮廓本身,在Python中是一个list。
- 第三个参数指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。后面的参数很简单。其中thickness表明轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式。绘制参数将在以后独立详细介绍。
函数原型
cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset ]]]]])
image:第一个参数是指明在哪幅图像上绘制轮廓;
contours:第二个参数是轮廓本身,在Python中是一个list。
contourIdx:第三个参数指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。
thickness:thickness表明轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式。
cv2.threshlod( )
简介
有三个参数
参数1:原始图片(灰度图)
参数2:具体阈值,用来分类像素的值
参数3:最大值 Third argument is the maxVal which represents the value to be given if pixel value is more than (sometimes less than) the threshold value. 第三个参数是maxVal,它表示如果像素值大于(有时小于)阈值则要给出的值。
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('gradient.png',0)
ret,thresh1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
ret,thresh2 = cv.threshold(img,127,255,cv.THRESH_BINARY_INV)
ret,thresh3 = cv.threshold(img,127,255,cv.THRESH_TRUNC)
ret,thresh4 = cv.threshold(img,127,255,cv.THRESH_TOZERO)
ret,thresh5 = cv.threshold(img,127,255,cv.THRESH_TOZERO_INV)
titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in xrange(6):
plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()