图像轮廓
文章目录
- 图像轮廓
- 1.图像轮廓绘制原理和流程
- 2.contours和hierarchy含义
- 2.1contours参数解析
- 2.2 hierarchy参数解析
- (1) 结构剖析
- (2) 举例说明
- (3) 举例说明的原图
- 2.3测试代码
- 2.4测试结果展示
- 3.函数原型
- 3.1 findContours
- 3.2 drawContours()
- 4.使用方法
- 5.参考文献
1.图像轮廓绘制原理和流程
图像轮廓轮廓识别和绘制主要使用Opencv的两个函数,findContours()和drawContours()组成,他们的工作机制是,前一个函数在经过二值化以后的图像中搜寻轮廓点,把轮廓点集保存在contours中,把层次关系保存在hierarchy中,这个两个参数的组成,我们后面详细说明。
图像绘制的流程为:
(1)把源图像转换为灰度图
(2)把绘图度进行二值化
(3)使用findContours()函数获取轮廓点集contours和层次关系hierarchy这两个参数。
(4)使用轮廓点集和层次关系这两个参数,使用drawContours()函数进行轮廓绘制。
2.contours和hierarchy含义
2.1contours参数解析
可能很多人都有像我一样的困惑,为什么contours是个两层vector套Point的结构,它定义的时候写做
vector<vector<Point>> contours;
看的出来,contours是个四层的结构,为了更加形象,我们假设可以用四维数组来描述这个变量,contours[0][0][0][0] 。
这四个维度的意思分别为:
(1)第一层次:在一张图片里面,这是第几个轮廓的点集。我们知道,一张照片会有很多个轮廓,所以,第一层描述的就是这是第几个轮廓。
(2)第二层次:第二个层次描述的意思是,这是这个轮廓里面的第几个点。因为一个轮廓是由很多的像素点组成的。
(3)第三个层次:像素点的x坐标
(4)第四个层次:像素点的y坐标
我们获取一幅图的contours,并且进行输出第一个轮廓的点集
cout <<contours[0] << endl;
可以得到这样的点的集合,表示的就是第一个轮廓是由哪些点组成的。
2.2 hierarchy参数解析
(1) 结构剖析
hierarchy用于描述每一个轮廓的层次信息,因为一张图片的轮廓往往具有互相嵌套的特点,所以,需要一个参数来表示这些轮廓的特点。,比如下面这幅图,我用红色画出的区域,就是两个圆(四条轮廓线,包括圆的内径和外径)嵌套的结构。
hierarchy参数具有两层结构,可以表示为类似的n行4列的表格。行数表示第几个轮廓,四列分别表示:
(1)第一列:第i个轮廓的上一个轮廓是谁。如果第i个轮廓没有上一个轮廓,那么第一个位置就标注为-1。
(2)第二列:第i个轮廓的下一个轮廓是谁。如果第i个轮廓没有下一个轮廓,那么第二个位置就标注为-1。
(3)第三列:第i个轮廓的子轮廓是谁。如果第i个轮廓没有子轮廓,第三位置标注为-1
(4)第四列:第i个轮廓的父轮廓是谁。如果第i个轮廓没有父轮廓,第三位置标注为-1
(2) 举例说明
比如,假设有这样一个hierarchy,用表格表示
1 | -1 | -1 | -1 |
3 | 0 | 2 | -1 |
-1 | -1 | -1 | 1 |
含义是:
(1)第0个轮廓(第一行)后面一个同级父轮廓是第1个轮廓,它没有前一个同级父轮廓,第0个轮廓没有外层父轮廓,也不包含内层子轮廓。
(2)第1个轮廓(第二行)后面一个同级父轮廓是第3个轮廓,前面一个同级父轮廓是第0个轮廓,他内层包含轮廓2,没有外层父轮廓
(3)第2个轮廓(第三行)没有前一个父轮廓,也没有前一个子轮廓。(说明这个轮廓属于被别人包含的轮廓),这个轮廓不包含子轮廓,并且被第一个轮廓包围,属于第一个轮廓的子轮廓。
(3) 举例说明的原图
这个hierarchy描述的图形结构为:第0个轮廓独立,第2个轮廓包含于第1个轮廓
三个轮廓一起显示:
第0个轮廓:
第1个轮廓:
第2个轮廓:
2.3测试代码
用于测试hierarchy代码含义的代码和图像放置在这里,如果没有看懂,可以自己进行实验
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
//01读取图片
Mat m = imread("4.jpg",0);
imshow("m", m);
Mat dst = m.clone();
//02对灰度图进行二值化,使用最大类间分割的方法计算阈值,不进行自定义了。
//并且由于图像是黑色线条,白色底,为了能够识别边缘,做了反向的二值化
threshold(dst, dst, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
imshow("dst", dst);
//03初始化显示的图像
Mat n = Mat::zeros(m.cols, m.rows, m.type());
//04定义contours和hierarchy两个参数
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
//05获取这两个参数,这两个函数的使用方法见后文
findContours(dst, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
int index = 0;
//06绘图
for (; index >= 0; index = hierarchy[index][0])
{
Scalar color(rand() & 255, rand() & 255);
drawContours(n, contours, index, color, 1, 8, hierarchy);
}
//07 输出hierarchy
for (int i = 0; i < 10; i++)
{
cout << hierarchy[i] << endl;
}
//09显示最后效果图
imshow("dst1", n);
waitKey(0);
return 0;
}
2.4测试结果展示
(1)原图(4.jpg):
(2)反向的二值化之后:
(3)结果图:
3.函数原型
3.1 findContours
void cv::findContours (
InputArray image,
OutputArrayOfArrays contours,
OutputArray hierarchy,
int mode,
int method,
Point offset = Point()
)
)
第一个参数:输入图像,要求是二值化的灰度图
第二个参数:用来保存图像轮廓的点集,前面已经介绍过,是一个四层嵌套结构
第三个参数:用来保存图像轮廓之间的层级结构,是一个两层嵌套结构
第四个参数:轮廓检索模式,这个模式的选择与hierarchy层级结构显示有关
标志符 | 含义 |
RETR_EXTERNAL | 只检测最外面的结构。即默认hierarchy最后两个参数都是-1 |
RETR_LIST | 轮廓结构没有等级关系 |
RETR_CCOMP | 轮廓结构只有两层关系 |
RETR_TREE | 显示全部的轮廓结构关系,就像这个例子中介绍的那样 |
第五个参数:轮廓近似方法。
3.2 drawContours()
void cv::drawContours (
InputOutputArray image,
InputArrayOfArrays contours,
int contourIdx,
const Scalar & color,
int thickness = 1,
int lineType = LINE_8,
InputArray hierarchy = noArray(),
int maxLevel = INT_MAX,
Point offset = Point()
)
第一个参数:在哪张图片绘图
第二个参数:轮廓点集
第三个参数:绘制第几个点集表示的轮廓。-1表示全画
第四个参数:线条的颜色
第五个参数:线条的宽度,-1表示实心图形
第六个参数:线型
第七个参数:层级结构
第八个参数:轮廓最大等级
第九个参数:轮廓偏移量
4.使用方法
使用举例就按前面所示的代码,这里不重复说明了
5.参考文献