opencv之轮廓发现

opencv版本:3.4.7
编译器版本:VS2019

轮廓发现概述(find contour in your image)

  • 轮廓发现是基于图像边缘提取的基础寻找对象轮廓的方法。所以边缘提取的阈值选定会影响最终轮廓发现的结果

相关函数API

在二值图像上发现轮廓 findContoursAPI

void findContours(
    InputOutputArray image, //输入图像,非0图像看做1,0像素保持不变,8bit
	OutputArrayOfArrays contours,//发现全部的轮廓对象
	OutputArray hierarchy, //该图的拓扑结构,可选,该轮廓发现算法是基于图像拓扑结构的实现
	int mode,//轮廓返回的模式
	int method, //发现方法
	Point offset = Point()//轮廓像素位移,默认(0,0)没有位移
	);

参数介绍

  • image:单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过Canny、拉普拉斯等边缘检测算子处理过的二值图像;
  • contoursvector<vector<Point>>类型,是一个向量,并且是一个双重向量,向量内每个元素保存了一组由连续的Point点构成的点的集合的向量,每一组Point点集就是一个轮廓。有多少轮廓,向量contours就有多少元素。
  • hierarchyvector<Vec4i> 类型,Vec4i是Vec<int,4>的别名,即容器内每一个元素都是一个包含了4int型变量的向量,所以从定义上看,hierarchy也是一个向量,向量内每个元素保存了一个包含4int整型的数组。向量hiararchy内的元素和轮廓向量contours内的元素是一一对应的,向量的容量相同。hierarchy向量内每一个元素的4int型变量——hierarchy[i][0] ~hierarchy[i][3],分别表示第i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号。如果当前轮廓没有对应的后一个轮廓、前一个轮廓、父轮廓或内嵌轮廓的话,则hierarchy[i][0] ~hierarchy[i][3]的相应位被设置为默认值-1
  • mode:int类型的,定义轮廓的检索模式:
    • 取值一:CV_RETR_EXTERNAL只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略;
    • 取值二:CV_RETR_LIST 检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1,具体下文会讲到;
    • 取值三:CV_RETR_CCOMP 检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层;
    • 取值四:CV_RETR_TREE, 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。
  • methodint类型,定义轮廓的近似方法:
    • 取值一:CV_CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到contours向量内;
    • 取值二:CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量内,拐点与拐点之间直线段上的信息点不予保留;
    • 取值三和四:CV_CHAIN_APPROX_TC89_L1CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法;
  • Point:偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓点上加上该偏移量,并且Point还可以是负值。

注意事项
显然,从函数名可以看出“寻找轮廓”的意思。我们可以通过边缘检测算法得到边缘二值图或者前景二值图,二值图的边缘像素或者前景像素就可以被看出是由多个轮廓(点集)组成的。函数findContours的作用就是将二值图的边缘像素或者前景像素拆分成多个轮廓,便于分开讨论每一个轮廓,其中参数image代表一张二值图**,contours代表输出的多个轮廓。对于该函数的C++API**,对一个轮廓的描述用vector,那么多个轮廓(多个点集)如何表示呢?即参数contours是什么数据结构呢?在C++API中,用vector<vector>描述多个轮廓,即将多个轮廓存在一个vector中。


绘制轮廓 drawContours函数API

void drawContours(
                  InputOutputArray image,  //输入图像 轮廓将绘制到此图上 
	              InputArrayOfArrays contours, //全部发现的轮廓对象
	              int contourIdx,//轮廓索引号
	              const Scalar& color,//绘制时候的颜色
	              int thickness = 1,//绘制线宽
	              int lineType = 8, //线的类型
	              InputArray hierarchy = noArray(),//拓扑结构图
	              int maxLevel = INT_MAX, //最大层数,0只绘制当前的,1表示绘制当前及其内嵌的轮廓
	              Point offset = Point()//轮廓位移 可选
	              )

