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。于是联系相关部门了解有没有现成的可用的这样一个字段来获得这个值。公司用的也是标准…...
Nunchaku FLUX.1 CustomV3镜像免配置:预装ComfyUI+Custom Workflow+LoRA权重一体化方案
Nunchaku FLUX.1 CustomV3镜像免配置:预装ComfyUICustom WorkflowLoRA权重一体化方案 想体验最新的AI绘画模型,但被复杂的安装、配置和模型下载劝退?今天给大家介绍一个“开箱即用”的终极方案——Nunchaku FLUX.1 CustomV3镜像。它把文生图…...
【多模态技术解析】先对齐再融合:动量蒸馏如何重塑视觉与语言表征学习
1. 为什么视觉和语言要先对齐再融合? 想象一下你正在教一个小朋友认识动物。如果先给他看一张猫的图片,再告诉他"这是狗",小朋友肯定会困惑。这就是典型的模态未对齐问题——视觉信息和语言信息没有正确匹配。在多模态AI领域&#…...
3D建模快速上手:零门槛掌握TripoSR AI驱动开源工具
3D建模快速上手:零门槛掌握TripoSR AI驱动开源工具 【免费下载链接】TripoSR 项目地址: https://gitcode.com/GitHub_Trending/tr/TripoSR 在数字创作领域,3D建模曾是专业人士的专属技能,需要掌握复杂的软件操作和几何知识。但今天&a…...
linux-系统函数
Linux 系统函数详解 Linux 系统函数是用户程序与内核交互的底层接口,通过系统调用(syscall)实现。以下是核心分类及典型函数: 1. 文件操作函数 #include <fcntl.h> int open(const char *pathname, int flags, mode_t mode)…...
当BFD不可用时:用华为NQA+静态路由实现低成本链路监测(含ICMP测试例详解)
华为NQA静态路由:低成本链路监测的实战指南 在传统企业网络中,静态路由因其配置简单、资源消耗低的特点,常被用于小型网络或边缘设备互联。但静态路由最大的痛点在于缺乏自动检测机制——当链路出现故障时,管理员往往要等到用户投…...
计算机基础:从半导体到CPU指令执行全解析
1. 从半导体到逻辑门:计算机的物理基础 计算机的核心部件CPU本质上是由无数微小开关组成的精密电路,而这些开关的物理基础就是半导体材料。半导体之所以被称为"半导体",是因为它的导电性介于导体和绝缘体之间。这种特性使得我们可以…...
手机当主力开发机?用Termux配置SSH连接远程服务器的完整流程(附防断连技巧)
手机变身开发终端:Termux全流程SSH配置与移动办公实战 在咖啡厅等朋友时突然需要紧急修复服务器故障,出差途中发现生产环境告警却找不到电脑——这些场景下,你的Android手机完全可以成为救命稻草。Termux这款终端模拟器配合SSH,能…...
高效构建智能媒体库:MetaTube插件全方位应用指南
高效构建智能媒体库:MetaTube插件全方位应用指南 【免费下载链接】jellyfin-plugin-metatube MetaTube Plugin for Jellyfin/Emby 项目地址: https://gitcode.com/gh_mirrors/je/jellyfin-plugin-metatube MetaTube是一款专为Jellyfin和Emby设计的开源元数据…...
ZYNQ双核通信必看:共享内存的Cache一致性处理实战
ZYNQ双核通信中的Cache一致性实战指南 在嵌入式系统开发中,多核处理器间的数据共享一直是开发者面临的挑战之一。Xilinx ZYNQ系列SoC凭借其ARM双核Cortex-A9架构与可编程逻辑的完美结合,为高性能嵌入式应用提供了强大支持。然而,当两个核心需…...
泛微E9开发实战:如何实现跨月份自动计算结束日期(附完整代码)
泛微E9开发实战:跨月份日期计算的工程化解决方案 财务报销周期自动闭合、项目里程碑智能推算、合同履约期限动态生成——这些高频业务场景背后,都藏着一个让泛微E9开发者头疼的日期计算难题。当开始日期遇上月末临界点,简单的天数相加就会引发…...
