OpenCV 为轮廓创建边界框和圆(62)

news2024/12/23 16:10:49

 返回:OpenCV系列文章目录(持续更新中......)

上一篇:OpenCV检测凸包(61)
下一篇 :OpenCV如何为等值线创建边界旋转框和椭圆(62)

目标

在本教程中,您将学习如何:

  • 使用 OpenCV 函数 cv::boundingRect
  • 使用 OpenCV 函数 cv::minEnclosingCircle

cv::boundingRect 和 cv::minEnclosingCircle 都是 OpenCV 库中常用的图像处理函数,主要用于轮廓绘制和弧形分析等操作。

cv::boundingRect 是一个用于计算轮廓边界的函数,它可以计算由轮廓点定义的矩形边框。该函数的主要思路是,在轮廓点坐标系中寻找最小的水平矩形(或垂直矩形),然后返回该矩形的左上角坐标和宽度、高度等信息。通过 boundingRect 函数,我们可以实现轮廓的外边框计算和绘制操作,使得轮廓分析更加精确和直观。

cv::minEnclosingCircle 则是一个用于计算轮廓最小外接圆的函数,它可以计算由轮廓点定义的最小圆形。该函数的主要思路是,在轮廓点中寻找最小的能包含所有点的圆形,然后返回该圆的圆心和半径信息。通过 minEnclosingCircle 函数,我们可以实现轮廓的最小外接圆计算和绘制,同时也可以实现对弧形、角度等特征的计算和分析。

cv::boundingRect 和 cv::minEnclosingCircle 通常会一起使用。它们可以用于轮廓分析、目标跟踪、形状检测等操作。通过 boundingRect 函数计算轮廓的边框,我们可以确定轮廓的矩形区域,从而实现轮廓的定位和绘制操作;通过 minEnclosingCircle 函数计算轮廓的最小圆形,我们可以确定轮廓的圆形区域,并计算出圆形的特征,从而实现更加精确的轮廓分析和检测。

C++代码

本教程代码如下所示。您也可以从这里下载

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
 
using namespace cv;
using namespace std;
 
Mat src_gray;
int thresh = 100;
RNG rng(12345);
 
void thresh_callback(int, void* );
 
int main( int argc, char** argv )
{
 CommandLineParser parser( argc, argv, "{@input | stuff.jpg | input image}" );
 Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ) );
 if( src.empty() )
 {
 cout << "Could not open or find the image!\n" << endl;
 cout << "usage: " << argv[0] << " <Input image>" << endl;
 return -1;
 }
 
 cvtColor( src, src_gray, COLOR_BGR2GRAY );
 blur( src_gray, src_gray, Size(3,3) );
 
 const char* source_window = "Source";
 namedWindow( source_window );
 imshow( source_window, src );
 
 const int max_thresh = 255;
 createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback );
 thresh_callback( 0, 0 );
 
 waitKey();
 return 0;
}
 
void thresh_callback(int, void* )
{
 Mat canny_output;
 Canny( src_gray, canny_output, thresh, thresh*2 );
 
 vector<vector<Point> > contours;
 findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE );
 
 vector<vector<Point> > contours_poly( contours.size() );
 vector<Rect> boundRect( contours.size() );
 vector<Point2f>centers( contours.size() );
 vector<float>radius( contours.size() );
 
 for( size_t i = 0; i < contours.size(); i++ )
 {
 approxPolyDP( contours[i], contours_poly[i], 3, true );
 boundRect[i] = boundingRect( contours_poly[i] );
 minEnclosingCircle( contours_poly[i], centers[i], radius[i] );
 }
 
 Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
 
 for( size_t i = 0; i< contours.size(); i++ )
 {
 Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );
 drawContours( drawing, contours_poly, (int)i, color );
 rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2 );
 circle( drawing, centers[i], (int)radius[i], color, 2 );
 }
 
 imshow( "Contours", drawing );
}

解释

主要功能相当简单,从注释中我们执行以下操作:

  • 打开图像,将其转换为灰度并模糊以消除噪点。
 CommandLineParser parser( argc, argv, "{@input | stuff.jpg | input image}" );
 Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ) );
 if( src.empty() )
 {
 cout << "Could not open or find the image!\n" << endl;
 cout << "usage: " << argv[0] << " <Input image>" << endl;
 return -1;
 }
 
 cvtColor( src, src_gray, COLOR_BGR2GRAY );
 blur( src_gray, src_gray, Size(3,3) );

  • 创建一个标题为“Source”的窗口,并在其中显示源文件。
 const char* source_window = "Source";
 namedWindow( source_window );
 imshow( source_window, src );
  • 在 “Source”的窗口上创建一个跟踪栏,并为其分配回调函数。通常,回调函数用于对某种信号做出反应,在我们的例子中,它是跟踪栏的状态变化。需要显式一次性调用thresh_callback才能同时显示“轮廓”窗口和“源”窗口。
 const int max_thresh = 255;
 createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback );
 thresh_callback( 0, 0 );

