OpenCV DNN C++ 使用 YOLO 模型推理
OpenCV DNN C++ 使用 YOLO 模型推理
引言
YOLO(You Only Look Once)是一种流行的目标检测算法,因其速度快和准确度高而被广泛应用。OpenCV 的 DNN(Deep Neural Networks)模块为我们提供了一个简单易用的 API,用于加载和运行预先训练的深度学习模型。本文将详细介绍如何使用 OpenCV 的 DNN 模块来进行 YOLOv5 的目标检测。
准备工作
确保您已经安装了 OpenCV 和 OpenCV 的 DNN 模块。如果您还没有,可以参照 OpenCV 官方文档来进行安装。
核心代码解析
结构体和类定义
struct DetectResult
{int classId;float score;cv::Rect box;
};class YOLOv5Detector
{
public:void initConfig(std::string onnxpath, int iw, int ih, float threshold);void detect(cv::Mat& frame, std::vector<DetectResult>& result);private:int input_w = 640;int input_h = 640;cv::dnn::Net net;int threshold_score = 0.25;
};
我们定义了一个名为 DetectResult
的结构体,用于存储检测结果,其中包括目标的类别 ID、得分和边界框。
YOLOv5Detector
类提供了两个主要的公共方法:
initConfig
:用于初始化网络模型和一些参数。detect
:用于进行目标检测。
初始化配置
void YOLOv5Detector::initConfig(std::string onnxpath, int iw, int ih, float threshold)
{this->input_w = iw;this->input_h = ih;this->threshold_score = threshold;this->net = cv::dnn::readNetFromONNX(onnxpath);
}
在 initConfig
方法中,我们主要进行了以下操作:
- 设置输入图像的宽度和高度(
input_w
和input_h
)。 - 设置目标检测的置信度阈值(
threshold_score
)。 - 通过
cv::dnn::readNetFromONNX
方法加载预训练的 ONNX 模型。
目标检测
void YOLOv5Detector::detect(cv::Mat& frame, std::vector<DetectResult>& results)
{// 图象预处理 - 格式化操作int w = frame.cols;int h = frame.rows;int _max = std::max(h, w);cv::Mat image = cv::Mat::zeros(cv::Size(_max, _max), CV_8UC3);cv::Rect roi(0, 0, w, h);frame.copyTo(image(roi));float x_factor = image.cols / 640.0f;float y_factor = image.rows / 640.0f;cv::Mat blob = cv::dnn::blobFromImage(image, 1 / 255.0, cv::Size(this->input_w, this->input_h), cv::Scalar(0, 0, 0),true, false);this->net.setInput(blob);cv::Mat preds = this->net.forward();cv::Mat det_output(preds.size[1], preds.size[2], CV_32F, preds.ptr<float>());float confidence_threshold = 0.5;std::vector<cv::Rect> boxes;std::vector<int> classIds;std::vector<float> confidences;for (int i = 0; i < det_output.rows; i++){float confidence = det_output.at<float>(i, 4);if (confidence < 0.45){continue;}cv::Mat classes_scores = det_output.row(i).colRange(5, 8);cv::Point classIdPoint;double score;minMaxLoc(classes_scores, 0, &score, 0, &classIdPoint);// 置信度 0~1之间if (score > this->threshold_score){float cx = det_output.at<float>(i, 0);float cy = det_output.at<float>(i, 1);float ow = det_output.at<float>(i, 2);float oh = det_output.at<float>(i, 3);int x = static_cast<int>((cx - 0.5 * ow) * x_factor);int y = static_cast<int>((cy - 0.5 * oh) * y_factor);int width = static_cast<int>(ow * x_factor);int height = static_cast<int>(oh * y_factor);cv::Rect box;box.x = x;box.y = y;box.width = width;box.height = height;boxes.push_back(box);classIds.push_back(classIdPoint.x);confidences.push_back(score);}}// NMSstd::vector<int> indexes;cv::dnn::NMSBoxes(boxes, confidences, 0.25, 0.45, indexes);for (size_t i = 0; i < indexes.size(); i++){DetectResult dr;int index = indexes[i];int idx = classIds[index];dr.box = boxes[index];dr.classId = idx;dr.score = confidences[index];cv::rectangle(frame, boxes[index], cv::Scalar(0, 0, 255), 2, 8);cv::rectangle(frame, cv::Point(boxes[index].tl().x, boxes[index].tl().y - 20),cv::Point(boxes[index].br().x, boxes[index].tl().y), cv::Scalar(0, 255, 255), -1);results.push_back(dr);}std::ostringstream ss;std::vector<double> layersTimings;double freq = cv::getTickFrequency() / 1000.0;double time = net.getPerfProfile(layersTimings) / freq;ss << "FPS: " << 1000 / time << " ; time : " << time << " ms";putText(frame, ss.str(), cv::Point(20, 40), cv::FONT_HERSHEY_PLAIN, 2.0, cv::Scalar(255, 0, 0), 2, 8);
}
在 detect
方法中,我们进行了以下几个关键步骤:
- 对输入图像进行预处理。
- 使用
cv::dnn::blobFromImage
函数创建一个 4 维 blob。 - 通过
setInput
和forward
方法进行前向传播,得到预测结果。
然后,我们对预测结果进行解析,通过非极大值抑制(NMS)得到最终的目标检测结果。
参考资料
- OpenCV 官方文档
完整代码
#include <fstream>
#include <iostream>
#include <string>
#include <map>
#include <opencv2/opencv.hpp>struct DetectResult
{int classId;float score;cv::Rect box;
};class YOLOv5Detector
{
public:void initConfig(std::string onnxpath, int iw, int ih, float threshold);void detect(cv::Mat& frame, std::vector<DetectResult>& result);private:int input_w = 640;int input_h = 640;cv::dnn::Net net;int threshold_score = 0.25;
};void YOLOv5Detector::initConfig(std::string onnxpath, int iw, int ih, float threshold)
{this->input_w = iw;this->input_h = ih;this->threshold_score = threshold;this->net = cv::dnn::readNetFromONNX(onnxpath);
}void YOLOv5Detector::detect(cv::Mat& frame, std::vector<DetectResult>& results)
{// 图象预处理 - 格式化操作int w = frame.cols;int h = frame.rows;int _max = std::max(h, w);cv::Mat image = cv::Mat::zeros(cv::Size(_max, _max), CV_8UC3);cv::Rect roi(0, 0, w, h);frame.copyTo(image(roi));float x_factor = image.cols / 640.0f;float y_factor = image.rows / 640.0f;cv::Mat blob = cv::dnn::blobFromImage(image, 1 / 255.0, cv::Size(this->input_w, this->input_h), cv::Scalar(0, 0, 0),true, false);this->net.setInput(blob);cv::Mat preds = this->net.forward();cv::Mat det_output(preds.size[1], preds.size[2], CV_32F, preds.ptr<float>());float confidence_threshold = 0.5;std::vector<cv::Rect> boxes;std::vector<int> classIds;std::vector<float> confidences;for (int i = 0; i < det_output.rows; i++){float confidence = det_output.at<float>(i, 4);if (confidence < 0.45){continue;}cv::Mat classes_scores = det_output.row(i).colRange(5, 8);cv::Point classIdPoint;double score;minMaxLoc(classes_scores, 0, &score, 0, &classIdPoint);// 置信度 0~1之间if (score > this->threshold_score){float cx = det_output.at<float>(i, 0);float cy = det_output.at<float>(i, 1);float ow = det_output.at<float>(i, 2);float oh = det_output.at<float>(i, 3);int x = static_cast<int>((cx - 0.5 * ow) * x_factor);int y = static_cast<int>((cy - 0.5 * oh) * y_factor);int width = static_cast<int>(ow * x_factor);int height = static_cast<int>(oh * y_factor);cv::Rect box;box.x = x;box.y = y;box.width = width;box.height = height;boxes.push_back(box);classIds.push_back(classIdPoint.x);confidences.push_back(score);}}// NMSstd::vector<int> indexes;cv::dnn::NMSBoxes(boxes, confidences, 0.25, 0.45, indexes);for (size_t i = 0; i < indexes.size(); i++){DetectResult dr;int index = indexes[i];int idx = classIds[index];dr.box = boxes[index];dr.classId = idx;dr.score = confidences[index];cv::rectangle(frame, boxes[index], cv::Scalar(0, 0, 255), 2, 8);cv::rectangle(frame, cv::Point(boxes[index].tl().x, boxes[index].tl().y - 20),cv::Point(boxes[index].br().x, boxes[index].tl().y), cv::Scalar(0, 255, 255), -1);results.push_back(dr);}std::ostringstream ss;std::vector<double> layersTimings;double freq = cv::getTickFrequency() / 1000.0;double time = net.getPerfProfile(layersTimings) / freq;ss << "FPS: " << 1000 / time << " ; time : " << time << " ms";putText(frame, ss.str(), cv::Point(20, 40), cv::FONT_HERSHEY_PLAIN, 2.0, cv::Scalar(255, 0, 0), 2, 8);
}std::map<int, std::string> classNames = {{0, "-1"}, {1, "0"}, {2, "1"}};int main(int argc, char* argv[])
{std::shared_ptr<YOLOv5Detector> detector = std::make_shared<YOLOv5Detector>();detector->initConfig(R"(D:\AllCodeProjects\best.onnx)", 640, 640, 0.25f);cv::Mat frame = cv::imread(R"(D:\0002.jpg)");std::vector<DetectResult> results;detector->detect(frame, results);for (DetectResult& dr : results){cv::Rect box = dr.box;cv::putText(frame, classNames[dr.classId], cv::Point(box.tl().x, box.tl().y - 10), cv::FONT_HERSHEY_SIMPLEX,.5, cv::Scalar(0, 0, 0));}cv::imshow("OpenCV DNN", frame);cv::waitKey();results.clear();
}
相关文章:
OpenCV DNN C++ 使用 YOLO 模型推理
OpenCV DNN C 使用 YOLO 模型推理 引言 YOLO(You Only Look Once)是一种流行的目标检测算法,因其速度快和准确度高而被广泛应用。OpenCV 的 DNN(Deep Neural Networks)模块为我们提供了一个简单易用的 API࿰…...

