计算机视觉——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.mzph.cn/web/36106.shtml

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

相关文章

http服务网络请求如何确保数据安全(含python示例源码)

深度学习类文章回顾 【YOLO深度学习系列】图像分类、物体检测、实例分割、物体追踪、姿态估计、定向边框检测演示系统【含源码】 【深度学习】物体检测/实例分割/物体追踪/姿态估计/定向边框/图像分类检测演示系统【含源码】 【深度学习】YOLOV8数据标注及模型训练方法整体流程…

RabbitMQ消息积压比较厉害,然后突然丢弃

RabbitMQ中的消息积压陡降通常表明某些突发事件或操作已经显著减少了队列中的消息数量。这种现象可能由多种原因引起&#xff0c;以下是一些可能的原因及其解释&#xff1a; 消费者处理速度突然增加 原因: 你的消费者&#xff08;消费者应用或服务&#xff09;可能在某个时间点…

FreeRTOS信号量和互斥量

信息量 简介 信号量是一种解决同步问题的机制&#xff0c;可以实现对共享资源的有序访问。 前面介绍的队列(queue)可以用于传输数据&#xff1a;在任务之间、任务和中断之间。 消息队列用于传输多个数据&#xff0c;但是有时候我们只需要传递状态&#xff0c;这个状态值需要用…

计算机网络:408考研|湖科大教书匠|原理参考模型I|学习笔记

系列目录 计算机网络总纲领 计算机网络特殊考点 计算机网络原理参考模型I 计算机网络原理参考模型II 目录 系列目录更新日志数据链路层(Data Link Layer)一、基本概念二、三个重要问题三、 &#x1f31f;点对点协议(PPP, Point-to-Point Protocol)四、 以太网五、802.11 无线局…

股票复盘思路

股票复盘是一个回顾和分析市场及个人交易决策的过程,旨在从过去的表现中学习并优化未来的投资策略。以下是一些基本的股票复盘步骤和关注点: 市场概况回顾: 观察并记录每日市场的整体表现,包括大盘指数涨跌、成交量变化。统计涨停和跌停个股的数量,了解市场情绪和活跃度。…

neo4j端口号不能访问的问题

安装可能出现的问题 访问Neo4j验证失败&#xff08;The client is unauthorized due to authentication failure.&#xff09;大概意思就是说服务器验证失败。 如果你有在浏览器上登录不同的neo4j数据库&#xff0c;很可能是由于缓存没有清理掉导致的。 可以试试无痕浏览来访问…

数据结构-分析期末选择题考点(串、数组)

竹月光中诗世界 松风影里酒生涯 目录 串的常见考法&#xff08;一&#xff09;BF算法 串的常见考法&#xff08;二&#xff09;KMP求 next数组 串的常见考法&#xff08;三&#xff09;串的概念及性质 串的常见考法&#xff08;四&#xff09;给出主串求子串数量 数组的常见…

使用 nvm 管理 Node 版本及 pnpm 安装

文章目录 GithubWindows 环境Mac/Linux 使用脚本进行安装或更新Mac/Linux 环境变量nvm 常用命令npm 常用命令npm 安装 pnpmNode 历史版本 Github https://github.com/nvm-sh/nvm Windows 环境 https://nvm.uihtm.com/nvm.html Mac/Linux 使用脚本进行安装或更新 curl -o- …

探索 Spring Cloud Gateway:构建微服务架构的关键一环

1. 简介 在当今的分布式系统中&#xff0c;微服务架构已经成为了一种流行的架构模式。在微服务架构中&#xff0c;服务被拆分为小型、可独立部署的服务单元&#xff0c;这些服务单元能够通过网络互相通信&#xff0c;形成一个整体的应用系统。然而&#xff0c;随着微服务数量的…

如何在AWS上使用免费的服务器

要在AWS上免费使用的服务器&#xff0c;你可以按照以下步骤操作&#xff1a; &#xff08;1&#xff09;注册AWS账户&#xff1a; 访问AWS官方网站&#xff08;https://aws.amazon.com/cn/&#xff09;&#xff0c;点击右上角的“完成注册”&#xff0c;按照页面提示填写相关…

