当前位置: 首页 > news >正文

c# 使用yolov5模型

1. 训练模型

在python中用yolo v5 训练自己的数据集,得到best.pt。

参考:

Yolov5训练自己的数据集(详细完整版)_yolov5缔宇-CSDN博客

在python中使用此模型:


import torch
from models.experimental import attempt_load
from utils.general import non_max_suppression, scale_boxes
from utils.plots import Annotator, colors
import cv2device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = attempt_load('runs/train/exp/weights/best.pt').to(device)  # 加载模型
stride = int(model.stride.max())  # 模型步长(用于缩放坐标)
names = model.module.names if hasattr(model, 'module') else model.names  # 类别名称img = cv2.imread("../ultralytics-main/dataset/images/val/camera0_20250611143415545667.jpg_0.0.png")
img_resize = cv2.resize(img,(640,640))
img_tensor = torch.from_numpy(img_resize).to(device).float() / 255.0  # 归一化
img_tensor = img_tensor.permute(2, 0, 1).unsqueeze(0)  # HWC → CHW,添加 batch 维度#  推理
with torch.no_grad():pred = model(img_tensor)[0]  # 推理# 后处理:NMS + 坐标缩放
pred = non_max_suppression(pred, conf_thres=0.25, iou_thres=0.45)  # NMS
annotator = Annotator(img_resize, line_width=2, example=str(names))  # 初始化标注器# 绘制检测结果
for det in pred:  # 遍历每张图片的检测结果(batch=1 时只有 1 个 det)if len(det):det[:, :4] = scale_boxes(img_tensor.shape[2:], det[:, :4], img_resize.shape[:2]).round()  # 缩放坐标到原图for *xyxy, conf, cls in reversed(det):  # xyxy: 边界框坐标, conf: 置信度, cls: 类别 IDlabel = f'{names[int(cls)]} {conf:.2f}'annotator.box_label(xyxy, label, color=colors(int(cls)))  # 绘制边界框和标签cv2.imshow("result",img_resize)
cv2.waitKey(0)

这里用一个比较简单的划痕污点检测模型,进行测试。

dataset:

2.模型转换

.pt是python格式,需要转换成.onnx。

pip install onnx

import torch
import onnx
# 加载 YOLOv5 模型
model = torch.hub.load('ultralytics/yolov5', 'custom', path='best.pt')# 转换为 ONNX 格式
dummy_input = torch.randn(1, 3, 640, 640)
print("开始转换")opset_version = 12torch.onnx.export(model,dummy_input,"best.onnx",input_names=['images'],output_names=['output'],opset_version=opset_version,dynamic_axes=None  
)
print("转换完成")

得到best.onnx

3.在c#中使用此模型。

创建 winform 项目 test—yolo

在nuget中 添加Microsoft.ML.OnnxRuntime

项目属性,生成,取消 首选32

界面设计:

主要方法:

  1. test_yolov5 - 主流程控制

  2. LoadImage - 图像预处理

  3. ProcessOutput - 模型输出解析

  4. NonMaxSuppression - 非极大值抑制

  5. DrawPredictions - 结果可视化

