【C++的OpenCV】第十二课-OpenCV图像常用操作(九):找到图像的边界(轮廓)findContours()和drawContours()
创始人
2024-06-01 01:03:36
0

🎉🎉🎉欢迎各位来到小白piao的学习空间!\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}{前言}前言
  • 一、绘制轮廓的方法\color{blue}{一、绘制轮廓的方法}一、绘制轮廓的方法
    • 1.1绘制轮廓的目的\color{green}{1.1 绘制轮廓的目的}1.1绘制轮廓的目的
    • 1.2所使用的基本方法\color{green}{1.2 所使用的基本方法}1.2所使用的基本方法
      • 1.2.1cv::findContours()\color{purple}{1.2.1 cv :: findContours()}1.2.1cv::findContours()
      • 1.2.2cv::drawContours()\color{purple}{1.2.2 cv :: drawContours()}1.2.2cv::drawContours()
    • 1.3实际案例\color{green}{1.3 实际案例}1.3实际案例
    • 1.4彩蛋\color{green}{1.4 彩蛋}1.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.1cv::findContours()\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 >,最外侧的vector存储图片中的所有轮廓,第二个vector存储每个轮廓的数据信息).
      • hierarchy:可选的(这是今天的难点哦)(不选的参考原型二即可)输出的向量容器(例如std::vector),包含有关图像拓扑的信息。它的元素(就是hierarchy中的元素)与轮廓的数量一样多(元素个数 = 轮廓个数)。对于每一个边界contour[i],对应的hierarchy[i]中有四个元素: hierarchy[i][0] , hierarchy[i][1] , hierarchy[i][2] , 和 hierarchy[i][3]的这些元素,会被分别设置成这个轮廓(注意:这些源图像中的轮廓是必须在同一级的!)的上一层轮廓、下一层轮廓、第一个子轮廓、父轮廓的基于0的索引【这个过程就是对源图像中的某个或者所有轮廓进行的拓扑操作】。
      • mode:轮廓检索的模式,详情参见:轮廓检索模式列表
      • method:边界近似的方法,详情参见:轮廓近似方法列表
      • offset:可选的轮廓点的偏移量,这是一个很有用的参数,对于你要分析整张图片上下文中提取出ROI且进行分析的时候。
    • 原型二的参数和原型一中的参数同样的含义

1.2.2cv::drawContours()\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 > contours; //边界容器vector 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又是一个容器,所以这是一个二维容器。
    上图:
    在这里插入图片描述
    所以,这部分干货,你懂了吗?
  • 关于拓扑:
    在这里插入图片描述
    就差不多这个意思,实际上就是轮廓(或者图像)沿四个方向的拓展。(上下里外)

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

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...
修复 爱普生 EPSON L4... L4151 L4153 L4156 L4158 L4163 L4165 L4166 L4168 L4...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...