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。于是联系相关部门了解有没有现成的可用的这样一个字段来获得这个值。公司用的也是标准…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...