第八章 Linux文件系统权限
目录 8.1 文件的一般权限 1.修改文件或目录的权限---chmod命令 2.对于文件和目录,r,w,x有不同的作用: 3.修改文件或目录的所属主和组---chown,chgrp 8.2 文件和目录的特殊权限 三种通过字符描述文件权限 8.3 ACL 权限 1.A…...

XXL-JOB源码梳理——一文理清XXL-JOB实现方案
分布式定时任务调度系统 流程分析 一个分布式定时任务,需要具备有以下几点功能: 核心功能:定时调度、任务管理、可观测日志高可用:集群、分片、失败处理高性能:分布式锁扩展功能:可视化运维、多语言、任…...

java做个qq机器人
前置的条件 机器人是基于mirai框架实现的。根据官方的文档,建议使用openjdk11。 我这里使用的编辑工具是idea2023 在idea中新建一个maven项目,虽然可以使用gradle进行构建,不过我这里由于网络问题没有跑通。 pom.xml <dependency>&l…...

前端 | AjaxAxios模块
文章目录 1. Ajax1.1 Ajax介绍1.2 Ajax作用1.3 同步异步1.4 原生Ajax 2. Axios2.1 Axios下载2.2 Axios基本使用2.3 Axios方法 1. Ajax 1.1 Ajax介绍 Ajax: 全称(Asynchronous JavaScript And XML),异步的JavaScript和XML。 1.2 Ajax作用 …...