回调函数完成了所有需要的工作。

  • 使用 cv::Canny 检测图像中的边缘。
 Mat canny_output;
 Canny( src_gray, canny_output, thresh, thresh*2 );

  • 查找等值线并将它们保存到向量 contour和hierarchy中
 vector<vector<Point> > contours;
 findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE );
  • 对于每个找到的等值线,我们现在以 +-3 的精度对多边形应用近似值,并指出曲线必须闭合。之后,我们为每个多边形找到一个边界矩形并将其保存到boundRect 。最后,我们为每个多边形找到一个最小封闭圆,并将其保存到center 和 radius向量。
 vector<vector<Point> > contours_poly( contours.size() );
 vector<Rect> boundRect( contours.size() );
 vector<Point2f>centers( contours.size() );
 vector<float>radius( contours.size() );
 
 for( size_t i = 0; i < contours.size(); i++ )
 {
 approxPolyDP( contours[i], contours_poly[i], 3, true );
 boundRect[i] = boundingRect( contours_poly[i] );
 minEnclosingCircle( contours_poly[i], centers[i], radius[i] );
 }

我们找到了我们需要的一切,我们所要做的就是画画。

  • 创建新的无符号 8 位字符垫,填充零。它将包含我们将要制作的所有图纸(矩形和圆形)。
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );

  • 对于每个等值线:选择一种随机颜色,用它绘制轮廓、边界矩形和最小封闭圆。
 for( size_t i = 0; i< contours.size(); i++ )
 {
 Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );
 drawContours( drawing, contours_poly, (int)i, color );
 rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2 );
 circle( drawing, centers[i], (int)radius[i], color, 2 );
 }
  • 显示结果:创建一个新窗口“轮廓”,并在其上显示我们添加到图纸中的所有内容。
 imshow( "Contours", drawing );

结果

在这里:


参考文献:

1、《Creating Bounding boxes and circles for contours》------ Ana Huamán

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

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

相关文章

foobar2000 for Mac:卓越音乐播放器

当您在寻找一款音质卓越、功能丰富的音频播放器时&#xff0c;foobar2000 for Mac无疑是您的首选。它拥有简洁明了的界面设计&#xff0c;易于上手&#xff0c;同时支持多种音频格式&#xff0c;让您无需担心兼容性问题。 foobar2000 for Mac v2.6.4免激活版下载 foobar2000 fo…

P6周人脸识别

一、前期准备 1.设置GPU import torch import torch.nn as nn import torchvision.transforms as transforms import torchvision from torchvision import transforms, datasets import os,PIL,pathlib,warningswarnings.filterwarnings("ignore") #忽…

SQL:NOT IN与NOT EXISTS不等价

在对SQL语句进行性能优化时&#xff0c;经常用到一个技巧是将IN改写成EXISTS&#xff0c;这是等价改写&#xff0c;并没有什么问题。问题在于&#xff0c;将NOT IN改写成NOT EXISTS时&#xff0c;结果未必一样。 目录 一、举例验证二、三值逻辑简述三、附录&#xff1a;用到的S…

SpringBoot自定义定时任务

通常&#xff0c;在我们的项目中需要定时给前台发送一些提示性消息或者我们想要的定时信息&#xff0c;这个时候就需要使用定时任务来实现这一功能&#xff0c;实现也很简单&#xff0c;接下来具体来看看吧~ 简单定时任务 首先&#xff0c;你需要在你的启动类上加上开启定时任…

【人工智能Ⅱ】实验5:自然语言处理实践(情感分类)

实验5&#xff1a;自然语言处理实践&#xff08;情感分类&#xff09; 一&#xff1a;实验目的与要求 1&#xff1a;掌握RNN、LSTM、GRU的原理。 2&#xff1a;学习用RNN、LSTM、GRU网络建立训练模型&#xff0c;并对模型进行评估。 3&#xff1a;学习用RNN、LSTM、GRU网络做…

Photoshop中图像编辑的基本操作

Photoshop中图像编辑的基本操作 Photoshop中调整图像窗口大小Photoshop中辅助工具的使用网格的使用标尺的使用注释工具的使用 Photoshop中置入嵌入式对象Photoshop中图像与画布的调整画布大小的修改画布的旋转图像尺寸的修改 Photoshop中撤销与还原采用快捷键进行撤销与还原采用…

基于MQTT通信开发的失物招领小程序

项目架构设计 这个项目采用前后端分离的方式&#xff0c;重新设计了两条链路来支撑程序的信息获取和传递 前端的小程序页面再启动页面渲染时&#xff0c;直接通过DBAPI从后端数据库获取信息&#xff0c;直接渲染在小程序中项目中给DBAPI的定位是快速从后端获取信息&#xff0…

