计算机视觉——OpenCV C++实现凸包

概述

在图像中发现和分析形式是解决大多数计算机视觉问题的技巧之一,获取轮廓是其中之一。对于新手来说,我会将轮廓描述为“仅仅是一条连接所有位于形状边缘上的点的曲线。”

假设我有下面这张手的图像,手的轮廓由绿线表示。红点代表我们将连接起来形成轮廓曲线的点。

我对轮廓的高级数学课程记忆犹新。然而,由于老师从未强调过轮廓在现实世界中的应用,所以很难理解这个主题的重要性。今天,我发现它在计算机视觉中的重要性。

什么是凸包?

一个没有大于180度的内角的物品被称为凸形的。非凸形或凹形是指不是凸形的形状。一个物体的外部或形状被称为外壳。

因此,一个形状或一组点的凸包是紧密围绕这些点或形状的凸形边界。

用外行话来说,一个物体的凸包是能够完全环绕或包裹该物体(或该物体的轮廓)的最小边界。

可以使用多种方法找到凸包。以下是一些最常见的算法及其相关的时间复杂度。输入点的数量为n,而外壳上的点的数量为h。

  • Sklansky (1982) — O(nlogn) (OpenCV使用此算法)
  • 礼物包装,又称Jarvis步进 — O(nh)
  • Graham扫描 — O(nlogn)
  • Chan算法 — O(nlogh)

使用OpenCV实现凸包

  1. 读取输入图像
src = cv::imread(argv[1], cv::IMREAD_GRAYSCALE);
  1. 将输入图像转换为二进制形式

将图像转换为灰度(在读取图像时已经完成)。

通过应用任何模糊算法从图像中去除噪声(这里我使用了高斯模糊)。

然后将图像阈值化,使其成为二进制形式。

cv::GaussianBlur(src, src, cv::Size(3,3), 0); // 应用3x3核的高斯模糊
ShowImg("Image After Applying Blur", src);
const int max_thresh = 255;
const std::string source_window = "Canny ";
cv::createTrackbar("Canny thresh:", source_window, &thresh, max_thresh, thresh_callback);
thresh_callback(0, 0);
cv::waitKey();
return 0;
}

