Program.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. using OpenCvSharp;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using CvPoint = OpenCvSharp.Point;
  10. namespace YoloTest
  11. {
  12. internal class Program
  13. {
  14. static void Main(string[] args)
  15. {
  16. string imagepath = "Model/2025-08-11-09-40-52-345.jpg";
  17. string ModelPath = "Model/S_best_stop_aug_ckpt.onnx";
  18. using (var detector = new YoloV6Detector(ModelPath, new[] { "OK", "NG" },true))
  19. {
  20. // 1. 使用 System.Drawing 加载图像用于检测
  21. using (var image = Image.FromFile(imagepath))
  22. {
  23. List<Detection> results = new List<Detection>();
  24. Stopwatch stopwatch = new Stopwatch();
  25. for(int i=0;i<50;i++)
  26. {
  27. stopwatch.Restart();
  28. results = detector.Detect(image);
  29. stopwatch.Stop();
  30. Console.WriteLine("运行次数:{0},流程耗时:{1}",i+1, stopwatch.ElapsedMilliseconds);
  31. }
  32. // 2. 使用 OpenCvSharp 加载图像用于绘制
  33. using (var mat = Cv2.ImRead(imagepath))
  34. {
  35. int imgWidth = mat.Width;
  36. int imgHeight = mat.Height;
  37. foreach (var det in results)
  38. {
  39. // 【新增】边缘过滤 - 去除紧贴上下边缘的结果
  40. //float edgeThreshold = imgHeight * 0.05f; // 边缘阈值:图像高度的 5%
  41. float edgeThreshold = 5; // 边缘阈值:图像高度的 5%
  42. // 检测框顶部或底部过于靠近边缘则跳过
  43. if (det.Y < edgeThreshold || (det.Y + det.Height) > (imgHeight - edgeThreshold))
  44. {
  45. continue;
  46. }
  47. // 坐标转换:根据检测结果是否为归一化坐标进行转换
  48. float x = det.X;
  49. float y = det.Y;
  50. float width = det.Width;
  51. float height = det.Height;
  52. // 计算边界框坐标
  53. int left = (int)x;
  54. int top = (int)y;
  55. int right = (int)(x + width);
  56. int bottom = (int)(y + height);
  57. // 确保坐标在图像范围内
  58. left = Math.Max(0, left);
  59. top = Math.Max(0, top);
  60. right = Math.Min(imgWidth, right);
  61. bottom = Math.Min(imgHeight, bottom);
  62. // 绘制矩形框 (BGR: 绿色)
  63. Cv2.Rectangle(mat, new CvPoint(left, top), new CvPoint(right, bottom), new Scalar(0, 255, 0), 2);
  64. // 准备标签文本
  65. string className = detector._classNames[det.ClassId];
  66. string label = $"{className}: {det.Confidence:F2}";
  67. // 计算文本大小
  68. var textSize = Cv2.GetTextSize(label, HersheyFonts.HersheySimplex, 0.5, 1, out int baseline);
  69. // 绘制标签背景
  70. Cv2.Rectangle(mat,
  71. new CvPoint(left, top - textSize.Height - 5),
  72. new CvPoint(left + textSize.Width, top),
  73. new Scalar(0, 255, 0),
  74. -1);
  75. // 绘制标签文本
  76. Cv2.PutText(mat, label, new CvPoint(left, top - 5),
  77. HersheyFonts.HersheySimplex, 0.5, new Scalar(0, 0, 0), 1);
  78. }
  79. Cv2.ImShow("result", ResizeMat(mat));
  80. // 保存结果图像
  81. //Cv2.ImWrite("Model/result_2025-08-11-09-55-30-647.jpg", mat);
  82. }
  83. }
  84. }
  85. Cv2.WaitKey(0);
  86. }
  87. // 非极大值抑制 (NMS) - 去除重叠框,保留置信度高的结果
  88. static List<Detection> ApplyNMS(List<Detection> detections, float iouThreshold = 0.45f)
  89. {
  90. if (detections.Count == 0) return detections;
  91. // 按置信度降序排序
  92. var sorted = detections.OrderByDescending(d => d.Confidence).ToList();
  93. var selected = new List<Detection>();
  94. while (sorted.Count > 0)
  95. {
  96. // 选择置信度最高的检测框
  97. var best = sorted[0];
  98. selected.Add(best);
  99. sorted.RemoveAt(0);
  100. // 移除与当前框 IoU 超过阈值的其他框
  101. sorted = sorted.Where(d =>
  102. {
  103. float iou = CalculateIoU(best, d);
  104. return iou < iouThreshold;
  105. }).ToList();
  106. }
  107. return selected;
  108. }
  109. // 计算两个检测框的 IoU (Intersection over Union)
  110. static float CalculateIoU(Detection a, Detection b)
  111. {
  112. // 计算交集坐标
  113. float x1 = Math.Max(a.X, b.X);
  114. float y1 = Math.Max(a.Y, b.Y);
  115. float x2 = Math.Min(a.X + a.Width, b.X + b.Width);
  116. float y2 = Math.Min(a.Y + a.Height, b.Y + b.Height);
  117. // 计算交集面积
  118. float intersection = Math.Max(0, x2 - x1) * Math.Max(0, y2 - y1);
  119. // 计算并集面积
  120. float areaA = a.Width * a.Height;
  121. float areaB = b.Width * b.Height;
  122. float union = areaA + areaB - intersection;
  123. return union > 0 ? intersection / union : 0;
  124. }
  125. static Mat ResizeMat(Mat mat)
  126. {
  127. Mat resizedImage = new Mat();
  128. double maxSize = 900;
  129. double scale = Math.Min(maxSize / mat.Width, maxSize / mat.Height);
  130. OpenCvSharp.Size scaledSize = new OpenCvSharp.Size(mat.Width * scale, mat.Height * scale);
  131. Cv2.Resize(mat, resizedImage, scaledSize);
  132. return resizedImage;
  133. }
  134. //public static void CheckGpuUsage()
  135. //{
  136. // var providers = SessionOptions.GetAvailableProviders();
  137. // Console.WriteLine("可用的执行提供程序:");
  138. // foreach (var provider in providers)
  139. // {
  140. // Console.WriteLine($"- {provider}");
  141. // }
  142. // // 应该能看到 "DmlExecutionProvider" 或 "OpenVinoExecutionProvider"
  143. //}
  144. }
  145. }