华为BGP路由实验基础1------用物理口建立对等体

1.用物理口做BGP建立对等体建立BGP连接 实验拓扑&#xff1a; 实验步骤&#xff1a; 1.完成基本配置 sys [Huawei]sys AR1 [AR1]undo in e [AR1]int g0/0/0 [AR1-GigabitEthernet0/0/0]ip add 1.1.1.1 24 [AR1-GigabitEthernet0/0/0]q [AR1] sys [Huawei]sys AR2 [AR2]undo i…

自研Java调度框架或者CTM或者鲁班

在软件开发中&#xff0c;"自研Java调度框架"通常指的是开发者或团队自行设计并实现的一个用于任务调度的系统&#xff0c;而不是使用现成的开源解决方案。这样的框架可以满足特定的业务需求&#xff0c;提供定制化的功能。以下是一些设计和实现自研Java调度框架时可…

【Python】已解决:Python正确安装文字识别库EasyOCR

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;Python正确安装文字识别库EasyOCR 一、分析问题背景 在使用Python进行图像处理和文字识别时&#xff0c;EasyOCR是一个流行的库&#xff0c;它基于PyTorch&…

【算法刷题 | 动态规划14】6.28(最大子数组和、判断子序列、不同的子序列)

文章目录 35.最大子数组和35.1题目35.2解法&#xff1a;动规35.2.1动规思路35.2.2代码实现 36.判断子序列36.1题目36.2解法&#xff1a;动规36.2.1动规思路36.2.2代码实现 37.不同的子序列37.1题目37.2解法&#xff1a;动规37.2.1动规思路37.2.2代码实现 35.最大子数组和 35.1…

Tensorflow Lite移动平台编译

Android平台编译 如果不做定制化操作,我们不需要自己编译TensorFlow Lite Android库。我们可以直接使用位于MavenCentral的TensorFlow Lite AAR。但是在某些情况下,我们需要本地编译TensorFlow Lite。例如,您可能正在构建一个包含operations selected from TensorFlow的自定…

探索机器学习——构建简单的线性回归模型

目录 引言 什么是线性回归&#xff1f; 为什么选择线性回归&#xff1f; 简单性&#xff1a;线性回归模型易于理解和实现。 基础性&#xff1a;它是许多更复杂模型的基础。 应用广泛&#xff1a;在金融、经济、生物统计学等领域有广泛应用。 构建线性回归模型 数据准备…

UNet进行病理图像分割

数据集链接:https://pan.baidu.com/s/1IBe_P0AyHgZC39NqzOxZhA?pwd=nztc 提取码:nztc UNet模型import torch import torch.nn as nnclass conv_block(nn.Module):def __init__(self, ch_in, ch_out):super(conv_block, self).__init__()self.conv = nn.Sequential(nn.Conv2d…

Python-算法编程100例-滑动窗口(入门级)

题目1&#xff1a;最大连续1的个数&#xff08;简单&#xff09; 给定一个二进制数组 nums &#xff0c; 计算其中最大连续 1 的个数。 解答&#xff1a;前缀和双指针 # 给定一个二进制数组 nums &#xff0c; 计算其中最大连续 1 的个数。 from typing import Listclass So…

笔记本电脑为什么可以链接热点,却无法连接WiFi

① 在开始菜单的搜索栏中&#xff0c;输入 cmd 。 ② 右击上方该程序&#xff0c;选择 以管理员身份运行 ③ 输入&#xff1a;nestsh winsock reset ④ 敲击回车&#xff0c;显示如下页面 ⑤ 再输入 ipconfig/flushdns 回车 ⑥ 然后重启电脑&#xff0c;OVER&#xff01;

供应商绩效仪表板:如何高效考察供应商

供应商在提供满足客户需求的商品和服务方面发挥着关键作用&#xff0c;因此企业必须监控和评估其绩效。 在当今快节奏的商业环境中&#xff0c;手动跟踪供应商数据非常耗时&#xff0c;且容易出错。供应商绩效仪表盘这时就派上用场了——这是一种非常有价值的工具&#xff0c;…