OpenCV轮廓相关操作API (C++)
在OpenCV中,轮廓(contours)是图像处理中的一个重要概念,通常用于形状分析、物体检测等任务。OpenCV提供了多种与轮廓相关的API,可以在C++中使用。
一.常用的与轮廓相关的操作及其对应的API函数
1.查找轮廓
findContours 函数用于在二值图像中查找轮廓。
void findContours(InputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset = Point() );
image: 输入的二值图像(通常为灰度图并经过阈值处理)。
contours: 检测到的轮廓,以std::vector<std::vector<Point>>形式存储。
hierarchy: 轮廓的拓扑信息,以std::vector<Vec4i>形式存储。
mode: 轮廓检索模式(如RETR_EXTERNAL, RETR_LIST, RETR_CCOMP, RETR_TREE)。
method: 轮廓逼近方法(如CHAIN_APPROX_SIMPLE, CHAIN_APPROX_TC89_L1, CHAIN_APPROX_TC89_KCOS, CHAIN_APPROX_NONE)。
offset: 可选的轮廓偏移量。
2.绘制轮廓
drawContours 函数用于在图像上绘制轮廓。
void 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() );
image: 输出的图像。
contours: 轮廓,以std::vector<std::vector<Point>>形式存储。
contourIdx: 指定要绘制的轮廓索引,-1表示绘制所有轮廓。
color: 轮廓的颜色。
thickness: 轮廓线的厚度。负值表示填充轮廓。
lineType: 轮廓线的类型。
hierarchy: 可选的轮廓拓扑信息,用于指定绘制的轮廓层次。
maxLevel: 绘制轮廓的最大层次深度。
offset: 可选的轮廓偏移量。
3.轮廓近似
approxPolyDP 函数用于对轮廓进行多边形逼近。
void approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed);
curve: 输入的轮廓。
approxCurve: 输出的逼近多边形。
epsilon: 逼近精度,表示轮廓到逼近多边形的最大距离。
closed: 指示逼近多边形是否闭合。
4.轮廓面积和周长
contourArea 和 arcLength 函数分别用于计算轮廓的面积和周长。
double contourArea(InputArray contour, bool oriented = false);
double arcLength(InputArray curve, bool closed);
contour: 输入的轮廓。
oriented: 当为true时,返回有符号面积(正值表示逆时针方向,负值表示顺时针方向)。
curve: 输入的轮廓或曲线。
closed: 指示曲线是否闭合。
5.轮廓矩
moments 函数用于计算轮廓的矩。
Moments moments(InputArray array, bool binaryImage = false);
array: 输入的轮廓或图像。
binaryImage: 当为true时,假定输入图像为二值图像。
Moments结构体包含各种矩,如m00, m10, m01, m20, m11, m02等,可以用来计算轮廓的几何属性,具体有:
a.空间矩(Spatial Moments)
空间矩是图像像素位置与其灰度值的加权和,它们描述了图像的整体分布。在 cv::Moments 结构体中,空间矩包括:
m00:零阶矩,表示图像的总亮度(或质量)。
m10:一阶矩关于 x 轴的分量,描述了图像在 x 方向上的亮度分布。
m01:一阶矩关于 y 轴的分量,描述了图像在 y 方向上的亮度分布。
m20、m11、m02:二阶矩,分别描述了图像在 x2 方向上的亮度分布。
m30、m21、m12、m03:三阶矩,进一步描述了图像的高阶亮度分布特性。
b.中心矩(Central Moments)
中心矩是相对于图像重心的矩,它们描述了图像形状相对于重心的分布。在 cv::Moments 结构体中,中心矩包括:
mu20、mu11、mu02:二阶中心矩,分别描述了图像形状在 x2 方向上的相对于重心的分布。
mu30、mu21、mu12、mu03:三阶中心矩,进一步描述了图像形状的高阶相对于重心的分布特性。
c.中心归一化矩(Normalized Central Moments)
中心归一化矩是通过将中心矩除以零阶中心矩的适当幂次来得到的,它们具有尺度不变性。在 cv::Moments 结构体中,虽然直接没有列出归一化中心矩的成员变量,
但可以通过中心矩和零阶中心矩(实际上在 cv::Moments 中是 m00,但注意 m00 不是中心矩,这里只是为了说明归一化的概念)来计算得到。
归一化中心矩的一般形式为:
nu_pq = mu_pq / (m00^((p+q)/2 + 1))
其中,nu_pq 表示 p+q 阶归一化中心矩,mu_pq 表示 p+q 阶中心矩,m00 表示零阶矩。
6.获取轮廓的凸包
通过cv::convexHull()获取轮廓的凸包。
void convexHull( InputArray points, OutputArray hull, bool clockwise = false, bool returnPoints = true );
points即输入的二维点集;
hull为输出的二维点集;
clockwise决定出来的轮廓是否为顺时针方向,为true时为顺时针方向;
returnPoints标志,为true时,hull将返回点集,此时为std::vector<cv::Point>类型,为false时,hull将返回返回对应于外壳点的轮廓点的索引。
二.代码示例
1.打开一个图片
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
// 读取图像
cv::Mat src = cv::imread("path_to_image.jpg", cv::IMREAD_GRAYSCALE);
if (src.empty()) {
std::cerr << "Could not open or find the image!" << std::endl;
return -1;
}
// 阈值处理
cv::Mat binary;
cv::threshold(src, binary, 127, 255, cv::THRESH_BINARY);
// 查找轮廓
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(binary, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
// 绘制轮廓
cv::Mat result;
cv::cvtColor(src, result, cv::COLOR_GRAY2BGR);
for (size_t i = 0; i < contours.size(); i++) {
cv::drawContours(result, contours, (int)i, cv::Scalar(0, 255, 0), 2, cv::LINE_8, hierarchy, 0);
}
// 显示结果
cv::imshow("Contours", result);
cv::waitKey(0);
return 0;
}
2.生成一个图像
#include <iostream>
#include <opencv2/opencv.hpp>
int main() {
// 创建一个空白的图像
cv::Mat image = cv::Mat::zeros(300, 300, CV_8UC1); // 单通道8位图像
// 在图像中间画一个白色的圆形作为轮廓
cv::circle(image, cv::Point(150, 150), 50, cv::Scalar(255), -1);
// 查找图像中的轮廓
std::vector<std::vector<cv::Point>> contours;
cv::findContours(image, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
// 计算轮廓的矩
cv::Moments moments = cv::moments(contours[0]);
// 从矩中计算质心
double cx = moments.m10 / moments.m00;
double cy = moments.m01 / moments.m00;
// 计算面积
double area = moments.m00;
// 在图像上标记质心
cv::circle(image, cv::Point(static_cast<int>(cx), static_cast<int>(cy)), 5, cv::Scalar(128), -1);
// 输出质心坐标和面积
std::cout << "Centroid at (" << cx << ", " << cy << ")" << std::endl;
std::cout << "Area: " << area << std::endl;
// 显示图像
cv::imshow("Contour with Centroid", image);
cv::waitKey(0);
return 0;
}
相关文章:
OpenCV轮廓相关操作API (C++)
在OpenCV中,轮廓(contours)是图像处理中的一个重要概念,通常用于形状分析、物体检测等任务。OpenCV提供了多种与轮廓相关的API,可以在C中使用。 一.常用的与轮廓相关的操作及其对应的API函数 1.查找轮廓 findContou…...

[开源]自动化定位建图系统
系统状态机: 效果展示: 1、 机器人建图定位系统-基础重定位,定位功能演示 2、 机器人建图定位系统-增量地图构建,手动回环检测演示 3、敬请期待… 开源链接: 1、多传感器融合里程计 https://gitee.com/li-wenhao-lw…...

linux ansible部署
ansible部署完后,执行报错 # ansible one -i hosts -m ping dataos193 | FAILED! > {"msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add …...

《Rust权威指南》学习笔记(二)
枚举enum 1.枚举的定义和使用如下图所示: 定义时还可以给枚举的成员指定数据类型,例如:enum IpAddr{V4(u8, u8, u8, u8),V6(String),}。枚举的变体都位于标识符的命名空间下,使用::进行分隔。 2.一个特殊的枚举Option࿰…...

Redis内存碎片
什么是内存碎片? 你可以将内存碎片简单地理解为那些不可用的空闲内存。 举个例子:操作系统为你分配了 32 字节的连续内存空间,而你存储数据实际只需要使用 24 字节内存空间,那这多余出来的 8 字节内存空间如果后续没办法再被分配存储其他数…...

Express 加 sqlite3 写一个简单博客
例图: 搭建 命令: 前提已装好node.js 开始创建项目结构 npm init -y package.json:{"name": "ex01","version": "1.0.0","main": "index.js","scripts": {"test": &q…...
正则表达式进阶学习(一):环视、捕获分组与后向引用
一、环视(零宽断言) 理论部分 环视(零宽断言)是一种用于匹配位置而非字符的正则表达式技术。它的核心特点是:不消耗字符,只检查某个位置前后是否符合特定的条件。可以理解为,环视是在匹配前“…...

《Vue3 七》插槽 Slot
插槽可以让组件的使用者来决定组件中的某一块区域到底存放什么元素和内容。 使用插槽: 插槽的使用过程其实就是抽取共性、预留不同。将共同的元素、内容依然留在组件内进行封装;将不同的元素使用 slot 作为占位,让外部决定到底显示什么样的…...

【C++数据结构——线性表】顺序表的基本运算(头歌实践教学平台习题)【合集】
目录😋 任务描述 相关知识 一、线性表的基本概念 二、初始化线性表 三、销毁线性表 四、判定是否为空表 五、求线性表的长度 六、输出线性表 七、求线性表中某个数据元素值 八、按元素值查找 九、插入数据元素 十、删除数据元素 测试说明 通关代码 测…...

Linux C/C++编程-获得套接字地址、主机名称和主机信息
【图书推荐】《Linux C与C一线开发实践(第2版)》_linux c与c一线开发实践pdf-CSDN博客《Linux C与C一线开发实践(第2版)(Linux技术丛书)》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 (jd.com…...
USB kbtab linux 驱动代码
#include <linux/kernel.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/usb/input.h> #include <asm/unaligned.h> /* Pressure-threshold modules param code from */MODULE_AUTHOR(“xxx”); MODULE_DESCRIPTION(“…...

力扣 跳跃游戏
每次更新目标位置时,实际上是在做一个局部的最优选择,选择跳跃能够到达当前目标位置的最远位置。因为每次更新目标位置时,都是基于当前能跳跃到的最远位置,因此最终的结果是全局最优的。 题目 从前往后遍历,更新可以到…...
使用npm 插件[mmdc]将.mmd时序图转换为图片
使用npm 插件[mmdc]将.mmd时序图转换为图片 1. 安装 mmdc2. 转换为图片 可以使用 mmdc (Mermaid CLI)这个工具来将 .mmd 时序图(Mermaid语法描述的时序图)转换为图片,以下是使用步骤: 1. 安装 mmdc 确保…...

ffmpeg 常用命令
更详细请参考ffmpeg手册,下载ffmpegrelease版后在doc中就有,主页面。video filter 参考ffmpeg-filters.html -version -formats -demuxers -protocols -muxers -filters -devices —pix_fmts -codecs -sample_fmts -decoders -layouts -encoders -colors…...
从入门到实战:C 语言 strlen 函数通关指南
文章目录 一、strlen函数简介1. 函数构成2. 参数说明3. 使用示例 二、模拟实现strlen函数(从新手角度逐步升级改进)1. 基础版本(利用循环计数)2. 改进版本(利用指针相减)3. 递归版本(利用递归思…...

npm install --global windows-build-tools --save 失败
注意以下点 为啥下载windows-build-tools,是因为node-sass4.14.1 一直下载不成功,提示python2 没有安装,最终要安装这个,但是安装这个又失败,主要有以下几个要注意的 1、node 版本 14.21.3 不能太高 2、管理员运行 …...

十种基础排序算法(C语言实现,带源码)(有具体排序例子,适合学习理解)
学习了十种常见的排序方法,此文章针对所学的排序方法进行整理(通过C语言完成排序)。 参考内容: https://blog.csdn.net/mwj327720862/article/details/80498455 https://www.runoob.com/w3cnote/ten-sorting-algorithm.html 1. 冒…...

基于fMRI数据计算脑脊液(CSF)与全脑BOLD信号的时间耦合分析
一、前言 笔者之前的文章《基于Dpabi和spm12的脑脊液(csf)分割和提取笔记》,介绍了如何从普通的fMRI数据中提取CSF信号。首先是基础的预处理,包括时间层校正、头动校正,再加上0.01-0.1Hz的带通滤波。接着用SPM12分割出CSF区域,设置一个比较严格的0.9阈值,确保提取的真是…...

实现websocket心跳检测,断线重连机制
WebSocket基础 WebSocket概念 WebSocket是一种革命性的 全双工通信协议 ,构建在TCP之上,旨在简化客户端与服务器之间的数据交换过程。通过单次握手建立持久连接,WebSocket实现了真正的双向实时通信,显著提高了交互效率。这一特性…...

ComfyUI节点安装笔记
AI高速发展,版本更新相当快(11月25日才安装的版本v.0.3.4,27日版本就已经更新到v.0.3.5了),在遇到问题,找到问题原因所在的过程中,ComfyUI版本、python版本、节点对环境版本的依赖,本…...

1、Go语言基础中的基础
摘要:马士兵教育的Go语言基础的视频笔记。 第一章:走进Golang 1.1、Go的SDK介绍 1.2、Go的项目基本目录结构 1.3、HelloWorld 1.4、编译 1.5、执行 1.6、一步到位 1.7、执行流程分析 1.8、语法注意事项 (1)源文件以"go&qu…...
C++单例模式教学指南
C单例模式完整教学指南 📚 目录 [单例模式基础概念][经典单例实现及问题][现代C推荐实现][高级话题:双重检查锁][实战应用与最佳实践][总结与选择指南] 1. 单例模式基础概念 1.1 什么是单例模式? 单例模式(Singleton Pattern&…...

robot_lab——rsl_rl的train.py整体逻辑
文章目录 Go2机器人训练流程详细分析概述1. 训练启动流程1.1 命令行参数解析RSL-RL相关参数组Isaac Sim应用启动参数组 1.2 RL配置1.3 Isaac Sim启动 2. 环境配置加载2.1 Hydra配置系统 3. 环境创建与初始化3.1 Gym环境创建3.2 Manager系统初始化3.2.1 ObservationManager3.2.2…...

LlamaIndex 工作流简介以及基础工作流
什么是工作流? 工作流是一种由事件驱动、基于步骤的应用程序执行流程控制方式。 你的应用程序被划分为多个称为“步骤(Steps)”的部分,这些步骤由“事件(Events)”触发,并且它们自身也会发出事…...
JAVA元编程
一、引言:元编程的本质与 Java 实现 元编程(Metaprogramming)是一种 “操纵程序的程序” 的编程范式,其核心思想是通过代码动态操作代码本身。在 Java 中,元编程主要通过 ** 反射(Reflection)、…...

【论文阅读笔记】万花筒:用于异构多智能体强化学习的可学习掩码
摘要 在多智能体强化学习(MARL)中,通常采用参数共享来提高样本效率。然而,全参数共享的流行方法通常会导致智能体之间的策略同质,这可能会限制从策略多样性中获得的性能优势。为了解决这一关键限制,我们提出…...

Vue基础(14)_列表过滤、列表排序
Array.prototype.filter()【ES5】 filter() 方法创建给定数组一部分的浅拷贝,其包含通过所提供函数实现的测试的所有元素。 语法: filter(callbackFn) filter(callbackFn, thisArg) 参数: callbackFn(回调函数):为数组中的每个元…...

行列式的性质
1 行列式使用如下性质定义 1)单位矩阵行列式值为 1, ,对于任意单位矩阵均成立; 2)当矩阵交换一行后,行列式值改变符号,如置换矩阵的行列式值为 (根据行交换次数决定)&…...

【自动思考记忆系统】demo (Java版)
背景:看了《人工智能》中的一段文章,于是有了想法。想从另一种观点(⭕️)出发,尝试编码,告别传统程序员一段代码解决一个问题的方式。下图是文章原文和我的思考涂鸦✍️,于是想写一个自动思考记…...
ios版本的Tiktok二次安装不上,提示:Unable to Install “TikTok”
问题:Domain: IXUserPresentableErrorDomain Code: 1 Recovery Suggestion: Failed to load Info.plist from bundle at path /private/var/containers/Bundle/Application/E99D86D4-F96E-48F9-86C5-FE095A22E13A/DouyinDev.app/PlugIns/AwemeNotificationService.a…...