信息系统项目管理师0087:组织系统(6项目管理概论—6.2项目基本要素—6.2.6组织系统)

点击查看专栏目录 文章目录 6.2.6组织系统1.治理框架2.管理要素3.组织结构类型6.2.6组织系统 项目运行时会受到项目所在的组织结构和治理框架的影响与制约。为有效且高效地开展项目,项目经理需要了解组织内的组织机构及职责分配情况,帮助自己有效地利用其权力、影响力、能力、…

5分钟速通大语言模型(LLM)的发展与基础知识

✍️ 作者&#xff1a;哈哥撩编程&#xff08;视频号同名&#xff09; 博客专家全国博客之星第四名超级个体COC上海社区主理人特约讲师谷歌亚马逊演讲嘉宾科技博主极星会首批签约作者 &#x1f3c6; 推荐专栏&#xff1a; &#x1f3c5; 程序员&#xff1a;职场关键角色通识宝…

【编程题-错题集】chika 和蜜柑(排序 / topK)

牛客对于题目链接&#xff1a;chika和蜜柑 (nowcoder.com) 一、分析题目 排序 &#xff1a;将每个橘⼦按照甜度由高到低排序&#xff0c;相同甜度的橘子按照酸度由低到高排序&#xff0c; 然后提取排序后的前 k 个橘子就好了。 二、代码 1、看题解之前AC的代码 #include <…

ttkbootstrap界面美化系列之PanedWindow(七)

在界面设计中经常用PanedWindow控件来对整个界面进行切割布局&#xff0c;让整个界面看上去有层次感&#xff0c;不至于说杂乱无章。在我之前的文章中有对tkinter的该控件做了详细的介绍&#xff0c;链接如下基于Tkinter的PanedWindow组件进行窗口布局-CSDN博客 本文主要是介绍…

Python-VBA函数之旅-oct函数

目录 一、oct函数的常见应用场景 二、oct函数使用注意事项 三、如何用好oct函数&#xff1f; 1、oct函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a;神奇夜光杯-CSDN博客 一、oct函数的常见应用场景 oc…

批量抓取某电影网站的下载链接

思路&#xff1a; 进入电影天堂首页&#xff0c;提取到主页面中的每一个电影的背后的那个urL地址 a. 拿到“2024必看热片”那一块的HTML代码 b. 从刚才拿到的HTML代码中提取到href的值访问子页面&#xff0c;提取到电影的名称以及下载地址 a. 拿到子页面的页面源代码 b. 数据提…

Linux理解文件操作 文件描述符fd 理解重定向 dup2 缓冲区 C语言实现自己的shell

文章目录 前言一、文件相关概念与操作1.1 open()1.2 close()1.3 write()1.4 read()1.4 写入的时候先清空文件内容再写入1.5 追加&#xff08;a && a&#xff09; 二、文件描述符2.1 文件描述符 fd 0 1 2 的理解2.2 FILE结构体&#xff1a;的源代码 三、深入理解文件描述…

Vue 开发中的一些问题简单记录,Cannot find module ‘webpack/lib/RuleSet‘

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精…

【C语言】项目实践-贪吃蛇小游戏(Windows环境的控制台下)

一.游戏要实现基本的功能&#xff1a; • 贪吃蛇地图绘制 • 蛇吃食物的功能 &#xff08;上、下、左、右方向键控制蛇的动作&#xff09; • 蛇撞墙死亡 • 蛇撞自身死亡 • 计算得分 • 蛇身加速、减速 • 暂停游戏 二.技术要点 C语言函数、枚举、结构体、动态内存管…

【Java探索之旅】内部类 静态、实例、局部、匿名内部类全面解析

文章目录 &#x1f4d1;前言一、内部类1.1 概念1.2 静态内部类1.3 实例内部类1.4 局部内部类1.5 匿名内部类 &#x1f324;️全篇总结 &#x1f4d1;前言 在Java编程中&#xff0c;内部类是一种强大的特性&#xff0c;允许在一个类的内部定义另一个类&#xff0c;从而实现更好的…

Rust web简单实战

一、使用async搭建简单的web服务 1、修改cargo.toml文件添加依赖 [dependencies] futures "0.3" tokio { version "1", features ["full"] } [dependencies.async-std] version "1.6" features ["attributes"]2、搭…

网络攻击(Cyber Attacks)

目录 1.概念 2.分类 3.总结 1.概念 网络攻击&#xff08;Cyber Attacks&#xff0c;也称赛博攻击&#xff09;是指针对计算机信息系统、基础设施、计算机网络或个人计算机设备的&#xff0c;任何类型的进攻动作。对于计算机和计算机网络来说&#xff0c;破坏、揭露、修改、使…

【C++】STL — List的接口讲解 +详细模拟实现

前言&#xff1a; 本章我们将学习STL中另一个重要的类模板list… list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。list的底层是带头双向循环链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xf…