【C++的OpenCV】第十二课-OpenCV图像常用操作(九):找到图像的边界(轮廓)findContours()和drawContours()

news2024/12/28 5:22:56

🎉🎉🎉 欢迎各位来到小白 p i a o 的学习空间! \color{red}{欢迎各位来到小白piao的学习空间!} 欢迎各位来到小白piao的学习空间!🎉🎉🎉
💖💖💖 持续更新,期待关注! \color{blue}{持续更新,期待关注!} 持续更新,期待关注!💖💖💖

目前已经为大家更新了: \color{green}{目前已经为大家更新了:} 目前已经为大家更新了:

  1. Python基础、中级、高级;
  2. C++数据结构和算法;
  3. Python数据结构和算法;
  4. OpenCV相关内容等重点内容

我的主页: \color{purple}{我的主页:} 我的主页:我的主页


我的资源: \color{purple}{我的资源:} 我的资源:我的资源

  1. IT技术各档次简历模板
  2. 各类项目(企业、毕设)
  3. 数据库安装包(Mysql8.0)
  4. 技能资料(电子书、软考等)


----------------------------------以下为正式内容----------------------------------------

前言 \color{purple}{前言} 前言

        大家通过前边的内容的学习,想必对于图像形态学有了初步的了解,了解原理之后,我们来看一写灵活的应用。今天的实例,可以好好品一品,如果能理解,那么将会对你在轮廓识别这里理解原理!注释就是答案!


前文链接:【C++的OpenCV】第十一课-OpenCV图像常用操作(八):直方图计算(cv.calc())


一、绘制轮廓的方法 \color{blue}{一、绘制轮廓的方法} 一、绘制轮廓的方法

1.1 绘制轮廓的目的 \color{green}{1.1 绘制轮廓的目的} 1.1绘制轮廓的目的

        快速找到图形的边界有助于进行图像或者特定图形的比较工作以及后期一些训练模型中的基本方法的实现,用于后期成熟项目中。在项目中也充分发挥着其作用。

1.2 所使用的基本方法 \color{green}{1.2 所使用的基本方法} 1.2所使用的基本方法

1.2.1 c v : : f i n d C o n t o u r s ( ) \color{purple}{1.2.1 cv :: findContours()} 1.2.1cv::findContours()

  • 函数原型:
// 原型一:
void cv::findContours	(	
							InputArray 	image,
							OutputArrayOfArrays 	contours,
							OutputArray 	hierarchy,
							int 	mode,
							int 	method,
							Point 	offset = Point() 
						)	

// 原型二:
void cv::findContours	(	
							InputArray 	image,
							OutputArrayOfArrays 	contours,
							int 	mode,
							int 	method,
							Point 	offset = Point() 
						)	
  • 函数功能:
            在一个二进制图片中找到轮廓;该函数使用算法240号从二进制(二值0和1)图像中检索轮廓。轮廓是形状分析、物体检测和识别的有用工具。请使用opencv3.2以上的版本!

  • 参数解释:

    • 原型一中:
      • image:要找轮廓的一张8位单通道二进制的源图像,其中非0的像素为1,0像素依旧为0,所以图像被认为是二进制的图像。可以使用compare、inRange、threshold、adaptiveThreshold、Canny等来创建灰度或彩色的二进制图像。如果参数mode等于RETR_COMPRETR_FLOODFILL,则输入也可以是标签的32位整数图像CV_32SC1)。
      • contours: 检测到的轮廓,每一个轮廓视为一个由多个点组成的矢量(vector)容器。 (例如:std::vector<std::vector<cv::Point> >,最外侧的vector存储图片中的所有轮廓,第二个vector存储每个轮廓的数据信息).
      • hierarchy:可选的(这是今天的难点哦)(不选的参考原型二即可)输出的向量容器(例如std::vector<cv::Vec4i>),包含有关图像拓扑的信息。它的元素(就是hierarchy中的元素)与轮廓的数量一样多(元素个数 = 轮廓个数)。对于每一个边界contour[i],对应的hierarchy[i]中有四个元素: hierarchy[i][0] , hierarchy[i][1] , hierarchy[i][2] , 和 hierarchy[i][3]的这些元素,会被分别设置成这个轮廓(注意:这些源图像中的轮廓是必须在同一级的!)的上一层轮廓、下一层轮廓、第一个子轮廓、父轮廓的基于0的索引【这个过程就是对源图像中的某个或者所有轮廓进行的拓扑操作】。
      • mode:轮廓检索的模式,详情参见:轮廓检索模式列表
      • method:边界近似的方法,详情参见:轮廓近似方法列表
      • offset:可选的轮廓点的偏移量,这是一个很有用的参数,对于你要分析整张图片上下文中提取出ROI且进行分析的时候。
    • 原型二的参数和原型一中的参数同样的含义

1.2.2 c v : : d r a w C o n t o u r s ( ) \color{purple}{1.2.2 cv :: drawContours()} 1.2.2cv::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() 
					)	
  • 函数功能:
    绘制轮廓线或者填充轮廓!如果thickness≥0,该函数在图像中绘制轮廓线,如果thickness<0,则填充轮廓所圈定的区域

  • 参数解释:

    • image: 目标图片,即要画轮廓的那个图片
    • contours:所有的轮廓,每个轮廓是一个点容器,所有轮廓被装在一个容器中
    • contourIdx:轮廓索引 i,i > 0时,i是几就画 i 所对应的轮廓,如果 i < 0 就画出所有轮廓
    • color:轮廓线的颜色
    • thickness:轮廓线厚度,如果这个值为负值(例如:thickness=FILLED),则填充轮廓内部
    • lineType:轮廓线的连接方式,参见线条连接样式列表
    • hierarchy:关于层次结构的可选信息。仅当您只想绘制部分轮廓时,才需要此选项(请参见maxLevel)。
    • maxLevel: 绘制轮廓的最大级别。如果为0,则仅绘制指定的轮廓。如果为1,函数将绘制该轮廓和所有嵌套轮廓。如果为2,则函数绘制轮廓、所有嵌套轮廓、所有的嵌套到嵌套轮廓等。此参数仅在有可用hierarchy时考虑。
    • offset:可选轮廓偏移参数。将所有绘制的轮廓移动指定的偏移量=(dx,dy)。

1.3 实际案例 \color{green}{1.3 实际案例} 1.3实际案例

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
using namespace std;
int main( int argc, char** argv )
{
    Mat src = imread("/home/aelx-chen/demo.jpg");
    //初始化一张空图片dst用于存储画轮廓后的结果
    Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3);
    src = src > 1; // 这是一个简单的二进制图像处理的方法,将图像转换为二进制图像。
    imshow( "Source", src ); // 显示源图像
    vector<vector<Point> > contours; //边界容器
    vector<Vec4i> hierarchy;// 层级容器
    findContours( src, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE );
    // 找src的轮廓,拓扑存入hierarchy中,
    //采用“检索所有轮廓并将其组织为两级层次结构。
    //在顶层,有组件的外部边界。在第二层,有洞的边界。
    //如果连接组件的孔内有另一个轮廓,则仍将其置于顶层”的检索模式(RETR_CCOMP),
    //和“压缩水平段、垂直段和对角段,只保留其端点。”的近似方法(CHAIN_APPROX_SIMPLE 简单线性近似)找到轮廓。
    int idx = 0; // 索引从0开始
    //遍历顶层的所有轮廓画轮廓:为什么是顶层?
    //因为找轮廓的方法中的参数RETR_CCOMP决定了找到的轮廓只有两层,
    //所以这个轮廓的上一层就是顶层了(注意,这种模式是指将轮廓拆为两层去检索的模式)。
    for( ; idx >= 0; idx = hierarchy[idx][0] )
    {
        Scalar color( rand()&255, rand()&255, rand()&255 );//随机彩色
        drawContours( dst, contours, idx, color, FILLED, 8, hierarchy );//画轮廓
        // idx就是轮廓的索引(注意这是hierarchy这个容器中的下标,这个容器中存储的是轮廓的拓扑信息,即这个轮廓的上一层、后一层、第一个子轮廓、父轮廓,之所以这样是因为可以关联到contours和hierarachy,很巧妙!【hierarchy这个容器中我们下方使用图解供大家理解】),
    }
    imshow( "Components", dst );
    waitKey(0);
}

1.4 彩蛋 \color{green}{1.4 彩蛋} 1.4彩蛋

  • 关于findContours()中 hierarchy 参数的图解(如果你能认真看到这里,那你对这个画轮廓的原理和图像学相关知识将会非常理解。)
  • hierarchy其实就是一个容器(类似这种:vector<Vec4i>),而Vec4i又是一个容器,所以这是一个二维容器。
    上图:
    在这里插入图片描述
    所以,这部分干货,你懂了吗?
  • 关于拓扑:
    在这里插入图片描述
    就差不多这个意思,实际上就是轮廓(或者图像)沿四个方向的拓展。(上下里外)

💖💖💖 持续更新,期待关注! \color{blue}{持续更新,期待关注!} 持续更新,期待关注!💖💖💖

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

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

相关文章

PMP项目管理项目整合管理

目录1 项目整合管理概述2 制定项目章程3 制定项目管理计划4 指导与管理项目工作5 管理项目知识6 监控项目工作7 实施整体变更控制8 结束项目或阶段1 项目整合管理概述 项目整合管理包括对隶属于项目管理过程组的各种过程和项目管理活动进行识别、定义、组合、统一和协调的各个…

Linux服务器还有漏洞?建议使用 OpenVAS 日常检查!

几乎每天都会有新的系统漏洞产生&#xff0c;系统管理员经常忙于管理服务器&#xff0c;有时候会忽略一些很明显的安全问题。扫描 Linux 服务器以查找安全问题并不是很简单的事情&#xff0c;所以有时候需要借助于一些专门的工具。 OpenVAS 就是这样一种开源工具&#xff0c;它…

Easy Deep Learning——池化层

池化是什么&#xff1f;它有什么作用&#xff1f; 还是草地的场景&#xff0c;把草地分成一块块的网格&#xff0c;数量还是太多了&#xff0c;如何继续简化输入数据呢? 这时候可以只取一块网格中所有的小草的大小形状的平均值或者最大值作为一个输入数据&#xff0c;这样就大…

Tik Tok新手秘籍,做好五点可轻松起号

新手做TikTok需要有一个具体的规划布局&#xff0c;如果没有深思熟虑就上手开始的话&#xff0c;很有可能会导致功亏一篑&#xff0c;甚至是浪费时间。因此&#xff0c;想要做好 TikTok&#xff0c;就必须从最基本的运营细节开始&#xff0c;一步一步来&#xff0c;下面为大家分…

近红外荧光染料修饰氨基IR 825 NH2,IR 825-Amine,IR-825 NH2

IR 825 NH2&#xff0c;IR 825-NH2&#xff0c;IR825 Amine&#xff0c;IR825-Amine&#xff0c;新吲哚菁绿-氨基&#xff0c;荧光染料修饰氨基产品规格&#xff1a;1.CAS号&#xff1a;N/A2.包装规格&#xff1a;10mg&#xff0c;25mg&#xff0c;50mg&#xff0c;包装灵活&am…

数据结构(3)— 线性表之顺序存储详解介绍(含代码)

&#xff08;1&#xff09;博客代码在数据结构代码---GitHub仓库&#xff1b;线性表介绍线性表的基础概念&#xff08;1&#xff09;甲骨文表示&#xff1a;线性表是零个或多个数据元素的有限序列。&#xff08;2&#xff09;线性表&#xff0c;顾名思义&#xff0c;就是说这个…

git | git 2023 详细版

文章目录一、Git命令1.2 设计用户签名1.3 初始化本地库1.4 查看本地库状态1.5 添加至暂存区1.6 从暂存区删除1.7 将暂存区的文件提交到本地库1.8 查看版本信息二、Git分支2.1 查看分支2.2 创建分支2.3 切换分支2.4 合并分支三、GitHub3.1 代码克隆clone3.2 给库取别名3.3 推送本…

【服务器管理】Wordpress服务器内存占用太高(优化方案详解)

简述 在刚刚配置完服务器之后&#xff0c;想着试一试wordpress这个功能&#xff0c;结果打开服务器后台&#xff0c;发现本来就不多的内存被占用了一大半。 我真的服了&#xff0c;我还啥都没干呢&#xff0c;就这么多的内存占用&#xff0c;那之后我开始弄了还得了。因此有必…

masstransit的message几个高级用法

1&#xff09;问题&#xff0c;Class MessageA 基类&#xff0c;Class MessageB继承自MessageA&#xff1b; 用bus.Publish方法本想把有些消息只发给B队列&#xff0c;结果由于其继承关系A队列也获得了消息&#xff1b; 解决方法用send&#xff0c; Uri uri new Uri(RabbitM…

专项攻克——二叉树

文章目录一、二叉树定义、分类二、二叉树的存储结构三、创建二叉树四、遍历方式一、二叉树定义、分类 二叉树&#xff1a;是N个结点的有序集合&#xff0c;该集合或者为空集&#xff0c;或者由一个根节点跟两棵互不相交的、分别称为根节点的左子树或者右子树的二叉树组成。每个…

vue项目打包Gzip压缩,IIS发布

什么是gzip、有何用&#xff1f; gzip是GNUzip的缩写&#xff0c;最早用于UNIX系统的文件压缩。HTTP协议上的gzip编码是一种用来改进web应用程序性能的技术&#xff0c;web服务器和客户端&#xff08;浏览器&#xff09;必须共同支持gzip。目前主流的浏览器&#xff0c;Chrome…

18 个重要的 JavaScript 字符串方法

1. trim()它删除了两侧的空白。ECMAScript 2019 中还包含 trimStart() 和 trimStart() 方法。它们与 trim() 相同&#xff0c;但 trimStart() 和 trimEnd() 分别从字符串的开头和结尾删除空格。2. match()match() 方法返回匹配字符串的数组。3. split()split() 方法将字符串转换…

5大GPU厂商共建 | openKylin社区GPU SIG首次例会召开!

3月8日&#xff0c;openKylin社区GPU SIG首次例会以线上形式召开。此次会议由长沙景美集成电路设计有限公司、摩尔线程智能科技&#xff08;北京&#xff09;有限责任公司、格兰菲智能科技有限公司、象帝先计算技术&#xff08;重庆&#xff09;有限公司等GPU厂商的多位SIG Mai…

JavaScript 中的全部对象

宿主对象&#xff08;host Objects&#xff09;&#xff1a;由 JavaScript 宿主环境提供的对象&#xff0c;它们的行为完全由宿主环境决定。 【 浏览器环境宿主&#xff0c;全局对象window&#xff0c;window 上又有很多属性&#xff0c;如 document。 全局对象 window 上的属…

ROS1学习笔记:tf坐标系广播与监听的编程实现(ubuntu20.04)

参考B站古月居ROS入门21讲&#xff1a;tf坐标系广播与监听的编程实现 基于VMware Ubuntu 20.04 Noetic版本的环境 文章目录一、创建功能包二、创建代码2.1 以C为例2.1.1 配置代码编译规则2.1.2 编译整个工作空间2.1.2 配置环境变量2.1.4 执行代码2.2 以Python为例2.2.1 配置代码…

SD卡通信协议那些事

SD卡通信 SD卡通信协议主要包括物理层、数据传输层和应用层三个部分。 物理层&#xff1a;SD卡使用SPI或SDIO两种物理层协议进行通信。SPI是一种同步串行通信协议&#xff0c;使用4根信号线进行通信&#xff1b;SDIO是一种异步串行通信协议&#xff0c;使用9根信号线进行通信…

[ROC-RK3568-PC] [Firefly-Android] 10min带你了解I2C的使用

&#x1f347; 博主主页&#xff1a; 【Systemcall小酒屋】&#x1f347; 博主追寻&#xff1a;热衷于用简单的案例讲述复杂的技术&#xff0c;“假传万卷书&#xff0c;真传一案例”&#xff0c;这是林群院士说过的一句话&#xff0c;另外“成就是最好的老师”&#xff0c;技术…

做了个springboot接口参数解密的工具,我给它命名为万能钥匙(已上传maven中央仓库,附详细使用说明)

前言&#xff1a;之前工作中做过两个功能&#xff0c;就是之前写的这两篇博客&#xff0c;最近几天有个想法&#xff0c;给它做成一个springboot的start启动器&#xff0c;直接引入依赖&#xff0c;写好配置就能用了 springboot使用自定义注解实现接口参数解密&#xff0c;普通…

什么是UEFI签名认证?UEFI签名有什么好处?

为了防御恶意软件攻击&#xff0c;目前市面上所有电脑设备启动时默认开启安全启动(Secure Boot)模式。安全启动(Secure Boot)是UEFI扩展协议定义的安全标准&#xff0c;可以确保设备只使用OEM厂商信任的软件启动。UEFI签名认证就是对运行在 UEFI 系统下的 efi 驱动和通过 UEFI …

IT行业就业趋势显示:二季度平均月薪超8千

我国的IT互联网行业在近些年来规模迅速扩大&#xff0c;技能和技术水平也明显提升&#xff0c;目前IT互联网行业已经成为社会发展中新型产业的重要组成部分&#xff0c;行业的人才队伍也在不断的发展壮大&#xff0c;选择进入入互联网行业工作的人也越来越多。 根据58同城前段…