代码:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Drawing.Imaging;
using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;namespace test_yolo
{public partial class Form1 : Form{public Form1(){InitializeComponent();}private void button_start_Click(object sender, EventArgs e){//使用 ONNX 格式的模型//string modelPath = "best.onnx";//string imagePath = "test.png";Image result = yolo_Program.test_yolov5(textBox_model.Text, textBox_img.Text);pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;pictureBox1.Image = result;}private void button_img_Click(object sender, EventArgs e){OpenFileDialog openFileDialog = new OpenFileDialog{Title = "选择文件",Filter = "所有文件 (*.*)|*.*",//InitialDirectory = @"C:\"};if (openFileDialog.ShowDialog() == DialogResult.OK){// 获取仅包含文件名的字符串string fileName = openFileDialog.SafeFileName;textBox_img.Text = fileName;}}private void button_model_Click(object sender, EventArgs e){OpenFileDialog openFileDialog = new OpenFileDialog{Title = "选择文件",Filter = "所有文件 (*.*)|*.*",//InitialDirectory = @"C:\"};if (openFileDialog.ShowDialog() == DialogResult.OK){// 获取仅包含文件名的字符串string fileName = openFileDialog.SafeFileName;textBox_model.Text = fileName;}}}class yolo_Program{// 检测类别名称private static readonly string[] classNames = new[] {"A","B","C","D","E","F","G","H","I","J"};public static Image test_yolov5(string modelPath, string imagePath){try{// 检查文件是否存在if (!System.IO.File.Exists(modelPath)){MessageBox.Show($"模型文件不存在: {modelPath}");return null;}if (!System.IO.File.Exists(imagePath)){MessageBox.Show($"图像文件不存在: {imagePath}");return null;}// 设置 ONNX Runtime 选项var options = new SessionOptions();// 根据您的需求选择合适的执行提供程序// 对于 CPU:options.AppendExecutionProvider_CPU();// 如果支持 GPU,可以添加 CUDA 提供程序(需要安装相应的包)// options.AppendExecutionProvider_CUDA();// 加载模型var session = new InferenceSession(modelPath, options);// 加载并预处理图像var (inputTensor, originalWidth, originalHeight) = LoadImage(imagePath);// 准备输入参数var inputs = new List<NamedOnnxValue>{NamedOnnxValue.CreateFromTensor("images", inputTensor)};// 运行模型推理var results = session.Run(inputs);// 处理输出结果var outputTensor = results.First().AsTensor<float>();var predictions = ProcessOutput(outputTensor, originalWidth, originalHeight);// 绘制检测结果Image result =  DrawPredictions(imagePath, predictions, "output.jpg");// MessageBox.Show($"检测完成,结果已保存至 output.jpg\n检测到 {predictions.Count} 个目标");return result;}catch (Exception ex){MessageBox.Show($"错误: {ex.Message}\n{ex.StackTrace}");return null;}}// 加载并预处理图像private static (DenseTensor<float> tensor, int width, int height) LoadImage(string imagePath){var image = Image.FromFile(imagePath);int originalWidth = image.Width;int originalHeight = image.Height;// 调整图像大小为模型输入尺寸var resizedImage = ResizeImage(image, 640, 640);// 图像转张量var tensor = new DenseTensor<float>(new[] { 1, 3, 640, 640 });using (var bitmap = new Bitmap(resizedImage)){for (int y = 0; y < bitmap.Height; y++){for (int x = 0; x < bitmap.Width; x++){var pixel = bitmap.GetPixel(x, y);// YOLOv5 使用 RGB 顺序,归一化到 0-1tensor[0, 0, y, x] = pixel.R / 255.0f; // Rtensor[0, 1, y, x] = pixel.G / 255.0f; // Gtensor[0, 2, y, x] = pixel.B / 255.0f; // B}}}return (tensor, originalWidth, originalHeight);}// 调整图像大小private static Bitmap ResizeImage(Image image, int width, int height){var destRect = new Rectangle(0, 0, width, height);var destImage = new Bitmap(width, height);destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);using (var graphics = Graphics.FromImage(destImage)){graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;using (var wrapMode = new ImageAttributes()){wrapMode.SetWrapMode(System.Drawing.Drawing2D.WrapMode.TileFlipXY);graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);}}return destImage;}// 处理模型输出private static List<Prediction> ProcessOutput(Tensor<float> output, int originalWidth, int originalHeight){const float confidenceThreshold = 0.5f;const float nmsThreshold = 0.4f;var predictions = new List<Prediction>();// YOLOv5 ONNX 模型的输出格式通常是 [1, 25200, 85]// 其中 85 = [x, y, w, h, confidence, class_probabilities...]int numDetections = output.Dimensions[1];int numClasses = output.Dimensions[2] - 5;for (int i = 0; i < numDetections; i++){float confidence = output[0, i, 4];if (confidence >= confidenceThreshold){// 找到概率最高的类别int classId = 0;float maxClassProb = 0;for (int c = 0; c < numClasses; c++){float classProb = output[0, i, 5 + c];if (classProb > maxClassProb){maxClassProb = classProb;classId = c;}}float score = confidence * maxClassProb;if (score >= confidenceThreshold){// 获取边界框坐标(相对于 640x640)float cx = output[0, i, 0];float cy = output[0, i, 1];float w = output[0, i, 2];float h = output[0, i, 3];// 转换为绝对坐标float x1 = (cx - w / 2) * originalWidth / 640;float y1 = (cy - h / 2) * originalHeight / 640;float x2 = (cx + w / 2) * originalWidth / 640;float y2 = (cy + h / 2) * originalHeight / 640;predictions.Add(new Prediction{ClassId = classId,Score = score,BBox = new RectangleF(x1, y1, x2 - x1, y2 - y1)});}}}// 非极大值抑制return NonMaxSuppression(predictions, nmsThreshold);}// 非极大值抑制private static List<Prediction> NonMaxSuppression(List<Prediction> predictions, float threshold){var result = new List<Prediction>();predictions = predictions.OrderByDescending(p => p.Score).ToList();while (predictions.Count > 0){var best = predictions[0];result.Add(best);predictions.RemoveAt(0);predictions = predictions.Where(p =>{float iou = CalculateIoU(best.BBox, p.BBox);return iou < threshold;}).ToList();}return result;}// 计算 IoUprivate static float CalculateIoU(RectangleF box1, RectangleF box2){float x1 = Math.Max(box1.Left, box2.Left);float y1 = Math.Max(box1.Top, box2.Top);float x2 = Math.Min(box1.Right, box2.Right);float y2 = Math.Min(box1.Bottom, box2.Bottom);float intersection = Math.Max(0, x2 - x1) * Math.Max(0, y2 - y1);float area1 = box1.Width * box1.Height;float area2 = box2.Width * box2.Height;return intersection / (area1 + area2 - intersection);}// 绘制预测结果private static Image DrawPredictions(string inputImagePath, List<Prediction> predictions, string outputImagePath){var image = Image.FromFile(inputImagePath);var graphics = Graphics.FromImage(image);graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;var colors = new[]{Color.Red, Color.Green, Color.Blue, Color.Yellow, Color.Orange,Color.Purple, Color.Cyan, Color.Magenta, Color.Lime, Color.Pink};foreach (var prediction in predictions){var bbox = prediction.BBox;var color = colors[prediction.ClassId % colors.Length];var label = $"{classNames[prediction.ClassId]}: {prediction.Score:F2}";var pen = new Pen(color, 3);graphics.DrawRectangle(pen, bbox.X, bbox.Y, bbox.Width, bbox.Height);var font = new Font("Arial", 12, FontStyle.Bold);var brush = new SolidBrush(color);var textBrush = new SolidBrush(Color.White);var textSize = graphics.MeasureString(label, font);var textBackground = new RectangleF(bbox.X, bbox.Y - textSize.Height, textSize.Width, textSize.Height);graphics.FillRectangle(brush, textBackground);graphics.DrawString(label, font, textBrush, bbox.X, bbox.Y - textSize.Height);}//保存// image.Save(outputImagePath, ImageFormat.Jpeg);return image;}}// 预测结果类public class Prediction{public int ClassId { get; set; }public float Score { get; set; }public RectangleF BBox { get; set; }}
}

运行后:

http://www.dtcms.com/a/466696.html

相关文章:

  • 表白网站制作代码公司邮箱如何申请
  • 厦门最早做网站的公司二字顺口名字公司
  • 【GIT】错误集锦及解决方案
  • C语言⽂件操作讲解(1~2)
  • 前端代码CR小知识点汇总
  • 企业建站免费模板wordpress访问统计
  • 乐清建站公司做网站哪里最便宜
  • 什么是 Spring AI?Spring AI 入门教程
  • 在线课程网站开发的研究意义客户管理系统免费版
  • 台州宇洋台州网站建设手机在线视频
  • uniapp开发 APP嵌入另一个APP打包的wgt文件,实现点击携带参数跳转到wgtAPP的某一个页面
  • VS2010做网站登录页面步骤可以免费浏览的网站
  • DeepSeek Sparse Attention(DSA)快速洞察(DeepSeek-V3.2)
  • 山西建设银行官方网站wordpress 文章投票插件
  • C++ 模拟 力扣1576. 替换所有的问号 题解 每日一题
  • 安全联盟网站认证网络营销的认识
  • 基于SpringBoot+Vue的少儿编程培训机构管理系(WebSocket及时通讯、协同过滤算法、Echarts图形化分析)
  • 时序数据库promQL
  • 网站安全检测可以监测哪些内容风险信息宜春网站开发
  • 网站建设中企动力强成都那家网站建设好
  • RK3588 linux在uboot关机模式下待熄屏休眠后拔插适配器无反应屏幕也不会亮
  • 建设厅网站关于建筑资质合并wordpress速度很慢
  • 做网站的叫什么软件上海阿里巴巴做网站
  • Redis的Hash解析
  • 旅游业网站开发建设毕设做微课资源网站设计可以吗
  • 设计公司网站什么重要杭州工业设计
  • 【北京迅为】iTOP-4412精英版使用手册-第三十五章 WEB控制LED
  • 重庆seo整站优化报价福建建筑人才网官网
  • 教学信息化大赛网站建设作品永久免费国外ip代理
  • [嵌入式系统-93]: NVIDIA 正在从‘数据中心霸主’向‘端-边-云一体化AI平台’战略扩张。