参数介绍

  • image: 代表输入的图像矩阵,将轮廓画在该图上;
  • contours:是得到的一系列点的集合,代表多个轮廓;
  • contourIdx:是一个索引,代表绘制contours中的第几个轮廓;
  • color:被填充的颜色,单色可以设置为Scalar(255)等;
  • thickness: 所画Contour的线条粗细,如果该参数值小于0,则表示填充整个轮廓内的区域;
  • lineType: 线的连通性;
  • hierarchy:可选层次信息结构,这里面是findContours所的到的基于Contours的层级信息;
  • maxLevel: 绘制轮廓的最大等级。如果等级为0,绘制单独的轮廓。如果为1,绘制轮廓及在其后的相同的级别下轮廓。如果值为2,所有的轮廓。如果等级为2,绘制所有同级轮廓及所有低一级轮廓,诸此种种。如果值为负数,函数不绘制同级轮廓,但会升序绘制直到级别为abs(max_level)-1的子轮廓
  • offset:照给出的偏移量移动每一个轮廓点坐标.当轮廓是从某些感兴趣区域(ROI)中提取的然后需要在运算中考虑ROI偏移量时,将会用到这个参数。

图像处理流程

  • 输入图像转化为灰度图
  • 使用Canny进行边缘提取,得到二值图
  • 使用findContours寻找轮廓
  • 使用drawContours绘制轮廓

代码演示

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
 
using namespace std;
using namespace cv;

#define PIC_PATH "C:\\pic\\"
#define PIC_NAME "1.jpg"

Mat src;
int threshold_value = 20;
int threshold_max = 255;

void contours_demo(int, void*);
int main() 
{
string pic = string(PIC_PATH) + string(PIC_NAME);
	cout << "原始图片为:"<<pic << endl;

	src = imread(pic);
	if (src.empty()) {
		cout << "图片不存在" << endl;
		return -1;
	}
	namedWindow("原始图片", WINDOW_AUTOSIZE);
	imshow("原始图片", src);

	cvtColor(src, src, COLOR_BGR2GRAY);  //转化为灰度图像

	namedWindow("灰度图像", WINDOW_AUTOSIZE);
	imshow("灰度图像", src);

	createTrackbar("边缘调整", "原始图片", &threshold_value, threshold_max, contours_demo);
	contours_demo(0, 0);
	
	
	waitKey(0);
	destroyAllWindows();
	return 0;
}
 
void contours_demo(int, void*)
{
	Mat canny_output,dst;

	vector<vector<Point>> contourspoints;   //轮廓集合
	vector<Vec4i> hierachy;                 //对应每一个轮廓所对用的层次索引 后一个轮廓 前一个轮廓 父轮廓 内嵌轮廓的索引编号
	Canny(src, canny_output, threshold_value, threshold_value * 2, 3, false);   //边缘处理
	//轮廓查找
	findContours(canny_output, contourspoints, hierachy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
	
	//创建目标图像
	dst = Mat::zeros(src.size(), CV_8UC3);
	
	RNG rng(123456);    //定义一个随机数变量
	for (size_t i = 0; i < contourspoints.size(); i++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));   //定义画笔颜色
		drawContours(dst, contourspoints, i, color, 2, 8, hierachy, 0, Point(0, 0));   //绘制轮廓
	}
	namedWindow("轮廓图", WINDOW_AUTOSIZE);   //显示目标图像
	imshow("轮廓图", dst);
}

执行效果

在这里插入图片描述


参考链接:https://blog.csdn.net/weixin_41695564/article/details/80085012

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,我可以告诉您关于OpenCV图像轮廓的一些信息。 在OpenCV中,图像轮廓是指图像中所有连续的边界点的集合。通过分析图像中的边缘,可以获取到物体的形状和边界信息。您可以使用不同的函数和方法来处理和计算图像轮廓轮廓近似是指根据指定的精度,将轮廓的形状近似为顶点数量较少的其他形状。可以使用函数cv.approxPolyDP()来进行轮廓近似操作。该函数的参数包括输入轮廓、精度和是否闭合等参数。通过调整精度来控制近似的程度。 轮廓的面积是指轮廓所包围区域的面积大小。在OpenCV中,可以使用函数cv.contourArea()或者通过轮廓的矩moments计算得到。前者直接计算轮廓的面积,后者通过计算轮廓的矩来获取面积。 轮廓的周长是指轮廓的边界上所有的像素点的总长度。可以使用函数cv.arcLength()来计算轮廓的周长。 如果想要在图像上绘制轮廓,可以使用函数cv.drawContours()。该函数的参数包括图像轮廓轮廓的索引、颜色和厚度等。通过设置轮廓的索引为-1,可以绘制所有的轮廓。 希望以上信息对您有所帮助。如果您还有其他问题,请随时提问。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Opencv轮廓](https://blog.csdn.net/weixin_44575152/article/details/115332445)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值