【OpenCV入门】形状/轮廓的检测
我的个人博客:谋仁·Blog
微信公众号:谋仁的麻袋
CSDN:曹谋仁
检测前预处理—-边缘检测二值图
所谓形状/轮廓的检测就是把待检测图像中的边缘轮廓组成的图形识别出来,并检测出轮廓点,再对其进行判断。所以为便于检测轮廓,我们要在检测之前进行一些预处理:
灰度->高斯滤波->Canny边缘检测算法->图像膨胀
代码:
1 | /// <summary> |
findContours函数—-检测轮廓
函数作用:从二值图像中检测轮廓
函数的定义:
1 | void findContours( |
参数解释:
- image:8位单通道图像,非零像素视为1,零像素视为0。这里一般输入经过Canny边缘检测、inRange选择、拉普拉斯等变换成01图像。
- contours:检测到轮廓的变量,每一个轮廓被存储为点向量。定义轮廓的类型为:
1 | vector<vector<Point>> |
这是一个双重向量,外层向量存放待检测图中所有形状的轮廓;内层向量存放的是某一个轮廓的点集合(一组由连续的Point构成的点的集合的向量)
- hierarchy:参数定义的类型为:
1 | vector<Vec4i> hierarchy |
Vec4i的定义:
1 | typedef Vec<int, 4> Vec4i |
向量内每个元素都包含了4个int型变量,所以从定义上看,hierarchy是一个向量,向量内每个元素都是一个包含4个int型的数组。
向量hierarchy内的元素和轮廓向量contours内的元素是一一对应的,向量的容量相同。hierarchy内每个元素的4个int型变量是hierarchy[i][0] ~ hierarchy[i][3],分别表示当前轮廓 i 的后一个轮廓、前一个轮廓、父轮廓和内嵌轮廓的编号索引。如果当前轮廓没有对应的四者中的其一的话,则相应的hierarchy[i][*]被置为-1。
- mode:轮廓的检测模式,其取值定义如下:
1 | enum RetrievalModes { |
翻译如下:
RETR_EXTERNAL:只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略;
RETR_LIST:检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系。这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1;
RETR_CCOMP:检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层;
RETR_TREE:检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。
RETR_FLOODFILL:官方没有介绍,暂时不知道
- method:轮廓逼近方法,取值定义如下:
1 | enum ContourApproximationModes { |
翻译如下:
CHAIN_APPROX_NONE:获取每个轮廓的每个像素,相邻的两个点的像素位置差不超过1;
CHAIN_APPROX_SIMPLE:压缩水平方向,垂直方向,对角线方向的元素,值保留该方向的重点坐标,如果一个矩形轮廓只需4个点来保存轮廓信息;
CHAIN_APPROX_TC89_L1和CHAIN_APPROX_TC89_KCOS:使用Teh-Chinl链逼近算法中的一种
参考:https://blog.csdn.net/qq_42887760/article/details/86565601
- offset:轮廓相对于原始图像的偏移量。例如:如果这里写Size(-10,-20),最终绘制的轮廓相对原图实际轮廓的位置往左偏移了10个像素,往上偏移了20个像素。如果是Size(10,20),就代表往右偏移10个像素,往下偏移20个像素。
findContours函数另一个重载与该定义唯一的区别是少了hierarchy参数,其他参数及含义都一样,故在此不多赘述。
contourArea、arcLength函数—-面积、周长
contourArea函数—-轮廓面积
函数作用:计算图像轮廓的面积
函数的定义:
1 | double contourArea( InputArray contour, bool oriented = false ); |
参数解释:
- contour:输入轮廓的点集合
- oriented:表示某一个方向上轮廓的的面积值,顺时针或者逆时针,一般选择默认false
arcLength函数—-轮廓长度
函数作用:计算图像轮廓的周长
函数的定义:
1 | double arcLength( InputArray curve, bool closed ); |
参数解释:
- curve:输入轮廓的点集合
- closed:表示曲线是否封闭
approxPolyDP函数—-曲线折线化
函数作用:将曲线或多边形用更少顶点的折现来拟合,即把一个连续光滑曲线折线化
曲线折线化的目的是获得折线顶点个数,进而可以判断出该轮廓大概是什么形状
函数的定义:
1 | void approxPolyDP( |
参数解释:
- curve:Mat类或vector类,2D点集,一般由轮廓线点组成的点集
- approxCurve:输出的折线化后点集
- epsilon:指定的精度,也即是原始曲线与近似曲线之间的最大距离
- closed:若为true,则说明拟合曲线是闭合的;反之,若为false,则不为闭合曲线
drawContours函数—-绘制轮廓
函数作用:绘制已经找到的图像的轮廓
函数的定义:
1 | void drawContours( |
参数解释:
- image:要绘制轮廓的图像
- contours:轮廓线的点集合
- contourIdx:指定要绘制轮廓的编号,如果是负数,则绘制所有的轮廓
- color:轮廓线的颜色,通常用Scalar(blue, green, red)调色
- thickness:轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式
- lineType:线型,取值的定义:
1 | enum LineTypes { |
- hierarchy:关于层级的可选参数,只有绘制部分轮廓时才会用到
- maxLevel:绘制轮廓的最高级别,这个参数只有hierarchy有效的时候才有效
maxLevel=0—–绘制与输入轮廓属于同一等级的所有轮廓即输入轮廓和与其相邻的轮廓
maxLevel=1—–绘制与输入轮廓同一等级的所有轮廓与其子节点
maxLevel=2—–绘制与输入轮廓同一等级的所有轮廓与其子节点以及子节点的子节点 - offset:绘制的轮廓相对于已找到的轮廓位置的偏移量。例如:如果这里写Size(-10,-20),最终绘制的轮廓相对已找到轮廓的位置往左偏移了10个像素,往上偏移了20个像素。如果是Size(10,20),就代表往右偏移10个像素,往下偏移20个像素。
示例
源代码:
1 |
|
运行结果: