OpenCV学习笔记(十七):查找并绘制轮廓:findContours(),drawContours(),approxPolyDP()

OpenCV学习笔记(十七):查找并绘制轮廓:findContours()

1、findContours() 函数

该函数使用Suzuki85算法从二值图像中检索轮廓。轮廓线是一种用于形状分析、目标检测和识别的有效工具。
opencv轮廓检测之FindContours函数算法解释
该函数从二值图像中检索轮廓,并返回检索到的轮廓数。函数将填充指针first_contour。它将包含指向第一个最外层轮廓的指针,如果没有检测到轮廓,则为空(如果图像是完全黑色的)。可以使用h_next和v_next链接从first_contour到达其他轮廓。绘制等值线讨论中的示例说明了如何使用等值线进行连接组件检测。轮廓还可以用于形状分析和对象识别-请参阅OpenCV示例目录中的squares.c。

void findContours(
InputOutputArray image, 		// 要绘制轮廓的图像,8位单通道的图像(256级灰度图)
OutputArrayOfArrays contours, 	// 所有输入的轮廓,找到的轮廓,其中每个轮廓会被存储为vector<Point>,// 所以contours的类型就是vector<vector<Point>>。
OutputArray hierarchy, 			// 层次结构,可选的输出向量,包含关于图像的拓扑结构信息。// 其具有跟轮廓数相同的元素个数,类型为vector<Vec4i>// 后一个轮廓、前一个轮廓、第一个子轮廓、父轮廓的索引编号,如果没有对应项,该值设置为-1
int mode, 						// 检索轮廓的模式分别表示										
int method, 					// 为轮廓的近似办法
Point offset=Point()			// 代表轮廓点的偏移量,可以设置为任意值。
);
==mode==
RETR_EXTERNAL 表示只检测外轮廓    
RETR_LIST 检测的轮廓不建立等级关系    
RETR_CCOMP 建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边 界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。    
RETR_TREE 建立一个等级树结构的轮廓。具体参考contours.c这个demo
==method==
CHAIN_APPROX_NONE 存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
CHAIN_APPROX_SIMPLE 压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS 使用teh-Chinl chain 近似算法		

2、drawContours()函数

该函数使用算法从二值图像中检索轮廓。绘制轮廓线或填充轮廓线。如果厚度≥0,该函数在图像中绘制轮廓轮廓;如果厚度<0,则填充轮廓边界区域。
参考博客:
轮廓的层级关系详解
OpenCV中findcontours函数hierarchy轮廓层级详解

void drawContours(
InputOutputArray image, 		// 要绘制轮廓的图像
InputArrayOfArrays contours, 	// 所有输入的轮廓,每个轮廓被保存成一个point向量(vector<vector<Point>>)
int contourIdx, 				// 指定要绘制轮廓的编号,如果是负数,则绘制所有的轮廓
const Scalar& color, 			// 绘制轮廓所用的颜色
int thickness=1, 				// 绘制轮廓的线的粗细,如果是负数,则轮廓内部被填充(CV_FILLED 填充内部)
int lineType=8, 				// 绘制轮廓的线的连通性(LINE_AA 抗锯齿线形)
InputArray hierarchy=noArray(), 	// 关于层级的可选参数,只有绘制部分轮廓时才会用到(hierarchy=hierarchy,绘制所有轮廓)
int maxLevel=INT_MAX, 			// 绘制轮廓的最高级别,这个参数只有hierarchy有效的时候才有效
Point offset=Point() 			// 代表轮廓点的偏移量,可以设置为任意值
)
==maxLevel==
maxLevel=0,绘制与输入轮廓属于同一等级的所有轮廓即输入轮廓和与其相邻的轮廓
maxLevel=1, 绘制与输入轮廓同一等级的所有轮廓与其子节点。
maxLevel=2,绘制与输入轮廓同一等级的所有轮廓与其子节点以及子节点的子节点

3、approxPolyDP()函数

以指定的精度近似生成多边形曲线。
函数逼近一条曲线或另一条曲线/顶点较少的多边形,使它们之间的距离小于或等于指定的精度。它使用Douglas-Peucker算法

void approxPolyDP(
InputArray curve,			// 输入的点集(存储在std::vector或Mat中的二维点的输入向量)
OutputArray approxCurve, 	// 输出的点集,当前点集是能最小包容指定点集的。draw出来即是一个多边形;
double epsilon, 			// 指定的精度,也即是原始曲线与近似曲线之间的最大距离。
bool closed					// 若为true,则说明近似曲线是闭合的,它的首位都是相连,反之,若为false,则断开。
);

4、示例一:

#include <opencv2/opencv.hpp>using namespace cv;
using namespace std;int main()
{QCoreApplication a(argc, argv);// 1、加载源图像//Mat srcImage = imread( "F:/C++/2. OPENCV 3.1.0/TEST/a.jpg", 1 );Mat srcImage = imread( "F:/C++/2. OPENCV 3.1.0/TEST/test3.png", 1 );if(!srcImage.data ) { printf("读取图片错误,请确定目录下是否有imread函数指定图片存在~! \n"); return false; }cvtColor(srcImage,srcImage,CV_BGR2GRAY);// 2、初始化结果图Mat dstImage = Mat::zeros(srcImage.size(), CV_8UC3);Mat dstImage1 =dstImage.clone();// 3、srcImage取大于阈值119的那部分//threshold(srcImage,srcImage,119,255,THRESH_BINARY);srcImage = srcImage > 119; // 取 阈值大于119imshow( "取阈值后的原始图", srcImage );// 4、定义轮廓和层次结构// 储存所有轮廓(每个轮廓为一个点向量集)// 储存每个轮廓的层次元素,hierarchy[i][0]~hierarchy[i][1] 分别表示后一个、前一个、父轮廓、内嵌轮廓的索引编号vector<vector<Point> > contours;vector<Vec4i> hierarchy;// 5、查找轮廓// RETR_EXTERNAL 表示只检测外轮廓// RETR_LIST 检测的轮廓不建立等级关系// RETR_CCOMP 建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边 界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。// RETR_TREE 建立一个等级树结构的轮廓。具体参考contours.c这个demo// CHAIN_APPROX_NONE 存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1// CHAIN_APPROX_SIMPLE 压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息// CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS 使用teh-Chinl chain 近似算法findContours( srcImage, contours, hierarchy,CV_RETR_CCOMP ,CV_CHAIN_APPROX_SIMPLE );cout<<"轮廓数量:"<<contours.size()<<endl;// 6、遍历所有顶层的轮廓, 以随机颜色绘制出每个连接组件颜色// hierarchy[index][0] 表示该某轮廓点集的后一个轮廓点集 索引号// hierarchy[index][1] 表示该某轮廓点集的前一个轮廓点集 索引号// hierarchy[index][2] 表示该某轮廓点集的第一个子轮廓(内嵌)点集 索引号// hierarchy[index][3] 表示该某轮廓点集的父轮廓点集 索引号for( int index = 0; index >= 0; index = hierarchy[index][0] ) // 绘制轮廓//for( int index = 0; index < contours.size(); index ++ ) // 绘制所有内外轮廓{Scalar color( rand()&255, rand()&255, rand()&255 );drawContours( dstImage, contours, index, color, 1, 8,hierarchy ); //CV_FILLED}//    // 7、检测到的所有轮廓分别用不同颜色画出来
//    for(size_t j=0; j<contours.size(); j++)
//    {
//        Scalar color( rand()&255, rand()&255, rand()&255 ); // 为每个轮廓新建随机颜色
//        for (size_t i = 0; i < contours[j].size(); i++)
//            {
//                // 绘制边缘
//                line(dstImage1, contours[j][i], contours[j][(i + 1) % contours[j].size()], color, 1, 8);
//            }
//    }// 8、显示最后的轮廓图imshow( "轮廓图", dstImage );//imshow( "边缘图", dstImage1 );waitKey(0);return 0;
}

结果:
在这里插入图片描述
在这里插入图片描述
分析:
1)“0轮廓"的下一条轮廓是"1轮廓”;“1轮廓"的下一条"3轮廓”;
2)"2轮廓"和"3轮廓"的下一条没有;
3)"0轮廓"和"2轮廓"上一条是-1表示没有;
4)“1轮廓"的子轮廓是"2轮廓”,其他的轮廓没有子轮廓。(1轮廓包含2轮廓)
5)"0、1、3轮廓"没有父轮廓,说明其为最外层轮廓(且为同级轮廓)
PS:轮廓层次关系 看hierarchy[index][2]和hierarchy[index][3]的值
在这里插入图片描述

5、示例二:

#include <opencv2/opencv.hpp>using namespace cv;
using namespace std;int levels = 3; // 精度等级
Mat img;
RNG g_rng(12345);
vector<vector<Point> > contours,contours0;
vector<Vec4i> hierarchy;int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);// 1、 读取图片img = imread( "F:/C++/2. OPENCV 3.1.0/TEST/face.png", 0 );if(!img.data ) { printf("读取图片错误,请确定目录下是否有imread函数指定图片存在~! \n"); return false; }imshow( "image", img );//       // 绘制6个人脸用于测试
//       // 创建 500*500 单通道矩阵 灰度图
//       Mat img = Mat::zeros(w, w, CV_8UC1);
//       for( int i = 0; i < 6; i++ )
//       {
//           int dx = (i%2)*250 - 30;
//           int dy = (i/2)*150;
//           const Scalar white = Scalar(255);
//           const Scalar black = Scalar(0);
//           if( i == 0 )
//           {
//               for( int j = 0; j <= 10; j++ )
//               {
//                   double angle = (j+5)*CV_PI/21;
//                   line(img, Point(cvRound(dx+100+j*10-80*cos(angle)),
//                       cvRound(dy+100-90*sin(angle))),
//                       Point(cvRound(dx+100+j*10-30*cos(angle)),
//                       cvRound(dy+100-30*sin(angle))), white, 1, 8, 0);
//               }
//           }
//           ellipse( img, Point(dx+150, dy+100), Size(100,70), 0, 0, 360, white, -1, 8, 0 );
//           ellipse( img, Point(dx+115, dy+70), Size(30,20), 0, 0, 360, black, -1, 8, 0 );
//           ellipse( img, Point(dx+185, dy+70), Size(30,20), 0, 0, 360, black, -1, 8, 0 );
//           ellipse( img, Point(dx+115, dy+70), Size(15,15), 0, 0, 360, white, -1, 8, 0 );
//           ellipse( img, Point(dx+185, dy+70), Size(15,15), 0, 0, 360, white, -1, 8, 0 );
//           ellipse( img, Point(dx+115, dy+70), Size(5,5), 0, 0, 360, black, -1, 8, 0 );
//           ellipse( img, Point(dx+185, dy+70), Size(5,5), 0, 0, 360, black, -1, 8, 0 );
//           ellipse( img, Point(dx+150, dy+100), Size(10,5), 0, 0, 360, black, -1, 8, 0 );
//           ellipse( img, Point(dx+150, dy+150), Size(40,10), 0, 0, 360, black, -1, 8, 0 );
//           ellipse( img, Point(dx+27, dy+100), Size(20,35), 0, 0, 360, white, -1, 8, 0 );
//           ellipse( img, Point(dx+273, dy+100), Size(20,35), 0, 0, 360, white, -1, 8, 0 );
//       }// 显示
//       namedWindow( "image", 1 );
//       imshow( "image", img );// 2、提取轮廓findContours( img, contours0, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);// 3、对轮廓进行逼近 获得多边形曲线轮廓向量点集contours.resize(contours0.size());for( size_t k = 0; k < contours0.size(); k++ )approxPolyDP(Mat(contours0[k]), contours[k], 0.1, true);// 4、滑动条调用// 设置轨迹条,控制从-3到3的轮廓等级namedWindow( "contours", 1 );createTrackbar( "levels+3", "contours", &levels, 7, on_trackbar );on_trackbar(0,0);// 初次调用waitKey(0);return a.exec();
}

轮廓控制回调函数

static void on_trackbar(int, void*)
{// 1、创建目标图像Mat cnt_img = Mat::zeros(img.rows, img.cols, CV_8UC3);// 2、处理参数int _levels = levels - 3;// 3、绘制轮廓// _levels <= 0 ? 3 : -1Scalar color = Scalar( g_rng.uniform(0, 255), g_rng.uniform(0,255), g_rng.uniform(0,255) );//任意值drawContours( cnt_img, contours,_levels <= 0 ? 3 : -1, Scalar(128,255,255),1, LINE_AA, hierarchy, std::abs(_levels) ); imshow("contours", cnt_img);
}

结果:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/491120.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

69张图看懂Elon Musk的脑机接口芯片项目

来源&#xff1a;内容由半导体行业观察整理因为制造特斯拉等各种先进科技产品&#xff0c;Elon Musk被誉为地球上最有创新力的人之一。近来&#xff0c;他更是在脑机接口上有了新的突破。据英国《金融时报》18日报道&#xff0c;他旗下的脑机接口初创公司Neuralink&#xff0c;…

C++可重载运算符和不可重载运算符

可重载运算符&#xff1a; 不可重载运算符&#xff1a;

OpenCV学习笔记(十八):凸包,最小包围区域算子:convexHull(),minAreaRect(),minEnclosingTriangle(),minEnclosingCircle()

OpenCV学习笔记&#xff08;十八&#xff09;&#xff1a;凸包&#xff0c;最小包围区域算子&#xff1a;convexHull(),minAreaRect(),minEnclosingTriangle(),minEnclosingCircle() 1、convexHull()函数 计算出图像点集的凸包&#xff0c;根据图像的轮廓点&#xff0c;通过函…

为什么技术进步让我们越来越焦虑不安?

转自&#xff1a;FT中文网技术进步究竟给我们带来了多少货真价实的福利&#xff1f;还是我们只是在忙忙碌碌和变动不居中收获了一些假象而已&#xff1f;“中国是个匆忙的国家。”这是谷歌董事长埃里克•施密特两年多前在中国举行的某个论坛上说的&#xff0c;这句话想必激起了…

OpenCV学习(十九) :图像的矩:moments(),HuMoments()

OpenCV学习(十九) &#xff1a;图像的矩:moments()&#xff0c;HuMoments() 参考博客&#xff1a; 图像的矩特征 Structural Analysis and Shape Descriptors&#xff1a;opencv 形态描述 【图像算法】图像特征&#xff1a;几何不变矩–Hu矩 如何理解概率论的“矩”&#xff1…

全球半导体现状分析

来源&#xff1a;行业报告研究院前景乐观当今科技创新迅猛发展&#xff0c;半导体行业有望持续增长。对半导体行业来说&#xff0c;2019年会相对疲软&#xff0c;但普华永道预计其将在2020年实现复苏并保持繁荣。2018年半导体行业销售总额为4,810亿美元。今后四年&#xff0c;即…

OpenCV学习(二十) :分水岭算法:watershed()

OpenCV学习(二十) &#xff1a;分水岭算法:watershed() 参考博客&#xff1a; OpenCV—分水岭算法 图像处理——分水岭算法 OpenCV学习(7) 分水岭算法(1) Opencv分水岭算法——watershed自动图像分割用法 -牧野- 分水岭算法是一种图像区域分割法&#xff0c;在分割的过程中&a…

人工智能的下一个道德挑战:如何对待动物

来源&#xff1a;爱范儿去年 11 月份&#xff0c;一段关于母熊和它幼崽的视频在网络上传播开来。根据画面中显示&#xff0c;在一片被白雪覆盖的陡峭斜坡上&#xff0c;一头雌性棕熊正带着它的幼崽艰难的攀爬。虽然因为陡峭的坡度和积雪导致小熊一直在打滑&#xff0c;但最终还…

SQLite的使用(二):数据增删改查

SQLiteDatabase 用来管理SQLite数据库的类。SQLiteDatabase新增、修改、删除和查询数据库数据的方法&#xff0c;还可以执行其他常见的数据库管理任务。 方法 描述 (void) execSQL(String sql) 执行一个SQL语句的方法 (long) insert(String table,String nullColumnHack,Co…

OpenCV学习(二十一) :计算图像连通分量:connectedComponents(),connectedComponentsWithStats()

OpenCV学习(二十一) &#xff1a;计算图像连通分量:connectedComponents(),connectedComponentsWithStats() 1、connectedComponents()函数 Connected Components即连通体算法用id标注图中每个连通体&#xff0c;将连通体中序号最小的顶点的id作为连通体的id。如果在图G中&am…

github上只下载部分文件

有时候我们不想在github上下载整个压缩包&#xff0c;因为压缩包可能比较大&#xff0c;而我们只想要其中的代码文件&#xff0c;也就是只想下载部分文件&#xff0c;例如下面这个网页我们只想下载后缀名为py的文件&#xff0c;这可以通过tortoisesvn来完成 https://github.co…

【机器视觉】机器视觉产业链

来源&#xff1a;产业智能官机器视觉&#xff08;Machine Vision&#xff09;指的是通过光学的装置和非接触的传感器自动的接收和处理真实物体的图像&#xff0c;以获得所需信息或控制机器人运动的装置&#xff0c;通俗的说就是应用在工业领域的视觉应用。▲机器视觉系统组成另…

OpenCV学习笔记(十七):图像修补:inpaint()

OpenCV学习笔记&#xff08;十七&#xff09;&#xff1a;图像修补&#xff1a;inpaint() inpaint()函数 使用区域邻域在图像中还原选定区域。 void inpaint( InputArray src, // 表示要修复的图像,8位三通道或三通道 InputArray inpaintMask, // 表示修复模板(掩模)&a…

plt.errorbar画误差曲线

plt.errorbar(x, y, yerrNone, xerrNone, fmt, ecolorNone, elinewidthNone, capsizeNone, capthickNone ) 功能&#xff1a;画误差曲线&#xff0c;也可以用于画置信区间/标准差/方差参数&#xff1a;x&#xff1a;横坐标的值&#xff0c;y&#xff1a;纵坐标的值&#xff0c…

OpenCV学习(二十) :直方图匹配、对比:calcHist(),minMaxLoc(),compareHist()

直方图匹配、对比:calcHist ,minMaxLoc,compareHist1、calcHist()函数2、归一化&#xff1a;normalize()函数3、minMaxLoc()函数4、compareHist()函数5、示例一&#xff1a;H-S彩色图像的色调、饱和度二维直方图绘制6、示例二&#xff1a;灰度值一维直方图绘制7、示例三&#x…

Intel和IBM押重注的神经模态计算,会给行业带来什么样的变化

Intel发布的Pohoiki Beach加速卡&#xff0c;含有64块Loihi芯片来源&#xff1a; 半导体行业观察上周&#xff0c;Intel发布了基于其神经模态&#xff08;neuromorphic&#xff09;计算芯片Loihi的加速卡Pohoiki Beach&#xff0c;该加速卡包含了64块Loihi芯片&#xff0c;共含…

OpenCV学习(二十二) :反向投影:calcBackProject(),mixChannels()

OpenCV学习(二十二) &#xff1a;反向投影:calcHist(),minMaxLoc(),compareHist() 参考博客&#xff1a; 反向投影backproject的直观理解 opencv 反向投影 颜色直方图的计算、显示、处理、对比及反向投影 一、概述 1、官方解释&#xff1a;反向投影是一种记录给定图像中的像…

美国正式宣告将在月球建立永久存在基地

来源&#xff1a;凤凰新闻央视网消息&#xff1a;7月20号是人类首次载人登陆月球50周年纪念日&#xff0c;美国公布了“阿尔忒弥斯计划”的官方标志图案&#xff0c;正式宣告将在月球建立永久存在基地。美国媒体直呼&#xff0c;美国要“占领”月球了。1969年&#xff0c;美国的…

一文看懂5G芯片背后的明争暗斗

来源&#xff1a;鲜枣课堂6月6日工信部正式发放5G商用牌照之后&#xff0c;国内5G网络建设的步伐大幅加快了。越来越多的城市出现了5G基站和5G信号&#xff0c;5G离我们的距离更近了。面对激动人心的5G&#xff0c;我们普通用户最关心的问题&#xff0c;当然是什么时候才能用上…

OpenCV学习(二十三) :模板匹配:matchTemplate(),minMaxLoc()

OpenCV学习(二十三) &#xff1a;模板匹配:matchTemplate() 1、概述 模板匹配是一种最原始、最基本的模式识别方法&#xff0c;研究某一特定对象物的图案位于图像的什么地方&#xff0c;进而识别对象物&#xff0c;这就是一个匹配问题。 它是图像处理中最基本、最常用的匹配方…