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

🎉🎉🎉 欢迎各位来到小白 p i a o 的学习空间! \color{red}{欢迎各位来到小白piao的学习空间!} 欢迎各位来到小白piao的学习空间!🎉🎉🎉


一、绘制轮廓的方法 \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}{持续更新,期待关注!} 持续更新,期待关注!💖💖💖
💖💖💖 持续更新,期待关注! \color{blue}{持续更新,期待关注!} 持续更新,期待关注!💖💖💖
目前已经为大家更新了: \color{green}{目前已经为大家更新了:} 目前已经为大家更新了:

  1. Python基础、中级、高级;
  2. C++数据结构和算法;
  3. Python数据结构和算法;
  4. OpenCV相关内容等重点内容— 我的主页: \color{purple}{我的主页:} 我的主页:我的主页

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

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

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

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
以下是使用 OpenCV 在 C++ 中实现不规则图像轮廓匹配并截取的示例代码: ```cpp #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main(int argc, char** argv) { // 读取原图和模板图 Mat src = imread("src.jpg", IMREAD_COLOR); Mat tpl = imread("tpl.jpg", IMREAD_COLOR); // 灰度化 Mat src_gray, tpl_gray; cvtColor(src, src_gray, COLOR_BGR2GRAY); cvtColor(tpl, tpl_gray, COLOR_BGR2GRAY); // 二值化 Mat src_bin, tpl_bin; threshold(src_gray, src_bin, 0, 255, THRESH_BINARY); threshold(tpl_gray, tpl_bin, 0, 255, THRESH_BINARY); // 寻找轮廓 vector<vector<Point>> src_contours, tpl_contours; vector<Vec4i> src_hierarchy, tpl_hierarchy; findContours(src_bin, src_contours, src_hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE); findContours(tpl_bin, tpl_contours, tpl_hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE); // 找到最佳匹配的轮廓 double max_score = 0; int max_idx = 0; for (size_t i = 0; i < tpl_contours.size(); i++) { double score = matchShapes(tpl_contours[i], src_contours[0], CONTOURS_MATCH_I1, 0); if (score > max_score) { max_score = score; max_idx = i; } } // 截取匹配到的轮廓区域 Rect roi = boundingRect(tpl_contours[max_idx]); Mat result = src(roi); // 显示结果 imshow("src", src); imshow("tpl", tpl); imshow("result", result); waitKey(0); return 0; } ``` 这段代码首先读取原图和模板图,并将它们灰度化和二值化。然后使用 `findContours` 函数寻找二值化后的图像中的轮廓。接下来,对于模板图中的每个轮廓,使用 `matchShapes` 函数计算与原图中轮廓的相似度,并找到最佳匹配的轮廓。最后,使用 `boundingRect` 函数找到匹配到的轮廓边界框,并截取原图中的对应区域作为最终结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白piao

创作不易,支持一下!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值