void thresh_callback(int, void*) {
cv::Mat canny_output;
cv::Canny(src, canny_output, thresh, thresh*2);
....

接下来,我们使用OpenCV的findContour函数找到每个图像周围的轮廓。

如果你是新手,你可能会想知道为什么我们不只是使用边缘检测。边缘检测只会提供边缘的位置。

然而,我们对边缘是如何相互连接的感到好奇。findContour找到连接并返回构成轮廓的点列表。

std::vector<std::vector<cv::Point>> contours;
cv::findContours(canny_output, contours, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
....

使用convexHull函数找到凸包

现在我们已经得到了轮廓,我们可以为每个轮廓找到凸包了。可以使用convexHull函数来实现。

std::vector<std::vector<cv::Point>> hull(contours.size());
for (size_t i = 0; i < contours.size(); i++) {
    cv::convexHull(contours[i], hull[i]);
}
....

绘制凸包

最后一步是可视化我们到目前为止发现的凸包。因为凸包本质上是一个轮廓,我们可以使用OpenCV的drawContours函数来创建一个。

cv::Scalar contours_color = cv::Scalar(255,0,0); // 蓝色
cv::Scalar hull_color = cv::Scalar(0,0,255); // 红色
for (size_t i = 0; i < contours.size(); i++) {
    cv::Scalar color = cv::Scalar(rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256));
    cv::drawContours(drawing, contours, (int)i, contours_color);
    cv::drawContours(drawing, hull, (int)i, hull_color);
}
ShowImg("Hull: ", drawing);

输出

应用

  • 从一组点创建边界
  • 我们的面部交换应用程序之前使用了凸包。我们使用凸包根据Dlib发现的面部标记找到面部的边界。
  • 在许多其他应用中,我们可以恢复特征点信息而不是轮廓信息。我们在几种活动照明系统中,如Kinect,恢复了一个灰度深度图,这是一组点的集合。这些点的凸包可以用来找到场景中物体的边界。
  • 避免碰撞
  • 考虑汽车是一组点的集合,多边形(最小集)包含所有这些点。如果凸包可以避开障碍物,那么汽车也应该可以。
  • 找到随机轮廓的交集比找到两个凸多边形的碰撞要计算上更复杂。因此,凸包更适合于碰撞检测和避免。

参考文献

  • OpenCV计算机视觉应用程序编程手册
  • OpenCV 4计算机视觉应用程序编程手册:使用OpenCV和C++构建复杂的计算机视觉应用程序,第4版
  • 现代C++编程手册
  • OpenCV文档

代码

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"

cv::Mat src;
int thresh = 100;
void thresh_callback(int, void);
void ErrorMsg(std::string msg) {
    std::cout << "!! Error !! n";
    std::cout << msg << std::endl;
}
void ShowImg(const std::string windowName, cv::Mat& img) {
    cv::namedWindow(windowName);
    cv::imshow(windowName, img);
}

int main(int argc, char argv[]) {
    if(argc < 1) {
        ErrorMsg("Please Provide Input Imagen");
    }
    src = cv::imread(argv[1], cv::IMREAD_GRAYSCALE);
    if (src.empty()) {
        ErrorMsg("Could not open or find the image!n");
        return -1;
    }
    cv::GaussianBlur(src, src, cv::Size(3,3), 0); // 应用3x3核的高斯模糊
    ShowImg("Image After Applying Blur", src);
    const int max_thresh = 255;
    const std::string source_window = "Canny ";
    cv::createTrackbar("Canny thresh:", source_window, &thresh, max_thresh, thresh_callback);
    thresh_callback(0, 0);
    cv::waitKey();
    return 0;
}

void thresh_callback(int, void) {
    cv::Mat canny_output;
    cv::Canny(src, canny_output, thresh, thresh*2);
    std::vector<std::vector<cv::Point>> contours;
    cv::findContours(canny_output, contours, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
    std::vector<std::vector<cv::Point>> hull(contours.size());
    for (size_t i = 0; i < contours.size(); i++) {
        cv::convexHull(contours[i], hull[i]);
    }
    cv::Mat drawing = cv::Mat::zeros(canny_output.size(), CV_8UC3);
    cv::Scalar contours_color = cv::Scalar(255,0,0); // 蓝色
    cv::Scalar hull_color = cv::Scalar(0,0,255); // 红色
    for (size_t i = 0; i < contours.size(); i++) {
        cv::Scalar color = cv::Scalar(rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256));
        cv::drawContours(drawing, contours, (int)i, contours_color);
        cv::drawContours(drawing, hull, (int)i, hull_color);
    }
    ShowImg("Hull: ", drawing);
}

这里详细介绍了凸包的概念、实现方法以及在计算机视觉中的应用,并提供了C++代码示例。凸包是计算机视觉中一个重要的概念,用于确定一组点或形状的最小凸形边界。

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

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

相关文章

NoSQL之Redis优化

目录 一、Redis 高可用 二、Redis 持久化 1.RDB 持久化 1&#xff09;触发条件 2&#xff09; 执行流程 3&#xff09;启动时加载 2.AOF 持久化 1&#xff09;开启AOF 2&#xff09;执行流程 3&#xff09;启动时加载 3.RDB和AOF的优缺点 三、Redis 性能管理 1.查…

【Dison夏令营 Day 07】用 Python 和 Rich 制作 Wordle克隆(下篇)

在大流行期间&#xff0c;Wordle 在 Twitter 上还算比较流行的一款基于网络的益智游戏&#xff0c;要求玩家每天在六次或更短时间内猜出一个新的五个字母的单词&#xff0c;每个人得到的单词都是一样的。 在本教程中&#xff0c;你将在终端上创建自己的 Wordle 克隆。自 2021 …

分享一款Type C接口USB转2路485模块【带完整原理图】

大家好&#xff0c;我是『芯知识学堂』的SingleYork&#xff0c;今天给大家分享一款很实用的工具–基于Type C接口的USB转2路485模块。 这款模块主芯片采用南京沁恒的CH342F这款芯片&#xff0c;芯片特性如下&#xff1a; 该系列芯片有QFN24和ESSOP10 这2种封装&#xff0c;…

深度网络现代实践 - 深度前馈网络之结构设计篇

序言 深度网络结构设计作为人工智能领域的基石&#xff0c;正引领着技术创新的浪潮。通过模拟人脑神经元间的复杂连接&#xff0c;深度神经网络展现了卓越的特征学习与模式识别能力。随着大数据与计算能力的提升&#xff0c;设计高效、精准且泛化能力强的深度网络结构成为研究…

深度探索“目录名称无效“:原因、解决方案与最佳实践

目录名称无效&#xff1a;现象背后的秘密 在日常使用电脑或移动设备时&#xff0c;我们时常会遇到“目录名称无效”的错误提示&#xff0c;这一提示仿佛是一道无形的屏障&#xff0c;阻断了我们与重要数据的联系。从本质上讲&#xff0c;“目录名称无效”意味着系统无法识别或…

基于正点原子FreeRTOS学习笔记——时间片调度实验

目录 一、时间片调度介绍 二、实验演示 1、宏修改 1.1、滴答定时器宏 1.2、调度器宏 2、实验程序 2.1.1、任务1&#xff0c;任务2不加临界区程序 2.1.2 实验现象 2.2.1、任务1&#xff0c;任务2加临界区程序 2.2.2 实验现象 一、时间片调度介绍 时间片&#xff1a;同…

Golang中defer和return顺序

在Golang中&#xff0c;defer 和 return 的执行顺序是一个重要的特性&#xff0c;它们的执行顺序如下&#xff1a; return语句不是一条单独的语句&#xff0c;实际上&#xff0c;它是由赋值和返回两部分组成的。赋值步骤会先执行&#xff0c;这一步会计算return语句中的表达式…

【后端面试题】【中间件】【NoSQL】MongoDB的配置服务器、复制机制、写入语义和面试准备

MongoDB的配置服务器 引入了分片机制之后&#xff0c;MongoDB启用了配置服务器(config server) 来存储元数据&#xff0c;这些元数据包括分片信息、权限控制信息&#xff0c;用来控制分布式锁。其中分片信息还会被负责执行查询mongos使用。 MongoDB的配置服务器有一个很大的优…

【C语言】const 关键字

在C语言中&#xff0c;const关键字用于定义常量&#xff0c;使得变量的值在其声明之后无法被修改。这可以帮助防止意外修改数据&#xff0c;提高代码的安全性和可读性。以下是有关const关键字的一些详细说明&#xff1a; 基本用法 const int max_value 100;在这个例子中&…

Zynq系列FPGA实现SDI视频编解码+图像缩放,基于GTX高速接口,提供4套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本博已有的FPGA图像缩放方案本方案的无缩放应用本方案在Xilinx--Kintex系列FPGA上的应用 3、详细设计方案设计原理框图SDI 输入设备Gv8601a 均衡器GTX 解串与串化SMPTE SD/HD/3G SDI IP核BT1120转RGB纯V…

FastApi中的常见请求类型

FastApi中的常见请求类型 后端开发语言中&#xff0c;我钟情于node&#xff0c;高效的异步处理真是让我眼前一亮&#xff0c;同时&#xff0c;简单易懂的语法也让我非常倾心 但是但是&#xff0c;因为考虑要写一个深度学习算法的后端接口&#xff0c;所以不得不选用python作为…

容器安全:等保合规性的基石

随着云计算和微服务架构的蓬勃发展&#xff0c;容器技术已经成为现代IT基础设施不可或缺的一部分。在网络安全等级保护制度&#xff08;等保&#xff09;的框架下&#xff0c;容器安全的要求日益凸显&#xff0c;成为等保合规性的基石。本文将深入探讨容器安全在等保中的重要性…

nginx的配置文件

nginx.conf 1、全局模块 worker_processes 1; 工作进程数&#xff0c;设置成服务器内核数的2倍&#xff08;一般不超过8个&#xff0c;超过8个反正会降低性能&#xff0c;4个 1-2个 &#xff09; 处理进程的过程必然涉及配置文件和展示页面&#xff0c;也就是涉及打开文件的…

让围绕数据库构建大模型应用更简单方便--DB-GPT

DB-GPT的目的是构建大模型领域的基础设施&#xff0c;通过开发多模型管理(SMMF)、Text2SQL效果优化、RAG框架以及优化、Multi-Agents框架协作、AWEL(智能体工作流编排)等多种技术能力&#xff0c;让围绕数据库构建大模型应用更简单&#xff0c;更方便。 1 处理流程 DB-GPT系…

问题集锦1

01.inner中使用JwtTokenUtil.getUserCode() 前端调用上传&#xff08;java&#xff09;&#xff0c;上传使用加购 Overridepublic Boolean insertShoppingCart(InsertShoppingCartParamsDto dto) {// 通过userCode,itemCode和supplierCode来判断当前加购人添加到购物车的商品是…

美术馆预约小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;展品信息管理&#xff0c;管理员管理&#xff0c;用户管理&#xff0c;美术馆管理&#xff0c;基础数据管理&#xff0c;论坛管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;美术馆&#xff…

工业路由器与家用路由器的区别

在现代网络环境中&#xff0c;路由器扮演着至关重要的角色。无论是在家庭网络还是在工业网络&#xff0c;选择合适的路由器都至关重要。本文将从多个角度&#xff0c;对工业路由器与家用路由器进行详细比较&#xff0c;帮助您更好地理解二者的区别。 1、安全性 工业路由器&…

API接口测试/Swgger-ui未授权访问

目录 API接口 接口文档 接口测试的方法 单流程 多流程 Swgger-ui未授权访问 在之间的一次面试中面试官问到了API接口测试&#xff0c;我回答的不好&#xff0c;因为自己确实不太会&#xff0c;后面才下去学习了&#xff0c;这里复习和练习一下 API接口 API&#xff08;…

背景图的动效,非常的炫酷,非一般的感觉。

我们都知道在一些展示型项目中&#xff0c;背景图加上动效后&#xff0c;可以立马让整个设计档次提升了&#xff0c;这次带来了一批背景图的动效图&#xff0c;大家看一下。

震惊!张宇强化36讲1200页,暑期强化高效利用指南!

特别喜欢张宇老师的讲课风格 如果你打算跟张宇老师&#xff0c;那么基础——>强化——>冲刺&#xff0c;你应该这么买书&#xff01; 张宇老师25版课程大改版&#xff0c;其中&#xff0c;36讲的变动是最大的&#xff0c;张宇老师25版课程把以往的强化课程前移&#xff0…