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

 返回: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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c++多线程2小时速成

简介 c多线程基础需要掌握这三个标准库的使用&#xff1a;std::thread,std::mutex, andstd::async。 1. Hello, world #include <iostream> #include <thread>void hello() { std::cout << "Hello Concurrent World!\n"; }int main() {std::th…

轻松应对数据恢复挑战:雷神笔记本,不同情况不同策略

在数字化时代&#xff0c;数据无疑是我们生活中不可或缺的一部分。无论是重要的工作文件、珍贵的家庭照片&#xff0c;还是回忆满满的视频&#xff0c;一旦丢失&#xff0c;都可能给我们的生活带来诸多不便。雷神笔记本作为市场上备受欢迎的电脑品牌&#xff0c;用户在使用过程…

ubuntu使用Remmina远程连接Windows桌面

概况 目的&#xff1a; 远程连接公司电脑写一点代码 之前的方案&#xff1a; 安装Win10虚拟机&#xff0c;虚拟机里连接 VPN&#xff0c; 然后用 mstsc 命令连接。 新的方案&#xff1a;连接VPN后&#xff0c; 开启Remmina直接连接远程 Windows 桌面 新方案优点&#xff1a…

分布式锁之-mysql

使用mysql实现分布式锁的方式这里演示两种&#xff1a; 1:基于 MySQL 实现的乐观锁 2:基于 MySQL 实现的悲观锁 数据库脚本 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;-- ---------------------------- -- Table structure for product_stock -- -----------------------…

【Python】机器学习之Sklearn基础教程大纲

机器学习之Sklearn基础教程大纲 1. 引言 机器学习简介Scikit-learn&#xff08;Sklearn&#xff09;库介绍安装和配置Sklearn 2. 数据预处理 2.1 数据加载与查看 - 加载CSV、Excel等格式的数据- 查看数据的基本信息&#xff08;如形状、数据类型等&#xff09;2.2 数据清洗…

Vue 组件间的数据绑定

在Vue组件中&#xff0c;v-model指令可以用来实现双向数据绑定。它用于将组件的属性和父组件中的数据进行双向绑定&#xff0c;使得当属性的值改变时&#xff0c;父组件中的数据也会相应地改变&#xff0c;并且当父组件中的数据改变时&#xff0c;属性的值也会相应地改变。 目…

【软考高项】三十一、成本管理4个过程

一、规划成本管理 1、定义、作用 定义&#xff1a;确定如何估算、预算、管理、监督和控制项目成本的过程作用&#xff1a;在整个项目期间为如何管理项目成本提供指南和方向 应该在项目规划阶段的早期就对成本管理工作进行规划&#xff0c;建立各成本管理过程的基本框架&…

使用docker-compose编排lnmp(dockerfile) 完成Wordpress

实验环境&#xff1a; 在已有docker环境和nginx镜像的基础上进行编排。 1、准备mysql容器目录及文件 2、dockerfile文件内容 3、my.cnf文件内容 4、准备php容器目录及文件 5、dockerfile文件内容 6、准备其他文件 7、编写docker-compose.yml文件 8、Docker Compose环境的实现…

Redisson 分布式锁和同步器

系列文章目录 文章目录 系列文章目录前言前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 redisson 是基于redis的扩展库,使得redis除了应用于缓存以外,还能做队列…

AI学习指南-人工智能概述

欢迎来到人工智能的奇妙世界&#xff01;如果你是初学者&#xff0c;那么你来对地方了。今天&#xff0c;我们将一起探索人工智能&#xff08;AI&#xff09;的基本概念&#xff0c;看看它是如何分类的&#xff0c;它的应用有哪些&#xff0c;以及未来可能的发展方向。准备好了…

Django之单文件上传(以图片为例)

一&#xff0c;创建项目 初始化&#xff0c;数据迁移&#xff0c;创建superuser&#xff0c;创建app等 二&#xff0c;配置settings.py 1&#xff0c;配置数据库&#xff08;本作者使用的mysql&#xff09;&#xff0c;以前文章有提到 2&#xff0c;配置静态文件存放路径 STAT…

Spring Cloud:探索它的核心组件,揭秘微服务生态

Spring Cloud简介 在我们的编程旅程中&#xff0c;我们会遇到各种各样的工具和技术&#xff0c;它们如同繁星般点缀在编程的天空中&#xff0c;而Spring Cloud就是其中一颗明亮的星。那么&#xff0c;什么是Spring Cloud呢&#xff1f; Spring Cloud&#xff0c;是一个基于Spr…

《尿不湿级》STM32 F103C8T6最小系统板搭建(五)BOOT

一、BOOT是什么&#xff1f; 大多数初学者第一次接触BOOT总是对这个词感到不解&#xff0c;从哪冒出一个奇奇怪怪的东西还要接跳线帽&#xff0c;为什么要配置它才能进行串口程序的下载&#xff1f;为什么不正确配置会导致单片机无法正常启动…… boot&#xff0c;及物动词&…

IOS 开发 - block 使用详解

1.Blobk的定义 block的写法相对难记,不必司机应被,只需要在xcode里打出"inlineBlock"--回车, 系统会自动帮你把基础版写法给你匹配出来 //Block的基础声明//等号""之前是blobk的声明,等号“”后面是block的实现/*returnType:返回类型(void、int、String *…

软件无线电系列——数字调制信号的解调算法

微信公众号上线&#xff0c;搜索公众号小灰灰的FPGA,关注可获取相关源码&#xff0c;定期更新有关FPGA的项目以及开源项目源码&#xff0c;包括但不限于各类检测芯片驱动、低速接口驱动、高速接口驱动、数据信号处理、图像处理以及AXI总线等 本节目录 一、数字调制信号的解调…

Shell编程debug

debug调试 debug方法 sh -x显示脚本执行过程set命令设置开始debug和结束debug的位置显示脚本某一部分执行过程&#xff0c;解决复杂脚本故障 示例&#xff1a; sh -x 显示脚本执行过程 set显示脚本的部分执行过程 set -x 开始调试&#xff0c;从这里开始显示脚本的详细执行过…

WebAssembly 入门教程 c++、python编译wasm

WebAssembly 入门 了解 wasm 使用场景&#xff0c;复杂对象传递和经验法则。 简介 WebAssembly 是一种新的编码方式&#xff0c;可以在现代的网络浏览器中运行。它是一种低级的类汇编语言&#xff0c;具有紧凑的二进制格式&#xff0c;可以接近原生的性能运行&#xff0c;并…

Docker入门篇来啦~

文章目录 1虚拟化技术1.1 硬件级虚拟化1.2 操作系统级虚拟化 2 Docker是什么2.1 Docker介绍2.2 容器和虚拟机的区别2.3 为什么使用Docker 3 Docker运行环境部署3.1 Docker安装3.2 Docker服务启动 4 Docker核心组件4.1 镜像4.1.1 镜像的基本概念4.1.2 镜像的组成结构4.1.3 镜像的…

上位机图像处理和嵌入式模块部署(树莓派4b使用lua)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 lua是一个脚本语言&#xff0c;比c语言开发容易&#xff0c;也没有python那么重&#xff0c;整体使用还是非常方便的。一般当成胶水语言进行开发&a…

Linux基础指令001

名称日期版本说明作者了解并熟练运用Linux基础指令2024/05/04v0.0.1汇总篇lgb 一&#xff0c;了解Linux,并安装 Linux是一套免费使用和自由传播的类Unix操作系统&#xff0c;是一个多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协…