using OpenCvSharp; using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using CvPoint = OpenCvSharp.Point; namespace YoloTest { internal class Program { static void Main(string[] args) { string imagepath = "Model/2025-08-11-09-40-52-345.jpg"; string ModelPath = "Model/S_best_stop_aug_ckpt.onnx"; using (var detector = new YoloV6Detector(ModelPath, new[] { "OK", "NG" },true)) { // 1. 使用 System.Drawing 加载图像用于检测 using (var image = Image.FromFile(imagepath)) { List results = new List(); Stopwatch stopwatch = new Stopwatch(); for(int i=0;i<50;i++) { stopwatch.Restart(); results = detector.Detect(image); stopwatch.Stop(); Console.WriteLine("运行次数:{0},流程耗时:{1}",i+1, stopwatch.ElapsedMilliseconds); } // 2. 使用 OpenCvSharp 加载图像用于绘制 using (var mat = Cv2.ImRead(imagepath)) { int imgWidth = mat.Width; int imgHeight = mat.Height; foreach (var det in results) { // 【新增】边缘过滤 - 去除紧贴上下边缘的结果 //float edgeThreshold = imgHeight * 0.05f; // 边缘阈值:图像高度的 5% float edgeThreshold = 5; // 边缘阈值:图像高度的 5% // 检测框顶部或底部过于靠近边缘则跳过 if (det.Y < edgeThreshold || (det.Y + det.Height) > (imgHeight - edgeThreshold)) { continue; } // 坐标转换:根据检测结果是否为归一化坐标进行转换 float x = det.X; float y = det.Y; float width = det.Width; float height = det.Height; // 计算边界框坐标 int left = (int)x; int top = (int)y; int right = (int)(x + width); int bottom = (int)(y + height); // 确保坐标在图像范围内 left = Math.Max(0, left); top = Math.Max(0, top); right = Math.Min(imgWidth, right); bottom = Math.Min(imgHeight, bottom); // 绘制矩形框 (BGR: 绿色) Cv2.Rectangle(mat, new CvPoint(left, top), new CvPoint(right, bottom), new Scalar(0, 255, 0), 2); // 准备标签文本 string className = detector._classNames[det.ClassId]; string label = $"{className}: {det.Confidence:F2}"; // 计算文本大小 var textSize = Cv2.GetTextSize(label, HersheyFonts.HersheySimplex, 0.5, 1, out int baseline); // 绘制标签背景 Cv2.Rectangle(mat, new CvPoint(left, top - textSize.Height - 5), new CvPoint(left + textSize.Width, top), new Scalar(0, 255, 0), -1); // 绘制标签文本 Cv2.PutText(mat, label, new CvPoint(left, top - 5), HersheyFonts.HersheySimplex, 0.5, new Scalar(0, 0, 0), 1); } Cv2.ImShow("result", ResizeMat(mat)); // 保存结果图像 //Cv2.ImWrite("Model/result_2025-08-11-09-55-30-647.jpg", mat); } } } Cv2.WaitKey(0); } // 非极大值抑制 (NMS) - 去除重叠框,保留置信度高的结果 static List ApplyNMS(List detections, float iouThreshold = 0.45f) { if (detections.Count == 0) return detections; // 按置信度降序排序 var sorted = detections.OrderByDescending(d => d.Confidence).ToList(); var selected = new List(); while (sorted.Count > 0) { // 选择置信度最高的检测框 var best = sorted[0]; selected.Add(best); sorted.RemoveAt(0); // 移除与当前框 IoU 超过阈值的其他框 sorted = sorted.Where(d => { float iou = CalculateIoU(best, d); return iou < iouThreshold; }).ToList(); } return selected; } // 计算两个检测框的 IoU (Intersection over Union) static float CalculateIoU(Detection a, Detection b) { // 计算交集坐标 float x1 = Math.Max(a.X, b.X); float y1 = Math.Max(a.Y, b.Y); float x2 = Math.Min(a.X + a.Width, b.X + b.Width); float y2 = Math.Min(a.Y + a.Height, b.Y + b.Height); // 计算交集面积 float intersection = Math.Max(0, x2 - x1) * Math.Max(0, y2 - y1); // 计算并集面积 float areaA = a.Width * a.Height; float areaB = b.Width * b.Height; float union = areaA + areaB - intersection; return union > 0 ? intersection / union : 0; } static Mat ResizeMat(Mat mat) { Mat resizedImage = new Mat(); double maxSize = 900; double scale = Math.Min(maxSize / mat.Width, maxSize / mat.Height); OpenCvSharp.Size scaledSize = new OpenCvSharp.Size(mat.Width * scale, mat.Height * scale); Cv2.Resize(mat, resizedImage, scaledSize); return resizedImage; } //public static void CheckGpuUsage() //{ // var providers = SessionOptions.GetAvailableProviders(); // Console.WriteLine("可用的执行提供程序:"); // foreach (var provider in providers) // { // Console.WriteLine($"- {provider}"); // } // // 应该能看到 "DmlExecutionProvider" 或 "OpenVinoExecutionProvider" //} } }