【Opencv】图像轮廓

图像轮廓

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.参考文献

【1】OpenCV最新4.1.1官网直击

发布了14 篇原创文章 · 获赞 1 · 访问量 495

猜你喜欢

转载自blog.csdn.net/qq_41741344/article/details/104635518