高效的ProtoBuf
一、背景 Google ProtoBuf介绍 这篇文章我们讲了怎么使用ProtoBuf进行序列化,但ProtoBuf怎么做到最高效的,它的数据又是如何压缩的,下面先看一个例子,然后再讲ProtoBuf压缩机制。 二、案例 网上有各种序列化方式性能对比&#…...
删除SQL记录
删除记录的方式汇总: 根据条件删除:DELETE FROM tb_name [WHERE options] [ [ ORDER BY fields ] LIMIT n ] 全部删除(表清空,包含自增计数器重置):TRUNCATE tb_namedelete和truncate的区别: d…...

数据结构--》探索数据结构中的字符串结构与算法
本文将带你深入了解串的基本概念、表示方法以及串操作的常见算法。通过深入理解串的相关概念和操作,我们将能够更好地应用它们来解决算法问题。 无论你是初学者还是进阶者,本文将为你提供简单易懂、实用可行的知识点,帮助你更好地掌握串在数据…...

云安全之等级保护详解
等级保护概念 网络安全等级保护,是对信息系统分等级实行安全保护,对信息系统中使用的安全产品实行按等级管理,对信息系统中发生的信息安全事件分等级进行响应、处置。 网络安全等级保护的核心内容是:国家制定统一的政策、标准&a…...
VUE状态持久化,储存动态路由
1. vuex persistPlugin.js 文件 const routerKey "ROUTER_KEY";export default (store) > {// 刷新页面时,存储改变的数据window.addEventListener("beforeunload", () > {localStorage.setItem(routerKey, JSON.stringify(store.stat…...

微信小程序代驾系统源码(含未编译前端,二开无忧) v2.5
简介: 如今有越来越多的人在网上做代驾,打造一个代驾平台,既可以让司机增加一笔额外的收入,也解决了车主酒后不能开发的问题,代驾系统基于微信小程序开发的代驾系统支持一键下单叫代驾,支持代驾人员保证金…...

1797_GNU pdf阅读器evince
全部学习汇总: GreyZhang/g_GNU: After some years I found that I do need some free air, so dive into GNU again! (github.com) 近段时间经历了很多事情,终于想找一点技术上的自由气氛。或许,没有什么比GNU的一些软件探索更适合填充这样的…...

网络-跨域解决
文章目录 前言一、跨域是什么?二、跨域的解决1.JSONP2.前端代理dev环境3.后端设置请求头CORS4.运维nginx代理 总结 前言 本文主要介绍跨域问题介绍并提供了四种解决办法。 一、跨域是什么? 准确的来说是浏览器存在跨域问题,浏览器为了安全考…...

git提交代码的流程
1.拉取代码 当你进入了一家公司就需要拉去公司的代码进行开发,此时你的项目小组长会给你个地址拉代码, git clone 公司项目的地址 此时如果不使用了这个方式拉去代码,拉去的是master分支上的代码,但是很多数的情况下,公司的项目可能会在其它的分支上,因此到公…...

【SpringBoot】配置文件详解
配置文件详解 一. 配置文件作用二. 配置文件的格式1. properties 配置文件说明①. properties 基本语法②. 读取配置⽂件③. properties 缺点 2. yml 配置⽂件说明①. yml 基本语法②. yml 使用进阶 3. properties VS yml 三. 设置不同环境的配置⽂件 一. 配置文件作用 整个项…...
一文讲懂-五险一金
假设在“北京”:这里的数值并不代表任何真实的城市或地区,只是为了说明计算方法。 工资: 月工资为 6000 元。养老保险: 单位比例: 20% 个人比例: 8%医疗保险: 单位比例: 10% 个人比例: 2%失业保险: 单位比例: 2% 个人比例: 0.5%工伤保险: 单位比例: 0.5…...

判断三条边是否构成三角形(Python实现)
组成三角形的三条边a,b,c需满足条件: ab>c ac>b bc>a 已知:三角形任意三条边的长度之和大于第三条边。 解题:定义3个变量a、b、c,让用户输入任意三个数字赋值给三个变量。判断三个变量中是否任意两个之和大于第三个数值。 判断条件之…...

The directory ‘*‘ or its parent directory is not owned by the current user
python安装编译时出现如下错误 The directory /home/admin/.cache/pip/http or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may …...
leetcode做题笔记162. 寻找峰值
峰值元素是指其值严格大于左右相邻值的元素。 给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。 你可以假设 nums[-1] nums[n] -∞ 。 你必须实现时间复杂度为 O(…...
nginx负载转发源请求http/https:X-Forwarded-Proto及nginx中的转发报头
今天在排查服务器的问题时最后定位到服务器因为经过了运维这一层的处理,转发过来的请求不管用户请求的是https还是http,我们的proxy服务器收到的都是80端口上的http。于是联系相关部门了解有没有现成的可用的这样一个字段来获得这个值。公司用的也是标准…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...

【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...

ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]
报错信息:libc.so.6: cannot open shared object file: No such file or directory: #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...