文章目录
边缘检测可以检测出边缘信息,但可能边缘不连续,而轮廓检测可以将边缘形成一个整体,便于后续处理。
Opencv中提供了查找图像轮廓的函数cv2.findContours(),其能查找图像的轮廓信息;cv2.drawContours()能将轮廓画出来。
一.查找并绘制轮廓
1.查找图像轮廓
函数cv2.findContours()的语法格式为:
contours,hierarchy=cv2.findContours(image,mode,method)
函数参数说明:
(1)返回值contours
返回的是一组轮廓信息,类型为list,但其每个元素的类型为ndarray。其内的每一个元素为一个轮廓,而每一个轮廓由若干点组成。我们可以通过contours[i]来获取图像第i个轮廓的信息。可以用len(contours)来获取其轮廓的个数。
(2)返回值hierarchy
描述不同轮廓之间的层次关系,每个轮廓都含有一个列表来描述当前轮廓所在的层次,形式为:
【Next,Previous,First_child,Parent】
各元素的含义:
Next:后一个轮廓的索引编号
Previous:前一个轮廓的索引编号
First_child:第一个子轮廓的索引编号
Parent:父轮廓的索引编号
若对应元素关系不存在时,则该参数的值为-1
(3)输入参数image
输入图像,一般情况下都是将图像处理为二值图像之后,再讲其作为image参数使用
(4)输入参数mode
其决定轮廓的提取方式,具体为:
1. cv2.RETR_EXTERNAL:只检测外轮廓
2. cv2.RETR_LIST:对检测到的轮廓不建立等级关系
3. cv2.RETR_CCOMP:检索所有轮廓并将他们组织为两级层次结构。上面一层为外边界,下面一层为内孔边界。
4. cv2.RETR_TREE:建立一个等级树结构的轮廓
(5)输入参数method
其决定如何表示轮廓,具体为:
1. cv2.CHAIN_APPROX_NONE:存储所有的轮廓点,相邻两像素点的位置不超过1。
2. cv2.CHAIN_APPROX_SIMPLE:压缩水平方向,垂直方向和对角方向的元素,只保留该方向的终点坐标。例如,对一个矩形,可以用四个点保存其轮廓信息。
2.绘制图像轮廓
cv2.drawContours()绘制图像轮廓,其语法格式:
image=cv2.drawContours(image,contours,contourIdx,color)
参数说明:
image:待绘制轮廓的图像
contours:需要绘制的轮廓,list类型,里面含有多个轮廓信息
contoursIdx:需要绘制轮廓的索引,可以指定需绘制的轮廓,若其为负数,则表明要绘所有的轮廓。
color:绘制轮廓的颜色,用BGR来表示。
3.实例
import cv2
image=cv2.imread("wb3.png")
image2=image.copy()
image1=image.copy()
image1=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
retval,image1=cv2.threshold(image1,127,255,cv2.THRESH_BINARY_INV)
contours,hierarchy=cv2.findContours(image1,cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)
o=cv2.drawContours(image,contours,-1,(0,0,255))
cv2.imshow("image",image2)
cv2.imshow("edge",o)
cv2.waitKey()
cv2.destroyAllWindows()
运行结果:
二.矩特征
比较两个轮廓最简单的方法为比较二者的轮廓矩。轮廓矩含有对象不同类型的几何特征。
1.轮廓矩的计算
Opencv提供了函数cv2.moments()来获取图像的moments特征。使用轮廓矩可以方便的比较两个轮廓。
函数语法:
retval=cv2.moments(array[,binaryimage])
参数说明:
array:可以是点集,也可以是灰度图像或者二值图像。当array为点集时,其会把这些点集当做轮廓中的顶点。
binaryimage:该参数为True时,图像内所有非零值处理为1。
retval:返回值,其类型为dict,常用的几个键值为:
mm0:零阶矩,代表边缘轮廓面积
中心矩:
二阶中心矩:mu20,mu11,mu02
三阶中心矩:mu30,mu21,mu12,mu03
归一化中心矩
二阶Hu矩:nu20,nu11,nu02
三阶Hu矩:nu30,nu21,nu12,nu03
中心矩具有平移不变性
归一化中心矩具有缩放不变性
2.计算轮廓面积
cv2.contourArea()用于计算轮廓面积,其语法:
retval=cv2.contourArea(contour[,oriented])
参数说明:
retval:轮廓面积
contour:轮廓
oritented:为True是,结果带正负号,表明轮廓是顺时针还是逆时针。默认为False,返回面积的绝对值。
3.计算轮廓周长
cv2.arcLength()用于计算轮廓面积,其语法:
retval=cv2.arcLength(curve[,closed])
参数说明:
retval:轮廓周长
curve:轮廓
closed:用来表示轮廓是否封闭。为True时,表示轮廓是封闭的。
三.轮廓近似
cv2.approxPolyDP()函数对图像轮廓进行多边近似,类似于二分。函数语法格式:
retval=cv2.approxPolyDP(cnt,epsilon,True)
参数:
retval:近似后的轮廓值
cnt:原始轮廓
epsilon:阈值
实例:
import cv2
image=cv2.imread("jh3.png")
image2=image.copy()
image1=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
contours,hierarchy=cv2.findContours(image1,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt=contours[1]
epsilon1=0.1*cv2.arcLength(cnt,True)
epsilon2=0.001*cv2.arcLength(cnt,True)
res1=cv2.approxPolyDP(cnt,epsilon1,True)
res2=cv2.approxPolyDP(cnt,epsilon2,True)
o1=cv2.drawContours(image2,[res1],-1,(0,0,255))
o2=cv2.drawContours(image,[res2],-1,(0,0,255))
cv2.imshow("o1",o1)
cv2.imshow("o2",o2)
cv2.waitKey()
cv2.destroyAllWindows()
运行结果:
可以观察到,epsilon(阈值)不同,得到结果不同,且阈值越小,得到的近似图形越精确。