基于C++的OpenCV4入门基础--图像轮廓

  1. 轮廓
    图像轮廓就是图像边界,主要针对二值图像,轮廓就是一系列点的集合

轮廓是一系列相连的像素点组成的曲线,代表了物体的基本外形。轮廓常用于形状分析和物体的检测和识别。

边缘检测根据灰度的突变检测边界,但检测到的边缘通常还是零散的片段,并未构成整体。从背景中分离目标,就要将边缘像素连接构成轮廓。也就是说,轮廓是连续的,边缘不一定都连续。边缘主要是作为图像的特征使用,而轮廓主要用来分析物体的形态。

2,C++ API : findContours 和 drawContours

CV_EXPORTS_W void findContours( InputArray image, OutputArrayOfArrays contours,
                              OutputArray hierarchy, int mode,
                              int method, Point offset = Point());
                              
CV_EXPORTS_W void 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() );

参数说明:

image:原始图像,8 位单通道二值图像
mode: 轮廓检索模式
cv.RETR_EXTERNAL:只检索最外层轮廓
cv.RETR_LIST:检索所有轮廓,不建立任何层次关系
cv.RETR_CCOMP:检索所有轮廓,并将其组织为两层, 顶层是各部分的外部轮廓,次层是内层轮廓
cv.RETR_TREE:检索所有轮廓,并重建嵌套轮廓的完整层次结构
cv.RETR_FLOODFILL:漫水填充法(泛洪填充)
method: 轮廓近似方法
cv.CHAIN_APPROX_NONE:输出轮廓的每个像素点
cv.CHAIN_APPROX_SIMPLE:压缩水平、垂直和斜线,仅保留这些线段的端点
cv.CHAIN_APPROX_TC89_L1:应用 Teh-Chin 链近似算法 L1
cv.CHAIN_APPROX_TC89_KCOS:应用 Teh-Chin 链近似算法 KCOS
contours:检测到的所有轮廓,列表格式,每个轮廓存储为包含边界点坐标 (x,y) 的点向量
列表(LIST)长度为 L,对应于找到的 L 个轮廓,按 0,…L-1 顺序排列
列表中的第 i 个元素是一个形如 (k,1,2) 的 Numpy 数组,表示第 i 个轮廓,k 是第 i 个轮廓的边界点的数量
数组 contours[i] 是构成第 i 个轮廓的各边界点坐标 (x,y) 的点向量
注意边界点的坐标表达形式是 (x,y),而不是 OpenCV 中常用的像素坐标表达形式 (y,x)。
hierarchy:轮廓的层次结构和拓扑信息,是一个形如 (1,k,4) 的 Numpy 数组
k 对应于找到的轮廓数量
hierarchy[0][i] 表示第 i 个轮廓的层次结构,是包含 4个值的数组 [Next, Previous, First Child, Parent],分别代表第 i 个轮廓的同层的后一个轮廓、同层的前一个轮廓、第一个子轮廓、父轮廓的编号
offset:每个轮廓点的偏移量,可选项,
注意事项:

原始图像 image 必须是单通道图像,其中的非 0 像素都被视为 1,因此图像被视为二值图像。在查找轮廓之前,可以使用 threshold、inRange、Canny 等方法从灰度或彩色图像中创建二值图像。
通常将轮廓近似方法 method 设为 CHAIN_APPROX_SIMPLE,对轮廓的水平、垂直和斜线进行压缩,只保留这些线段的端点,因此轮廓是由一系列线段连接而成的闭合曲线。
每一个轮廓都是一个 Numpy 数组,包含对象边界点 (x,y) 的坐标,注意不是 (y,x)。
如果从图像 ROI 中提取轮廓,然后在图像上下文中进行分析,偏移量 offset 将非常有用。
轮廓的层次结构的表达嵌套在顶级数组中,可以使用 hierarchy[0][i] 访问第 i 个轮廓的层次结构元素。
对应于第 i 个轮廓 contours[i],hierarchy [i][0]~hierarchy[i][3] 分别代表它的同层的后一个轮廓、同层的前一个轮廓、第一个子轮廓、父轮廓的编号。

3,用法

//图像轮廓发现
int main(int argc, char** argv) {

	Mat src = imread("F:/code/images/rice.png");
	CV_Assert(!src.empty());
	namedWindow("input", WINDOW_AUTOSIZE);
	imshow("input", src);


	//高斯滤波
	GaussianBlur(src, src, Size(3, 3), 0);

	//得到灰度图
	Mat gray, binary;
	cvtColor(src, gray, COLOR_RGB2GRAY);
	imshow("gray", gray);

	//得到二值图
	threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
	imshow("binary", binary);

	
	//发现轮廓
	vector<vector<Point>> contours;//因为每个contour都是一系列点的集合
	vector<Vec4i> hierarchy;//层次信息
	findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
	
	for (size_t t = 0; t < contours.size(); t++) {
		drawContours(src, contours, -1, Scalar(0, 0, 255), 1, 8);
	}
	imshow("find contours demo", src);
	
	waitKey(0);
	destroyAllWindows();
	return 0;
}

在这里插入图片描述