使用onnxruntime c++ API实现yolov5m视频检测

@[使用onnxruntime c++ API实现yolov5m视频检测]

本文演示了yolov5m从模型导出到onnxruntime推理的过程

一.创建容器

docker run --shm-size=32g -ti  --privileged --net=host \--rm \-v $PWD:/home -w /home ghcr.io/intel/llvm/ubuntu2204_base /bin/bash

二.安装依赖

apt install libopencv-dev -y
wget https://github.com/microsoft/onnxruntime/releases/download/v1.19.2/onnxruntime-linux-x64-1.19.2.tgz
tar -xf onnxruntime-linux-x64-1.19.2.tgz

三.生成onnx模型

rm yolov5 -rf
git clone https://github.com/ultralytics/yolov5.git
cd yolov5
pip install -r requirements.txt
wget https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m.pt
python export.py --weights yolov5m.pt --include onnx --img 640
mv yolov5m.onnx ../
cd ..

四.生成类别名

tee gen_names.py<<-'EOF'
import yaml
data=yaml.safe_load(open("yolov5/data/coco.yaml","r"))
with open("coco.names","w") as f:for name in list(data['names'].values()):f.write(f"{name}\n")
EOF
python gen_names.py

五.运行测试程序

tee yolov5_onnxruntime.cpp<<-'EOF'
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <opencv2/opencv.hpp>
#include <onnxruntime_cxx_api.h>using namespace std;
using namespace cv;// NMS参数
float confThreshold = 0.25; // 置信度阈值
float nmsThreshold = 0.45;  // NMS 阈值
int inpWidth = 640;         // 网络输入宽度
int inpHeight = 640;        // 网络输入高度// COCO 数据集类别名称
vector<string> classes;// 加载类别名称
void loadClasses(const string& classesFile) {ifstream ifs(classesFile.c_str());string line;while (getline(ifs, line)) {classes.push_back(line);}
}// 后处理,解析模型输出并进行NMS
void postprocess(const Mat& frame, const vector<vector<Mat>>& outputs);// 自定义 NMSBoxes 函数
void NMSBoxesCustom(const vector<Rect>& boxes, const vector<float>& scores, float scoreThreshold, float nmsThreshold, vector<int>& indices);int main(int argc, char** argv) {// 检查参数if (argc != 4) {cout << "用法: ./yolov5_onnxruntime <yolov5.onnx> <classes.names> <input.mp4>" << endl;return -1;}string model_path = argv[1];string classesFile = argv[2];string video_path = argv[3];// 加载类别名称loadClasses(classesFile);// 初始化 ONNX Runtime 环境Ort::Env env(OrtLoggingLevel::ORT_LOGGING_LEVEL_WARNING, "YoloV5");Ort::SessionOptions session_options;session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);// 如果需要使用GPU,需要启用CUDA// OrtCUDAProviderOptions cuda_options;// session_options.AppendExecutionProvider_CUDA(cuda_options);// 创建会话printf("%s\n",model_path.c_str());Ort::Session session(env, model_path.c_str(), session_options);// 获取输入输出节点信息Ort::AllocatorWithDefaultOptions allocator;// 输入节点size_t num_input_nodes = session.GetInputCount();printf("num_input_nodes:%d\n",num_input_nodes);vector<const char*> input_node_names(num_input_nodes);vector<int64_t> input_node_dims;for (int i = 0; i < num_input_nodes; i++) {// 获取输入节点名Ort::AllocatedStringPtr input_name = session.GetInputNameAllocated(i, allocator);printf("input_name:%s\n",input_name.get());input_node_names[i] = strdup(input_name.get());// 获取输入节点维度Ort::TypeInfo type_info = session.GetInputTypeInfo(i);auto tensor_info = type_info.GetTensorTypeAndShapeInfo();input_node_dims = tensor_info.GetShape();}// 输出节点size_t num_output_nodes = session.GetOutputCount();printf("num_output_nodes:%d\n",num_output_nodes);vector<const char*> output_node_names(num_output_nodes);for (int i = 0; i < num_output_nodes; i++) {Ort::AllocatedStringPtr output_name = session.GetOutputNameAllocated(i, allocator);printf("output_name:%s\n",output_name.get());output_node_names[i] = strdup(output_name.get());}// 打开视频文件VideoCapture cap(video_path);if (!cap.isOpened()) {cerr << "无法打开视频文件!" << endl;return -1;}Mat frame;while (cap.read(frame)) {// 图像预处理Mat img;resize(frame, img, Size(inpWidth, inpHeight));cvtColor(img, img, COLOR_BGR2RGB);img.convertTo(img, CV_32F, 1.0 / 255.0);// 转换为CHW格式vector<float> img_data;int channels = img.channels();int img_h = img.rows;int img_w = img.cols;img_data.resize(channels * img_h * img_w);vector<Mat> chw;for (int i = 0; i < channels; ++i) {Mat channel(img.rows, img.cols, CV_32FC1, img_data.data() + i * img_h * img_w);chw.push_back(channel);}split(img, chw);// 创建输入张量array<int64_t, 4> input_shape{1, channels, img_h, img_w};size_t input_tensor_size = img_data.size();Ort::Value input_tensor = Ort::Value::CreateTensor<float>(allocator.GetInfo(), img_data.data(), input_tensor_size, input_shape.data(), input_shape.size());// 进行推理auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_node_names.data(), &input_tensor, 1, output_node_names.data(), num_output_nodes);// 解析输出vector<vector<Mat>> outputs;for (auto& tensor : output_tensors) {float* output_data = tensor.GetTensorMutableData<float>();auto type_info = tensor.GetTensorTypeAndShapeInfo();vector<int64_t> output_shape = type_info.GetShape();// 将输出数据转换为 Matint rows = output_shape[1];int dimensions = output_shape[2];Mat output = Mat(rows, dimensions, CV_32F, output_data);// 将输出添加到列表outputs.push_back({output});}// 后处理postprocess(frame, outputs);// 显示结果imwrite("Detection.jpg", frame);break;}cap.release();destroyAllWindows();return 0;
}void postprocess(const Mat& frame, const vector<vector<Mat>>& outputs) {// 存储检测结果vector<int> classIds;vector<float> confidences;vector<Rect> boxes;int img_w = frame.cols;int img_h = frame.rows;float x_factor = img_w / (float)inpWidth;float y_factor = img_h / (float)inpHeight;// 遍历检测结果for (size_t i = 0; i < outputs.size(); ++i) {Mat detections = outputs[i][0];int rows = detections.rows;for (int r = 0; r < rows; ++r) {float confidence = detections.at<float>(r, 4);if (confidence >= confThreshold) {Mat scores = detections.row(r).colRange(5, detections.cols);Point classIdPoint;double maxClassScore;minMaxLoc(scores, 0, &maxClassScore, 0, &classIdPoint);if (maxClassScore >= confThreshold) {// 解析坐标float cx = detections.at<float>(r, 0);float cy = detections.at<float>(r, 1);float w = detections.at<float>(r, 2);float h = detections.at<float>(r, 3);int left = int((cx - 0.5 * w) * x_factor);int top = int((cy - 0.5 * h) * y_factor);int width = int(w * x_factor);int height = int(h * y_factor);classIds.push_back(classIdPoint.x);confidences.push_back(confidence);boxes.push_back(Rect(left, top, width, height));}}}}// 执行自定义非极大值抑制vector<int> indices;NMSBoxesCustom(boxes, confidences, confThreshold, nmsThreshold, indices);// 绘制检测框for (size_t i = 0; i < indices.size(); ++i) {int idx = indices[i];Rect box = boxes[idx];// 绘制边界框rectangle(frame, box, Scalar(0, 255, 0), 2);// 显示类别名称和置信度string label = format("%.2f", confidences[idx]);if (!classes.empty()) {CV_Assert(classIds[idx] < (int)classes.size());label = classes[classIds[idx]] + ":" + label;}printf("%02d %04d,%04d,%04d,%04d\n",classIds[idx],box.x,box.y,box.width,box.height);int baseLine;Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);int top = max(box.y, labelSize.height);rectangle(frame, Point(box.x, top - labelSize.height),Point(box.x + labelSize.width, top + baseLine),Scalar::all(255), FILLED);putText(frame, label, Point(box.x, top),FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0,0,0), 1);}
}// 自定义 NMSBoxes 函数实现
void NMSBoxesCustom(const vector<Rect>& boxes, const vector<float>& scores, float scoreThreshold, float nmsThreshold, vector<int>& indices) {// 创建一个向量,包含每个框的索引vector<int> idxs;for (size_t i = 0; i < scores.size(); ++i) {if (scores[i] >= scoreThreshold) {idxs.push_back(i);}}// 如果没有满足条件的框,返回空的索引if (idxs.empty()) {return;}// 根据置信度分数对索引进行排序(从高到低)sort(idxs.begin(), idxs.end(), [&scores](int i1, int i2) {return scores[i1] > scores[i2];});vector<bool> suppressed(idxs.size(), false);// 进行 NMS 处理for (size_t i = 0; i < idxs.size(); ++i) {if (suppressed[i]) {continue;}int idx_i = idxs[i];indices.push_back(idx_i);Rect box_i = boxes[idx_i];for (size_t j = i + 1; j < idxs.size(); ++j) {if (suppressed[j]) {continue;}int idx_j = idxs[j];Rect box_j = boxes[idx_j];// 计算 IoU(交并比)float iou = (box_i & box_j).area() / float((box_i | box_j).area());// 如果 IoU 大于阈值,抑制当前框if (iou > nmsThreshold) {suppressed[j] = true;}}}
}
EOF
g++ yolov5_onnxruntime.cpp -o yolov5_onnxruntime  `pkg-config --cflags --libs opencv4` \-I onnxruntime-linux-x64-1.19.2/include -L onnxruntime-linux-x64-1.19.2/lib -lonnxruntime \-Wl,-rpath onnxruntime-linux-x64-1.19.2/lib
./yolov5_onnxruntime yolov5m.onnx coco.names input.mp4    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/8100.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

