当前位置: 首页 > news >正文

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中&#xff0c;轮廓&#xff08;contours&#xff09;是图像处理中的一个重要概念&#xff0c;通常用于形状分析、物体检测等任务。OpenCV提供了多种与轮廓相关的API&#xff0c;可以在C中使用。 一.常用的与轮廓相关的操作及其对应的API函数 1.查找轮廓 findContou…...

[开源]自动化定位建图系统

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

linux ansible部署

ansible部署完后&#xff0c;执行报错 # 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.枚举的定义和使用如下图所示&#xff1a; 定义时还可以给枚举的成员指定数据类型&#xff0c;例如&#xff1a;enum IpAddr{V4(u8, u8, u8, u8),V6(String),}。枚举的变体都位于标识符的命名空间下&#xff0c;使用::进行分隔。 2.一个特殊的枚举Option&#xff0…...

Redis内存碎片

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

Express 加 sqlite3 写一个简单博客

例图&#xff1a; 搭建 命令&#xff1a; 前提已装好node.js 开始创建项目结构 npm init -y package.json:{"name": "ex01","version": "1.0.0","main": "index.js","scripts": {"test": &q…...

正则表达式进阶学习(一):环视、捕获分组与后向引用

一、环视&#xff08;零宽断言&#xff09; 理论部分 环视&#xff08;零宽断言&#xff09;是一种用于匹配位置而非字符的正则表达式技术。它的核心特点是&#xff1a;不消耗字符&#xff0c;只检查某个位置前后是否符合特定的条件。可以理解为&#xff0c;环视是在匹配前“…...

《Vue3 七》插槽 Slot

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

【C++数据结构——线性表】顺序表的基本运算(头歌实践教学平台习题)【合集】

目录&#x1f60b; 任务描述 相关知识 一、线性表的基本概念 二、初始化线性表 三、销毁线性表 四、判定是否为空表 五、求线性表的长度 六、输出线性表 七、求线性表中某个数据元素值 八、按元素值查找 九、插入数据元素 十、删除数据元素 测试说明 通关代码 测…...

Linux C/C++编程-获得套接字地址、主机名称和主机信息

【图书推荐】《Linux C与C一线开发实践&#xff08;第2版&#xff09;》_linux c与c一线开发实践pdf-CSDN博客《Linux C与C一线开发实践&#xff08;第2版&#xff09;&#xff08;Linux技术丛书&#xff09;》(朱文伟&#xff0c;李建英)【摘要 书评 试读】- 京东图书 (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(“…...

力扣 跳跃游戏

每次更新目标位置时&#xff0c;实际上是在做一个局部的最优选择&#xff0c;选择跳跃能够到达当前目标位置的最远位置。因为每次更新目标位置时&#xff0c;都是基于当前能跳跃到的最远位置&#xff0c;因此最终的结果是全局最优的。 题目 从前往后遍历&#xff0c;更新可以到…...

使用npm 插件[mmdc]将.mmd时序图转换为图片

使用npm 插件[mmdc]将.mmd时序图转换为图片 1. 安装 mmdc2. 转换为图片 可以使用 mmdc &#xff08;Mermaid CLI&#xff09;这个工具来将 .mmd 时序图&#xff08;Mermaid语法描述的时序图&#xff09;转换为图片&#xff0c;以下是使用步骤&#xff1a; 1. 安装 mmdc 确保…...

ffmpeg 常用命令

更详细请参考ffmpeg手册&#xff0c;下载ffmpegrelease版后在doc中就有&#xff0c;主页面。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函数&#xff08;从新手角度逐步升级改进&#xff09;1. 基础版本&#xff08;利用循环计数&#xff09;2. 改进版本&#xff08;利用指针相减&#xff09;3. 递归版本&#xff08;利用递归思…...

npm install --global windows-build-tools --save 失败

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

十种基础排序算法(C语言实现,带源码)(有具体排序例子,适合学习理解)

学习了十种常见的排序方法&#xff0c;此文章针对所学的排序方法进行整理&#xff08;通过C语言完成排序&#xff09;。 参考内容&#xff1a; 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是一种革命性的 全双工通信协议 &#xff0c;构建在TCP之上&#xff0c;旨在简化客户端与服务器之间的数据交换过程。通过单次握手建立持久连接&#xff0c;WebSocket实现了真正的双向实时通信&#xff0c;显著提高了交互效率。这一特性…...

ComfyUI节点安装笔记

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

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

抽象类和接口(全)

一、抽象类 1.概念&#xff1a;如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象&#xff0c;这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法&#xff0c;包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中&#xff0c;⼀个类如果被 abs…...

怎么开发一个网络协议模块(C语言框架)之(六) ——通用对象池总结(核心)

+---------------------------+ | operEntryTbl[] | ← 操作对象池 (对象数组) +---------------------------+ | 0 | 1 | 2 | ... | N-1 | +---------------------------+↓ 初始化时全部加入 +------------------------+ +-------------------------+ | …...