通过ML.Net调用Yolov5的Onnx模型

news/2025/9/22 17:56:37/文章来源:https://www.cnblogs.com/dx5800/p/19105744

本文介绍如何在.Net环境调用Yolov5的模型,把yolov5的pt模型转成onnx模型,接着通过Microsoft.ML.OnnxRuntime调用yolov5的onnx模型

1.安装yolov5

git clone https://github.com/ultralytics/yolov5.git
cd yolov5
python -m venv venv
.\venv\Scripts\activate
pip install -r requirements.txt

2.安装好环境以后运行示例

2.1下载yolov5模型放到项目根目录,地址:https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt
2.2 执行一下命令:
python detect.py --weights yolov5s.pt --source data/images/zidane.jpg
输出:

data\images\zidane.jpg: 384x640 2 persons, 2 ties, 140.7ms
Speed: 1.0ms pre-process, 140.7ms inference, 1.0ms NMS per image at shape (1, 3, 640, 640)
Results saved to runs\detect\exp

runs/detect/exp可以看输出结果
image

3.把yolov5.pt转成yolov5.onnx,以下命令会在根目录输出一个yolov5.onnx

python export.py --weights yolov5s.pt --img 640 --batch 1 --device cpu --include onnx

4.获取onnx模型但是输入输出参数,参数在.net项目会用到

import onnx
# 加载 ONNX 模型 
model = onnx.load("yolov5s.onnx")print("=== 模型输入 ===")
for input_tensor in model.graph.input:name = input_tensor.nameelem_type = input_tensor.type.tensor_type.elem_typedims = [d.dim_value for d in input_tensor.type.tensor_type.shape.dim]print(f"Name: {name}")print(f"  ElementType: {elem_type}")print(f"  Dimensions: {dims}")print("\n=== 模型输出 ===")
for output_tensor in model.graph.output:name = output_tensor.nameelem_type = output_tensor.type.tensor_type.elem_typedims = [d.dim_value for d in output_tensor.type.tensor_type.shape.dim]print(f"Name: {name}")print(f"  ElementType: {elem_type}")print(f"  Dimensions: {dims}")

输出结果如下:
image

5.把onnx放到.net,然后运行项目

下面给出代码:

using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading.Channels;namespace YoloV5SoftNMS
{class Program{static void Main(string[] args){string modelPath = "yolov5s.onnx";string imagePath = "zidane.jpg";int inputWidth = 640;int inputHeight = 640;float confThreshold = 0.25f; // 保留小目标float iouThreshold = 0.45f;   // Soft-NMS IOU阈值float sigma = 0.5f;          // Soft-NMS 高斯衰减参数// 1️. 预处理var (inputTensor, padX, padY, scale, origWidth, origHeight) = PreprocessImage(imagePath, inputWidth, inputHeight);// 2️. ONNX 推理using var session = new InferenceSession(modelPath);var inputs = new List<NamedOnnxValue>{NamedOnnxValue.CreateFromTensor("images", inputTensor)//这里面images就是前面模型输入参数};using var results = session.Run(inputs);var outputTensor = results.First(r => r.Name == "output0").AsTensor<float>(); //这里面output0对应前面模型输出参数var output = outputTensor.ToArray();// 3️. 解析输出var predictions = ParseOutputs(output, 80, confThreshold);Console.WriteLine("=== NMS 前候选框 ===");foreach (var p in predictions)Console.WriteLine($"Class:{p.ClassId} Conf:{p.Confidence:0.00} X1:{p.X1:0.} Y1:{p.Y1:0.} X2:{p.X2:0.} Y2:{p.Y2:0.}");// 4️. Soft-NMSvar finalBoxes = SoftNMS(predictions, iouThreshold, sigma, confThreshold);Console.WriteLine("=== Soft-NMS 结果 ===");foreach (var p in finalBoxes)Console.WriteLine($"Class:{p.ClassId} Conf:{p.Confidence:0.00} X1:{p.X1:0.} Y1:{p.Y1:0.} X2:{p.X2:0.} Y2:{p.Y2:0.}");// 5️. 绘制回原图using var bitmap = new Bitmap(imagePath);using var g = Graphics.FromImage(bitmap);foreach (var p in finalBoxes){float x1 = (p.X1 - padX) / scale;float y1 = (p.Y1 - padY) / scale;float x2 = (p.X2 - padX) / scale;float y2 = (p.Y2 - padY) / scale;g.DrawRectangle(Pens.Red, x1, y1, x2 - x1, y2 - y1);g.DrawString($"ID:{p.ClassId} {p.Confidence:0.00}", new Font("Arial", 12), Brushes.Yellow, x1, y1 - 16);}bitmap.Save("result.jpg");Console.WriteLine("完成,结果保存为 result.jpg");Console.ReadKey();}/// <summary>/// 处理图片,把图片转成按CHW排布的一维数组/// </summary>/// <param name="imagePath"></param>/// <param name="targetWidth"></param>/// <param name="targetHeight"></param>/// <returns></returns>static (DenseTensor<float>, float, float, float, int, int) PreprocessImage(string imagePath, int targetWidth, int targetHeight){using var bitmap = new Bitmap(imagePath);int origW = bitmap.Width;int origH = bitmap.Height;float scale = Math.Min(targetWidth / (float)origW, targetHeight / (float)origH);int newW = (int)(origW * scale);int newH = (int)(origH * scale);float padX = (targetWidth - newW) / 2f;float padY = (targetHeight - newH) / 2f;using var resized = new Bitmap(targetWidth, targetHeight);using (var g = Graphics.FromImage(resized)){g.FillRectangle(Brushes.Black, 0, 0, targetWidth, targetHeight);g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;g.DrawImage(bitmap, padX, padY, newW, newH);}resized.Save("resized_input.jpg");float[] data = new float[3 * targetWidth * targetHeight];for (int y = 0; y < targetHeight; y++){for (int x = 0; x < targetWidth; x++){var color = resized.GetPixel(x, y);int idx = y * targetWidth + x;data[idx] = color.R / 255f;data[targetWidth * targetHeight + idx] = color.G / 255f;data[2 * targetWidth * targetHeight + idx] = color.B / 255f;}}//DenseTensor 是 ML.NET / ONNX Runtime 用来表示张量的数据结构// 第一个参数 data → 一维浮点数组// 第二个参数[1, 3, H, W] → 张量形状://1 → batch = 1,一次输入 1 张图片//3 → RGB 通道//targetHeight / targetWidth → 缩放后图片大小//张量会自动按照 CHW 排布,把一维数组映射成 4 维张量[batch, channel, height, width],刚好对应 YOLOv5 ONNX 模型输入。var tensor = new DenseTensor<float>(data, new int[] { 1, 3, targetHeight, targetWidth });return (tensor, padX, padY, scale, origW, origH);}/// <summary>/// 对输出的可信度进行过滤/// </summary>/// <param name="output"></param>/// <param name="numClasses"></param>/// <param name="confThreshold"></param>/// <returns></returns>static List<YoloPrediction> ParseOutputs(float[] output, int numClasses, float confThreshold){int numBoxes = output.Length / (5 + numClasses);var predictions = new List<YoloPrediction>();for (int i = 0; i < numBoxes; i++){int offset = i * (5 + numClasses);float x = output[offset];float y = output[offset + 1];float w = output[offset + 2];float h = output[offset + 3];float objConf = output[offset + 4];float maxClassConf = 0;int classId = 0;for (int c = 0; c < numClasses; c++){float classConf = output[offset + 5 + c];if (classConf > maxClassConf){maxClassConf = classConf;classId = c;}}float conf = objConf * maxClassConf;if (conf > confThreshold){predictions.Add(new YoloPrediction{X1 = x - w / 2,Y1 = y - h / 2,X2 = x + w / 2,Y2 = y + h / 2,Confidence = conf,ClassId = classId});}}return predictions;}/// <summary>/// 对一组候选框执行 Soft Non-Maximum Suppression (Soft-NMS),减少重叠框的冗余,但不像传统 NMS 那样直接丢弃,而是降低它们的置信度。/// </summary>/// <param name="boxes"></param>/// <param name="iouThreshold"></param>/// <param name="sigma"></param>/// <param name="confThreshold"></param>/// <returns></returns>static List<YoloPrediction> SoftNMS(List<YoloPrediction> boxes, float iouThreshold, float sigma, float confThreshold){var dets = boxes.OrderByDescending(b => b.Confidence).ToList();var keep = new List<YoloPrediction>();while (dets.Count > 0){var maxBox = dets[0];keep.Add(maxBox);dets.RemoveAt(0);for (int i = 0; i < dets.Count; i++){float iou = IoU(maxBox, dets[i]);if (iou > iouThreshold)dets[i].Confidence *= (float)Math.Exp(-iou * iou / sigma);}dets = dets.Where(b => b.Confidence > confThreshold).OrderByDescending(b => b.Confidence).ToList();}return keep;}/// <summary>/// 计算两个框之间的 IoU(Intersection over Union, 交并比)/// </summary>/// <param name="a"></param>/// <param name="b"></param>/// <returns></returns>static float IoU(YoloPrediction a, YoloPrediction b){float x1 = Math.Max(a.X1, b.X1);float y1 = Math.Max(a.Y1, b.Y1);float x2 = Math.Min(a.X2, b.X2);float y2 = Math.Min(a.Y2, b.Y2);float interArea = Math.Max(0, x2 - x1) * Math.Max(0, y2 - y1);float unionArea = (a.X2 - a.X1) * (a.Y2 - a.Y1) + (b.X2 - b.X1) * (b.Y2 - b.Y1) - interArea;return interArea / unionArea;}class YoloPrediction{public float X1, Y1, X2, Y2;public float Confidence;public int ClassId;}}
}

5.输出结果

image

6.输出对应的类别

yolov5模型可以识别80种类别,可以根据id找到对应的类别,把这个类别放到.Net项目就可以了,可以看到id为0是person,id为27是tie
image

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java-如何在Eclipse开发-数组

Java-如何在Eclipse开发-数组数组的常见概念: 数组:是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。 数组:长度从零开始计算。 链表:不连续而数组是连续的 1)数…

元宇宙与零售业变革:沉浸式体验重构消费全链路 - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

常用数据生成器

树 期望高度 \(O(\log)\): /* 生成期望树高 O(logn) 级别的树 生成方法:钦定 1 为根,对于后续的节点 i,随机在 [1,i-1] 中选取一个点作为父亲 打乱方法:对所有点重新随机编号 */ #include<random> #include…

沧州建设网站公司网络服务推广

文章目录 图像轮廓查找轮廓绘制轮廓轮廓的面积与周长多边形逼近与凸包外接矩形项目总览【车辆统计】视频加载【车辆统计】去背景【车辆统计】形态学处理【车辆统计】逻辑处理【车辆统计】显示信息【车辆统计】 图像轮廓 查找轮廓 # -*- coding: utf-8 -*- import cv2 import n…

12306网站建设多少钱如何提高百度权重

php中文网最新课程每日17点准时技术干货分享异常处理是软件开发过程中无法逃避的问题。对于一套设计良好代码高效的程序&#xff0c;出现异常的可能性会比较低&#xff0c;但这并不意味着不会出现异常,有些异常甚至会引起严重的后果&#xff0c;所以如何及时的发现程序中的异常…

优秀的集团网站微信公众号制作网页

1、什么是事务 在实际的业务开发中&#xff0c;有些业务操作要多次访问数据库。一个业务要发送多条SQL语句给数据库执行。需要将多次访问数据库的操作视为一个整体来执行&#xff0c;要么所有的SQL语句全部执行成功。如果其中有一条SQL语句失败&#xff0c;就进行事务的回滚&a…

个人两字印章在线制作网站百度关键词查询排名

鲸参谋监测的京东平台10月份牛奶乳品市场销售数据已出炉&#xff01; 10月份&#xff0c;牛奶乳品整体销售上涨。鲸参谋数据显示&#xff0c;今年10月&#xff0c;京东平台上牛奶乳品的销量将近1700万&#xff0c;同比增长1%&#xff1b;销售额将近17亿&#xff0c;同比增长约5…

谁可以做网站优化排名推广网站制作用到什么技术

在本文中&#xff0c;我将展示如何在Apache Aries Blueprint xml文件中添加一些内联脚本。 我不一定会称其为最佳实践&#xff0c;但我一直认为这种功能可能有用。 可能当我被迫使用xml来模拟命令式编程结构&#xff08;例如使用Apache Ant时&#xff09;时&#xff0c;我开始…

大庆网站制作公司地址大学生网页设计作业成品

MD[Gitlab 安装手册] Gitlab 安装手册 说明: Gitlab最低配置1核2g,建议配置2核4g以上且单独部署,如有多项目CI/CD要求,可以4核8g 1. 安装相关依赖(安装policycoreutils) [rootsjclinux ~]# yum -y install policycoreutils openssh-server openssh-clients postfix 2. 启动s…

做网站每年要交不费用吗成都公司注册地址托管

一.什么是死锁&#xff1f; 死锁是由于两个或以上的线程互相持有对方需要的资源&#xff0c;导致这些线程处于等待状态&#xff0c;无法执行。 二.产生死锁的四个必要条件 1.互斥性&#xff1a;线程对资源的占有是排他性的&#xff0c;一个资源只能被一个线程占有&#xff0c;直…

中国做铁塔的公司网站网站建设企业服务

目录 力扣724. 寻找数组的中心下标 解析代码 力扣724. 寻找数组的中心下标 724. 寻找数组的中心下标 LCR 012. 寻找数组的中心下标 1991. 找到数组的中间位置&#xff08;三道一样的题&#xff0c;一鱼三吃&#xff09; 难度 简单 给你一个整数数组 nums &#xff0c;请…

基于RSSI修正的定位算法分析

分析和实现基于RSSI(接收信号强度指示)修正的定位算法 % 基于RSSI修正的定位算法分析 clear; clc; close all;%% 1. 参数设置 fprintf(设置定位系统参数...\n);% 环境参数 n = 2.5; % 路径损耗指数 (…

接口测试流程+jmeter并发+面试题(总结) - 指南

接口测试流程+jmeter并发+面试题(总结) - 指南2025-09-22 17:49 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display…

c# 反射动态添加Attribute

//测试类 var type = typeof(TestClass);//给类对象添加、获取特性 TypeDescriptor.AddAttributes(type, indexAttr); //var attr = TypeDescriptor.GetAttributes(type)[typeof(DynamicCacheBufferAtrribute)] as Dyn…

wordpress站内链接跳转优秀企业宣传册样本

这段代码是 _make_causal_mask 函数中处理滑动窗口局部注意力的部分。这里的目的是创建一个额外的掩码,以便在自注意力机制中只考虑每个位置附近的一定数量的位置,而不是所有之前的位置。这通常用于减少计算复杂性和提高长序列处理的效率。 代码分析如下: diagonal = past_k…

网站开发搭建合同范本如何建立免费网站

转载请说明出处~本文教程翻译jni官方文档的部分内容。要查看Jni官方文档&#xff0c;请点击这里先感叹一下时光如水&#xff0c;岁月不留人哇有木有&#xff01;&#xff01;&#xff01;认真想想在XMU的这三年&#xff0c;真的改变了我好多。我还清楚地记得学习C语言写的第一个…

重庆商城网站建设百度收录的网站标题 --

第一轮 说说HaspMap底层原理&#xff1f;再说说它跟HaspTable和ConcurrentHashMap他们之间的相同点和不同点&#xff1f; 讲讲jdk1.7和1.8的区别&#xff1f; 几种内置的线程池 MySQL事务隔离级别以及MVCC机制 Redis缓存雪崩、缓存穿透以及如何解决&#xff1f; 分布式架构…

广东品牌网站建设报价做门户网站 cms

( A, B )---3*30*2---( 1, 0 )( 0, 1 ) 让网络的输入只有3个节点&#xff0c;AB训练集各由5张二值化的图片组成&#xff0c;让A中有3个1&#xff0c;B中全是0&#xff0c;统计迭代次数并排序。 在3*5的空间内分布3个点有19种可能&#xff0c;但不同的分布只有6种 差值就诶够 …

旅游网站建设的目标青岛最大的设计院

1、集合元素处理&#xff08;传统方式&#xff09; 现在有两个ArrayList集合存储队伍当中的多个成员姓名&#xff0c;要求使用传统的for循环&#xff08;或增强for循环&#xff09;依次进行一下若干操作步骤&#xff1a; 第一个队伍只要 名字为 3 个字 的成员姓名&#xff1b;存…

手机网站模板网深圳小企业网站建设

本文旨在编写一个简单的shell外壳程序&#xff01;功能类似于shell的一些基本操作&#xff01;虽然不能全部实现shell的一些功能&#xff01;但是通过此文章&#xff0c;自己写一个简单的shell程序也是不成问题&#xff01;并且通过此文章&#xff0c;可以让读者对linux中一些环…