CSS如何改变滚动条的颜色样式粗细?

默认滚动条很丑怎么办&#xff1f;如何改版滚动条的粗细&#xff0c;颜色&#xff0c;让它更美观&#xff1f;CSS如何改变滚动条的粗细&#xff1f; 干货来了 /* Webkit内核浏览器的滚动条样式 */ ::-webkit-scrollbar {width: 4px; /* 设置滚动条的宽度 */ }::-webkit-scroll…

idea连接docker并构建镜像

安装docker 安装docker idea连接docker 安装docker插件 设置docker连接 设置docker.exe 这个docker.exe是为了运行docker&#xff0c;可以通过安装docker desktop获取 docker desktop下载地址 右键图标找到文件位置 在同级的resource中 编写Dockerfile # 使用官方 Nginx…

你竟然赶我走

目录 解题思路 题目设计原理 总结 解题思路 拿到图看属性没问题&#xff0c;格式是 jpg 的&#xff0c;但是这张图片肯定不简单。 文件分离不出东西。 使用 stegsolve 打开&#xff0c;使用文件格式分析功能&#xff0c;拉到最底下&#xff0c;flag 浮出水面。好吧&#xff…

ssm065基于JAVA WEB技术大健康综合咨询问诊平台的设计与实现+jsp(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 题目&#xff1a;健康综合咨询问诊平台设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本健康综合咨询…

masm汇编字符输入换行输出演示

从键盘读取一个字符并换行输出 assume cs:codecode segmentstart:mov ah, 1int 21hmov bl, almov dl, 10 mov ah, 2int 21h mov dl, blmov ah, 2int 21hmov ah, 4chint 21hcode ends end start 效果演示&#xff1a;

设备管理网关(golang版本)

硬件设备&#xff1a;移远EC200A-CN LTE Cat 4 无线通信模块 操作系统&#xff1a;openwrt 技术选型&#xff1a;layui golang sqlite websocket 工程结构 界面展示 区域管理 设备管理 运行监控 系统参数 资源文件 版本信息

变电站接地电阻监测装置-输电铁塔接地电阻监测装置:实时监测,预防故障

变电站接地电阻监测装置 接地电阻对电力系统的安全和稳定性至关重要&#xff0c;但在高压环境和极端气候下&#xff0c;接地系统可能出现性能下降&#xff0c;增加故障和跳闸的风险。传统的人工检测方法常常无法及时发现这些问题&#xff0c;并且操作繁琐。为此&#xff0c;我…

【ArcGIS】绘制各省碳排放分布的中国地图

首先&#xff0c;准备好各省、自治区、直辖市及特别行政区&#xff08;包括九段线&#xff09;的shp文件&#xff1a; 通过百度网盘分享的文件&#xff1a;GS&#xff08;2022&#xff09;1873 链接&#xff1a;https://pan.baidu.com/s/1wq8-XM99LXG_P8q-jNgPJA 提取码&#…

maven plugin:在自定义插件中获取当前项目的依赖库列表

我的项目中需要在自定义maven插件中调用javadoc获取java源码的注释,就需要为了javadoc能正常解析源码,还需要源码所在项目的依赖库列表(java 9以上版本的javadoc这是必须的)作为-classpath. 方案一:dependency:build-classpath 如果在项目安装(install)阶段(phase),这个参数通…

linux基础2

声明 学习视频来自B站UP主泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 一&#xff0c;linux目录简介 1&#xff0c;根目录&#xff08;/&#xff09; 根目录是Linux文件系统的…

Leecode热题100-78.子集

给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的 子集 &#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[],[1],[2],[1,2]…

【NRM】npm镜像源地址管理

【NRM】npm镜像源地址管理 1.背景 因为公司有npm内网源地址&#xff0c;很多外网依赖拉取很慢。使用nrm管理npm的源地址&#xff0c;更方便切换使用 2.NRM是什么 nrm(npm registry manager&#xff0c;nrm )是npm的镜像源管理工具&#xff0c;有时候国外资源太慢&#xff0…

uniapp—android原生插件开发(1环境准备)

本篇文章从实战角度出发&#xff0c;将UniApp集成新大陆PDA设备RFID的全过程分为四部曲&#xff0c;涵盖环境搭建、插件开发、AAR打包、项目引入和功能调试。通过这份教程&#xff0c;轻松应对安卓原生插件开发与打包需求&#xff01; 项目背景&#xff1a; UniApp集成新大陆P…

C语言复习第9章 字符串/字符/内存函数

目录 一、字符串函数1.1 读取字符串gets函数原型Example 1.2 字符串拷贝strcpy函数原型模拟实现官方源码 1.3 求字符串长度strlen函数原型关于返回值size_与算术转换的一个易错点模拟实现:递归模拟实现:指针-指针模拟实现:暴力官方源码 1.4 字符串追加strcat函数原型注意自己给…

借助 Aspose.Words,使用 C# 从 Word 文档中删除页面

如果您正在寻找一种快速删除 Word 文档中不相关、过时或空白页的方法&#xff0c;那么您来对地方了。在这篇博文中&#xff0c;我们将学习如何使用 C# 从 Word 文档中删除页面。我们将逐步引导您完成该过程&#xff0c;提供清晰的示例&#xff0c;以帮助您以编程方式高效地从 W…

AI领域的新千禧:为你的智能助手取个趣味名字!

内容概要 随着智能助手的崛起&#xff0c;它们逐渐成为我们日常生活中不可或缺的一部分。在这个过程中&#xff0c;为这些助手取一个趣味名字显得尤为重要。一个有趣的名字不仅能让用户感到更加亲切&#xff0c;还能带来更多的互动乐趣&#xff0c;使得人与科技之间的关系更加…

大数据-205 数据挖掘 机器学习理论 - 线性回归 最小二乘法 多元线性

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

python包管理工具pip和conda的使用对比

python包管理工具pip和conda的使用对比 总述1. pip使用2. conda注意虚拟环境之间的嵌套&#xff0c;这个会导致安装包后看不到包&#xff0c;实际是安装到了base环境里 未完待续 总述 pip相对于conda,对应包的依赖关系管理不强&#xff0c;坏处是容易造成包冲突&#xff0c;好…

考取无人机“飞手”执照,进入部队、电力、铁路、石油企业抢占优势

考取无人机“飞手”执照&#xff0c;对于希望进入部队、电力、铁路、石油企业等领域的人来说&#xff0c;确实可以抢占一定的职业优势。以下是对这一观点的详细分析&#xff1a; 一、无人机“飞手”执照的考取 1. 考取条件&#xff1a; 年满16周岁&#xff0c;初中以上文化程…

蒙特卡洛方法(MC Exploring Starts算法例子)

本文章中使用的算法和例子来源于bilibili中西湖大学赵世钰老师的【强化学习的数学原理】课程。网址&#xff1a;第5课-蒙特卡洛方法&#xff08;MC Exploring Starts算法&#xff09;_哔哩哔哩_bilibili 目录 一、算法简介 二、相关定义 1、策略评估 2、visit定义 3、epis…