C#OnnxRuntime部署DAMO-YOLO交通标识检测
- 开源代码
- 2025-09-15 09:39:01

目录
说明
效果
模型信息
项目
代码
下载
参考
说明 效果 模型信息
Model Properties ------------------------- ---------------------------------------------------------------
Inputs ------------------------- name:input tensor:Float[1, 3, 640, 640] ---------------------------------------------------------------
Outputs ------------------------- name:transposed_output tensor:Float[1, 5, 8400] ---------------------------------------------------------------
项目 代码using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; using OpenCvSharp; using OpenCvSharp.Dnn; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Text; using System.Windows.Forms;
namespace Onnx_Demo { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png"; string image_path = ""; string model_path; string classer_path; public string[] class_names; public int class_num;
DateTime dt1 = DateTime.Now; DateTime dt2 = DateTime.Now;
int input_height; int input_width;
InferenceSession onnx_session;
int box_num; float conf_threshold; float nms_threshold;
StringBuilder sb = new StringBuilder();
/// <summary> /// 选择图片 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = fileFilter; if (ofd.ShowDialog() != DialogResult.OK) return;
pictureBox1.Image = null;
image_path = ofd.FileName; pictureBox1.Image = new Bitmap(image_path);
textBox1.Text = ""; pictureBox2.Image = null; }
/// <summary> /// 推理 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button2_Click(object sender, EventArgs e) { if (image_path == "") { return; }
button2.Enabled = false; pictureBox2.Image = null; textBox1.Text = ""; sb.Clear(); Application.DoEvents();
Mat image = new Mat(image_path);
float ratio = Math.Min(input_height * 1.0f / image.Rows, input_width * 1.0f / image.Cols); int neww = (int)(image.Cols * ratio); int newh = (int)(image.Rows * ratio); Mat dstimg = new Mat(); Cv2.CvtColor(image, dstimg, ColorConversionCodes.BGR2RGB); Cv2.Resize(dstimg, dstimg, new OpenCvSharp.Size(neww, newh)); Cv2.CopyMakeBorder(dstimg, dstimg, 0, input_height - newh, 0, input_width - neww, BorderTypes.Constant, new Scalar(1));
//Cv2.ImShow("input_img", dstimg);
//输入Tensor Tensor<float> input_tensor = new DenseTensor<float>(new[] { 1, 3, 640, 640 }); for (int y = 0; y < dstimg.Height; y++) { for (int x = 0; x < dstimg.Width; x++) { input_tensor[0, 0, y, x] = dstimg.At<Vec3b>(y, x)[0]; input_tensor[0, 1, y, x] = dstimg.At<Vec3b>(y, x)[1]; input_tensor[0, 2, y, x] = dstimg.At<Vec3b>(y, x)[2]; } }
dstimg.Dispose();
List<NamedOnnxValue> input_container = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor("input", input_tensor) };
//推理 dt1 = DateTime.Now; var ort_outputs = onnx_session.Run(input_container).ToArray(); dt2 = DateTime.Now;
float[] data = Transpose(ort_outputs[0].AsTensor<float>().ToArray(), 4 + class_num, box_num);
float[] confidenceInfo = new float[class_num]; float[] rectData = new float[4];
List<DetectionResult> detResults = new List<DetectionResult>();
for (int i = 0; i < box_num; i++) { Array.Copy(data, i * (class_num + 4), rectData, 0, 4); Array.Copy(data, i * (class_num + 4) + 4, confidenceInfo, 0, class_num);
float score = confidenceInfo.Max(); // 获取最大值
int maxIndex = Array.IndexOf(confidenceInfo, score); // 获取最大值的位置
int xmin = (int)(rectData[0] / ratio); int ymin = (int)(rectData[1] / ratio); int xmax = (int)(rectData[2] / ratio); int ymax = (int)(rectData[3] / ratio);
Rect box = new Rect(); box.X = (int)xmin; box.Y = (int)ymin; box.Width = (int)(xmax - xmin); box.Height = (int)(ymax - ymin);
detResults.Add(new DetectionResult( maxIndex, class_names[maxIndex], box, score)); }
//NMS CvDnn.NMSBoxes(detResults.Select(x => x.Rect), detResults.Select(x => x.Confidence), conf_threshold, nms_threshold, out int[] indices); detResults = detResults.Where((x, index) => indices.Contains(index)).ToList();
sb.AppendLine("推理耗时:" + (dt2 - dt1).TotalMilliseconds + "ms"); sb.AppendLine("------------------------------");
//绘制结果 Mat result_image = image.Clone(); foreach (DetectionResult r in detResults) { Cv2.PutText(result_image, $"{r.Class}:{r.Confidence:P0}", new OpenCvSharp.Point(r.Rect.TopLeft.X, r.Rect.TopLeft.Y - 10), HersheyFonts.HersheySimplex, 1, Scalar.Red, 2); Cv2.Rectangle(result_image, r.Rect, Scalar.Red, thickness: 2);
sb.AppendLine(string.Format("{0}:{1},({2},{3},{4},{5})" , r.Class , r.Confidence.ToString("P0") , r.Rect.TopLeft.X , r.Rect.TopLeft.Y , r.Rect.BottomRight.X , r.Rect.BottomRight.Y )); }
if (pictureBox2.Image != null) { pictureBox2.Image.Dispose(); }
pictureBox2.Image = new Bitmap(result_image.ToMemoryStream());
result_image.Dispose();
textBox1.Text = sb.ToString();
button2.Enabled = true; }
/// <summary> ///窗体加载 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Form1_Load(object sender, EventArgs e) { model_path = "model/damoyolo_traffic_sign.onnx";
//创建输出会话,用于输出模型读取信息 SessionOptions options = new SessionOptions(); options.LogSeverityLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_INFO; options.AppendExecutionProvider_CPU(0);// 设置为CPU上运行
// 创建推理模型类,读取模型文件 onnx_session = new InferenceSession(model_path, options);//model_path 为onnx模型文件的路径
input_height = 640; input_width = 640;
box_num = 8400; conf_threshold = 0.25f; nms_threshold = 0.5f;
classer_path = "model/lable.txt"; class_names = File.ReadAllLines(classer_path, Encoding.UTF8); class_num = class_names.Length;
image_path = "test_img/1.jpg"; pictureBox1.Image = new Bitmap(image_path); }
/// <summary> /// 保存 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button3_Click(object sender, EventArgs e) { if (pictureBox2.Image == null) { return; } Bitmap output = new Bitmap(pictureBox2.Image); SaveFileDialog sdf = new SaveFileDialog(); sdf.Title = "保存"; sdf.Filter = "Images (*.jpg)|*.jpg|Images (*.png)|*.png|Images (*.bmp)|*.bmp|Images (*.emf)|*.emf|Images (*.exif)|*.exif|Images (*.gif)|*.gif|Images (*.ico)|*.ico|Images (*.tiff)|*.tiff|Images (*.wmf)|*.wmf"; if (sdf.ShowDialog() == DialogResult.OK) { switch (sdf.FilterIndex) { case 1: { output.Save(sdf.FileName, ImageFormat.Jpeg); break; } case 2: { output.Save(sdf.FileName, ImageFormat.Png); break; } case 3: { output.Save(sdf.FileName, ImageFormat.Bmp); break; } case 4: { output.Save(sdf.FileName, ImageFormat.Emf); break; } case 5: { output.Save(sdf.FileName, ImageFormat.Exif); break; } case 6: { output.Save(sdf.FileName, ImageFormat.Gif); break; } case 7: { output.Save(sdf.FileName, ImageFormat.Icon); break; }
case 8: { output.Save(sdf.FileName, ImageFormat.Tiff); break; } case 9: { output.Save(sdf.FileName, ImageFormat.Wmf); break; } } MessageBox.Show("保存成功,位置:" + sdf.FileName); } }
private void pictureBox1_DoubleClick(object sender, EventArgs e) { ShowNormalImg(pictureBox1.Image); }
private void pictureBox2_DoubleClick(object sender, EventArgs e) { ShowNormalImg(pictureBox2.Image); }
public void ShowNormalImg(Image img) { if (img == null) return;
frmShow frm = new frmShow();
frm.Width = Screen.PrimaryScreen.Bounds.Width; frm.Height = Screen.PrimaryScreen.Bounds.Height;
if (frm.Width > img.Width) { frm.Width = img.Width; }
if (frm.Height > img.Height) { frm.Height = img.Height; }
bool b = frm.richTextBox1.ReadOnly; Clipboard.SetDataObject(img, true); frm.richTextBox1.ReadOnly = false; frm.richTextBox1.Paste(DataFormats.GetFormat(DataFormats.Bitmap)); frm.richTextBox1.ReadOnly = b;
frm.ShowDialog();
}
public unsafe float[] Transpose(float[] tensorData, int rows, int cols) { float[] transposedTensorData = new float[tensorData.Length];
fixed (float* pTensorData = tensorData) { fixed (float* pTransposedData = transposedTensorData) { for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { int index = i * cols + j; int transposedIndex = j * rows + i; pTransposedData[transposedIndex] = pTensorData[index]; } } } } return transposedTensorData; } }
public class DetectionResult { public DetectionResult(int ClassId, string Class, Rect Rect, float Confidence) { this.ClassId = ClassId; this.Confidence = Confidence; this.Rect = Rect; this.Class = Class; }
public string Class { get; set; }
public int ClassId { get; set; }
public float Confidence { get; set; }
public Rect Rect { get; set; }
}
}
using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; using OpenCvSharp; using OpenCvSharp.Dnn; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Text; using System.Windows.Forms; namespace Onnx_Demo { public partial class Form1 : Form { public Form1() { InitializeComponent(); } string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png"; string image_path = ""; string model_path; string classer_path; public string[] class_names; public int class_num; DateTime dt1 = DateTime.Now; DateTime dt2 = DateTime.Now; int input_height; int input_width; InferenceSession onnx_session; int box_num; float conf_threshold; float nms_threshold; StringBuilder sb = new StringBuilder(); /// <summary> /// 选择图片 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = fileFilter; if (ofd.ShowDialog() != DialogResult.OK) return; pictureBox1.Image = null; image_path = ofd.FileName; pictureBox1.Image = new Bitmap(image_path); textBox1.Text = ""; pictureBox2.Image = null; } /// <summary> /// 推理 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button2_Click(object sender, EventArgs e) { if (image_path == "") { return; } button2.Enabled = false; pictureBox2.Image = null; textBox1.Text = ""; sb.Clear(); Application.DoEvents(); Mat image = new Mat(image_path); float ratio = Math.Min(input_height * 1.0f / image.Rows, input_width * 1.0f / image.Cols); int neww = (int)(image.Cols * ratio); int newh = (int)(image.Rows * ratio); Mat dstimg = new Mat(); Cv2.CvtColor(image, dstimg, ColorConversionCodes.BGR2RGB); Cv2.Resize(dstimg, dstimg, new OpenCvSharp.Size(neww, newh)); Cv2.CopyMakeBorder(dstimg, dstimg, 0, input_height - newh, 0, input_width - neww, BorderTypes.Constant, new Scalar(1)); //Cv2.ImShow("input_img", dstimg); //输入Tensor Tensor<float> input_tensor = new DenseTensor<float>(new[] { 1, 3, 640, 640 }); for (int y = 0; y < dstimg.Height; y++) { for (int x = 0; x < dstimg.Width; x++) { input_tensor[0, 0, y, x] = dstimg.At<Vec3b>(y, x)[0]; input_tensor[0, 1, y, x] = dstimg.At<Vec3b>(y, x)[1]; input_tensor[0, 2, y, x] = dstimg.At<Vec3b>(y, x)[2]; } } dstimg.Dispose(); List<NamedOnnxValue> input_container = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor("input", input_tensor) }; //推理 dt1 = DateTime.Now; var ort_outputs = onnx_session.Run(input_container).ToArray(); dt2 = DateTime.Now; float[] data = Transpose(ort_outputs[0].AsTensor<float>().ToArray(), 4 + class_num, box_num); float[] confidenceInfo = new float[class_num]; float[] rectData = new float[4]; List<DetectionResult> detResults = new List<DetectionResult>(); for (int i = 0; i < box_num; i++) { Array.Copy(data, i * (class_num + 4), rectData, 0, 4); Array.Copy(data, i * (class_num + 4) + 4, confidenceInfo, 0, class_num); float score = confidenceInfo.Max(); // 获取最大值 int maxIndex = Array.IndexOf(confidenceInfo, score); // 获取最大值的位置 int xmin = (int)(rectData[0] / ratio); int ymin = (int)(rectData[1] / ratio); int xmax = (int)(rectData[2] / ratio); int ymax = (int)(rectData[3] / ratio); Rect box = new Rect(); box.X = (int)xmin; box.Y = (int)ymin; box.Width = (int)(xmax - xmin); box.Height = (int)(ymax - ymin); detResults.Add(new DetectionResult( maxIndex, class_names[maxIndex], box, score)); } //NMS CvDnn.NMSBoxes(detResults.Select(x => x.Rect), detResults.Select(x => x.Confidence), conf_threshold, nms_threshold, out int[] indices); detResults = detResults.Where((x, index) => indices.Contains(index)).ToList(); sb.AppendLine("推理耗时:" + (dt2 - dt1).TotalMilliseconds + "ms"); sb.AppendLine("------------------------------"); //绘制结果 Mat result_image = image.Clone(); foreach (DetectionResult r in detResults) { Cv2.PutText(result_image, $"{r.Class}:{r.Confidence:P0}", new OpenCvSharp.Point(r.Rect.TopLeft.X, r.Rect.TopLeft.Y - 10), HersheyFonts.HersheySimplex, 1, Scalar.Red, 2); Cv2.Rectangle(result_image, r.Rect, Scalar.Red, thickness: 2); sb.AppendLine(string.Format("{0}:{1},({2},{3},{4},{5})" , r.Class , r.Confidence.ToString("P0") , r.Rect.TopLeft.X , r.Rect.TopLeft.Y , r.Rect.BottomRight.X , r.Rect.BottomRight.Y )); } if (pictureBox2.Image != null) { pictureBox2.Image.Dispose(); } pictureBox2.Image = new Bitmap(result_image.ToMemoryStream()); result_image.Dispose(); textBox1.Text = sb.ToString(); button2.Enabled = true; } /// <summary> ///窗体加载 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Form1_Load(object sender, EventArgs e) { model_path = "model/damoyolo_traffic_sign.onnx"; //创建输出会话,用于输出模型读取信息 SessionOptions options = new SessionOptions(); options.LogSeverityLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_INFO; options.AppendExecutionProvider_CPU(0);// 设置为CPU上运行 // 创建推理模型类,读取模型文件 onnx_session = new InferenceSession(model_path, options);//model_path 为onnx模型文件的路径 input_height = 640; input_width = 640; box_num = 8400; conf_threshold = 0.25f; nms_threshold = 0.5f; classer_path = "model/lable.txt"; class_names = File.ReadAllLines(classer_path, Encoding.UTF8); class_num = class_names.Length; image_path = "test_img/1.jpg"; pictureBox1.Image = new Bitmap(image_path); } /// <summary> /// 保存 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button3_Click(object sender, EventArgs e) { if (pictureBox2.Image == null) { return; } Bitmap output = new Bitmap(pictureBox2.Image); SaveFileDialog sdf = new SaveFileDialog(); sdf.Title = "保存"; sdf.Filter = "Images (*.jpg)|*.jpg|Images (*.png)|*.png|Images (*.bmp)|*.bmp|Images (*.emf)|*.emf|Images (*.exif)|*.exif|Images (*.gif)|*.gif|Images (*.ico)|*.ico|Images (*.tiff)|*.tiff|Images (*.wmf)|*.wmf"; if (sdf.ShowDialog() == DialogResult.OK) { switch (sdf.FilterIndex) { case 1: { output.Save(sdf.FileName, ImageFormat.Jpeg); break; } case 2: { output.Save(sdf.FileName, ImageFormat.Png); break; } case 3: { output.Save(sdf.FileName, ImageFormat.Bmp); break; } case 4: { output.Save(sdf.FileName, ImageFormat.Emf); break; } case 5: { output.Save(sdf.FileName, ImageFormat.Exif); break; } case 6: { output.Save(sdf.FileName, ImageFormat.Gif); break; } case 7: { output.Save(sdf.FileName, ImageFormat.Icon); break; } case 8: { output.Save(sdf.FileName, ImageFormat.Tiff); break; } case 9: { output.Save(sdf.FileName, ImageFormat.Wmf); break; } } MessageBox.Show("保存成功,位置:" + sdf.FileName); } } private void pictureBox1_DoubleClick(object sender, EventArgs e) { ShowNormalImg(pictureBox1.Image); } private void pictureBox2_DoubleClick(object sender, EventArgs e) { ShowNormalImg(pictureBox2.Image); } public void ShowNormalImg(Image img) { if (img == null) return; frmShow frm = new frmShow(); frm.Width = Screen.PrimaryScreen.Bounds.Width; frm.Height = Screen.PrimaryScreen.Bounds.Height; if (frm.Width > img.Width) { frm.Width = img.Width; } if (frm.Height > img.Height) { frm.Height = img.Height; } bool b = frm.richTextBox1.ReadOnly; Clipboard.SetDataObject(img, true); frm.richTextBox1.ReadOnly = false; frm.richTextBox1.Paste(DataFormats.GetFormat(DataFormats.Bitmap)); frm.richTextBox1.ReadOnly = b; frm.ShowDialog(); } public unsafe float[] Transpose(float[] tensorData, int rows, int cols) { float[] transposedTensorData = new float[tensorData.Length]; fixed (float* pTensorData = tensorData) { fixed (float* pTransposedData = transposedTensorData) { for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { int index = i * cols + j; int transposedIndex = j * rows + i; pTransposedData[transposedIndex] = pTensorData[index]; } } } } return transposedTensorData; } } public class DetectionResult { public DetectionResult(int ClassId, string Class, Rect Rect, float Confidence) { this.ClassId = ClassId; this.Confidence = Confidence; this.Rect = Rect; this.Class = Class; } public string Class { get; set; } public int ClassId { get; set; } public float Confidence { get; set; } public Rect Rect { get; set; } } } 下载源码下载
参考modelscope /models/iic/cv_tinynas_object-detection_damoyolo_traffic_sign/summary
C#OnnxRuntime部署DAMO-YOLO交通标识检测由讯客互联开源代码栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“C#OnnxRuntime部署DAMO-YOLO交通标识检测”
上一篇
PDF万能水印删除工具