修改框架(未完全完成)实现单个相机分开绑定算法
This commit is contained in:
		
							
								
								
									
										409
									
								
								Check.Main/Infer/YoloDetector.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										409
									
								
								Check.Main/Infer/YoloDetector.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,409 @@ | ||||
| using Check.Main.Camera; | ||||
| using Check.Main.Common; | ||||
| using OpenCvSharp; | ||||
| using SkiaSharp; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Drawing; | ||||
| using System.Linq; | ||||
| using YoloDotNet; | ||||
| using YoloDotNet.Models; | ||||
|  | ||||
| namespace Check.Main.Infer | ||||
| { | ||||
|     /// <summary> | ||||
|     /// YOLO 检测结果对象,包含标签、置信度与检测框 | ||||
|     /// </summary> | ||||
|     public class YoloPrediction | ||||
|     { | ||||
|         public YoloLabel Label { get; set; } | ||||
|         public float Score { get; set; } | ||||
|         public BoundingBox BoundingBox { get; set; } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// YOLO 类别标签 | ||||
|     /// </summary> | ||||
|     public class YoloLabel | ||||
|     { | ||||
|         public string Name { get; set; } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 检测框坐标结构体 | ||||
|     /// </summary> | ||||
|     public struct BoundingBox | ||||
|     { | ||||
|         public float Left { get; set; } | ||||
|         public float Top { get; set; } | ||||
|         public float Width { get; set; } | ||||
|         public float Height { get; set; } | ||||
|  | ||||
|         public BoundingBox(float left, float top, float width, float height) | ||||
|         { | ||||
|             Left = left; | ||||
|             Top = top; | ||||
|             Width = width; | ||||
|             Height = height; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// YOLO 目标检测器实现类 | ||||
|     /// </summary> | ||||
|     public class YoloDetector : IDetector, IDisposable | ||||
|     { | ||||
|         private Yolo _yoloModel; | ||||
|         private int _modelID; | ||||
|         private float _confidenceThreshold = 0.25f; | ||||
|         private float _nmsThreshold = 0.45f; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 初始化 YOLO 检测器并加载模型 | ||||
|         /// </summary> | ||||
|         /// <param name="modelIdStr">模型 ID 字符串</param> | ||||
|         /// <param name="detectionSettings">可选检测参数</param> | ||||
|         /// <exception cref="ArgumentException">ID 无效</exception> | ||||
|         /// <exception cref="InvalidOperationException">模型未加载</exception> | ||||
|         public void Initialize(string modelIdStr, object detectionSettings = null) | ||||
|         { | ||||
|             if (string.IsNullOrWhiteSpace(modelIdStr)) | ||||
|                 throw new ArgumentException("模型ID字符串不能为空。", nameof(modelIdStr)); | ||||
|  | ||||
|             if (!int.TryParse(modelIdStr, out _modelID)) | ||||
|                 throw new ArgumentException("模型ID必须为有效整数。", nameof(modelIdStr)); | ||||
|  | ||||
|             _yoloModel = YoloModelManager.GetModel(_modelID) | ||||
|                 ?? throw new InvalidOperationException($"YOLO 模型 (ID: {_modelID}) 未加载或找不到。"); | ||||
|  | ||||
|             if (detectionSettings is YoloDetectionSettings yoloSettings) | ||||
|             { | ||||
|                 _confidenceThreshold = Math.Clamp(yoloSettings.ConfidenceThreshold, 0f, 1f); | ||||
|                 _nmsThreshold = Math.Clamp(yoloSettings.NmsThreshold, 0f, 1f); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 执行检测,判断是否含有 logo 类对象 | ||||
|         /// </summary> | ||||
|         public DetectionResult Detect(Bitmap image) | ||||
|         { | ||||
|             if (_yoloModel == null) | ||||
|                 throw new InvalidOperationException("YoloDetector 未初始化或模型未加载。"); | ||||
|  | ||||
|             if (image == null) | ||||
|                 return new DetectionResult(false, "输入图像为空。"); | ||||
|  | ||||
|             try | ||||
|             { | ||||
|                 using var skBitmap = CameraProcessor.ToSKBitmapFast(image); | ||||
|                 if (skBitmap == null) | ||||
|                     return new DetectionResult(false, "图像转换失败。"); | ||||
|  | ||||
|                 using var skImage = SKImage.FromBitmap(skBitmap); | ||||
|                 if (skImage == null) | ||||
|                     return new DetectionResult(false, "无法生成 SKImage。"); | ||||
|  | ||||
|                 var predictions = _yoloModel.RunObjectDetection( | ||||
|                     skImage, | ||||
|                     confidence: _confidenceThreshold, | ||||
|                     iou: _nmsThreshold | ||||
|                 ); | ||||
|  | ||||
|                 // 检查是否检测到 logo | ||||
|                 bool foundLogo = predictions.Any(p => | ||||
|                     p.Label.Name.Equals("logo", StringComparison.OrdinalIgnoreCase)); | ||||
|  | ||||
|                 return foundLogo | ||||
|                     ? new DetectionResult(false, "NG") | ||||
|                     : new DetectionResult(true, "OK"); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 return new DetectionResult(false, $"检测失败: {ex.Message}"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 在图像上绘制检测框与标签 | ||||
|         /// </summary> | ||||
|         public Bitmap DrawYoloPredictions(Bitmap source, IEnumerable<YoloPrediction> predictions) | ||||
|         { | ||||
|             if (source == null) | ||||
|                 throw new ArgumentNullException(nameof(source)); | ||||
|  | ||||
|             if (predictions == null || !predictions.Any()) | ||||
|                 return (Bitmap)source.Clone(); | ||||
|  | ||||
|             Bitmap output = (Bitmap)source.Clone(); | ||||
|  | ||||
|             using var graphics = Graphics.FromImage(output); | ||||
|             using var pen = new Pen(Color.Yellow, 2); | ||||
|             using var font = new Font("Arial", 10, FontStyle.Bold); | ||||
|             using var brush = new SolidBrush(Color.Yellow); | ||||
|  | ||||
|             foreach (var pred in predictions) | ||||
|             { | ||||
|                 var box = pred.BoundingBox; | ||||
|                 var rect = new RectangleF(box.Left, box.Top, box.Width, box.Height); | ||||
|  | ||||
|                 // 绘制检测框 | ||||
|                 graphics.DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height); | ||||
|  | ||||
|                 // 绘制标签 | ||||
|                 string label = $"{pred.Label?.Name ?? "unknown"} ({pred.Score:P1})"; | ||||
|                 graphics.DrawString(label, font, brush, rect.X, rect.Y - 15); | ||||
|             } | ||||
|  | ||||
|             return output; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 无需显式释放模型,资源由 YoloModelManager 管理 | ||||
|         /// </summary> | ||||
|         public void Dispose() | ||||
|         { | ||||
|             //_yoloModel = null; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| //总结,区分好YoloModelManager.cs和YoloDetector.cs各自的职能,谁负责模型管理,谁负责yolo算法的执行,现在这两个文件是交织在一起比较乱的,有时间去处理一下 | ||||
| //看上面的定义的一些结构体胡总和类,就可以调用啦 | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| //using Check.Main.Camera; | ||||
| //using Check.Main.Common; | ||||
| //using SkiaSharp; | ||||
| //using System; | ||||
| //using System.Collections.Generic; | ||||
| //using System.Drawing; | ||||
| //using System.Linq; | ||||
| //using System.Text; | ||||
| //using System.Threading.Tasks; | ||||
| //using YoloDotNet; | ||||
| //using YoloDotNet.Models; | ||||
|  | ||||
|  | ||||
|  | ||||
| //namespace Check.Main.Infer | ||||
| //{ | ||||
| //    public class YoloDetector : IDetector | ||||
| //    { | ||||
| //        private Yolo _yoloModel; | ||||
| //        private int _modelID; // 需要知道模型ID来从 YoloModelManager 获取 | ||||
| //        private float _confidenceThreshold = 0.25f; | ||||
| //        private float _nmsThreshold = 0.45f; | ||||
|  | ||||
| //        public void Initialize(string modelIdStr, object detectionSettings = null) | ||||
| //        { | ||||
| //            if (!int.TryParse(modelIdStr, out _modelID)) | ||||
| //            { | ||||
| //                throw new ArgumentException("YoloDetector 初始化需要有效的模型ID字符串。", nameof(modelIdStr)); | ||||
| //            } | ||||
| //            _yoloModel = YoloModelManager.GetModel(_modelID); | ||||
| //            if (_yoloModel == null) | ||||
| //            { | ||||
| //                throw new InvalidOperationException($"YOLO 模型 (ID: {_modelID}) 未加载或找不到。"); | ||||
| //            } | ||||
|  | ||||
| //            if (detectionSettings is YoloDetectionSettings yoloSettings) | ||||
| //            { | ||||
| //                _confidenceThreshold = yoloSettings.ConfidenceThreshold; | ||||
| //                _nmsThreshold = yoloSettings.NmsThreshold; | ||||
| //                // 注意:YOLO模型的置信度和NMS阈值最好在YoloModelManager加载时设置 | ||||
| //                // 这里如果需要运行时调整,可能需要Yolo.SetThresholds方法 | ||||
| //            } | ||||
| //        } | ||||
|  | ||||
| //        public DetectionResult Detect(Bitmap image) | ||||
| //        { | ||||
| //            if (_yoloModel == null) | ||||
| //                throw new InvalidOperationException("YoloDetector 未初始化或模型未加载。"); | ||||
|  | ||||
| //            using (var skImage = CameraProcessor.ToSKBitmapFast(image)) // 使用 CameraProcessor 的静态方法 | ||||
| //            { | ||||
| //                if (skImage == null) | ||||
| //                { | ||||
| //                    return new DetectionResult(false, "图像转换失败"); | ||||
| //                } | ||||
|  | ||||
| //                // 在这里可以应用运行时阈值,如果Yolo模型支持 | ||||
| //                // _yoloModel.Confidence = _confidenceThreshold; | ||||
| //                // _yoloModel.Nms = _nmsThreshold; | ||||
|  | ||||
| //                var predictions = _yoloModel.RunObjectDetection(skImage); | ||||
|  | ||||
| //                bool isOk = !predictions.Any(); // 假设没有检测到任何目标为 OK | ||||
| //                string message = isOk ? "OK" : "NG"; | ||||
|  | ||||
| //                List<RectangleF> boundingBoxes = predictions.Select(p => new RectangleF(p.Rectangle.X, p.Rectangle.Y, p.Rectangle.Width, p.Rectangle.Height)).ToList(); | ||||
| //                Bitmap resultImage = DrawYoloPredictions(image, predictions); | ||||
|  | ||||
| //                return new DetectionResult(isOk, message, 0, boundingBoxes, resultImage); | ||||
| //            } | ||||
| //        } | ||||
|  | ||||
| //        private Bitmap DrawYoloPredictions(Bitmap originalImage, IEnumerable<YoloPrediction> predictions) | ||||
| //        { | ||||
| //            Bitmap resultBmp = (Bitmap)originalImage.Clone(); | ||||
| //            using (Graphics g = Graphics.FromImage(resultBmp)) | ||||
| //            { | ||||
| //                Pen ngPen = new Pen(Color.Red, 3); | ||||
| //                Font font = new Font("Arial", 12, FontStyle.Bold); | ||||
| //                Brush brush = new SolidBrush(Color.Red); | ||||
|  | ||||
| //                foreach (var p in predictions) | ||||
| //                { | ||||
| //                    Rectangle rect = new Rectangle((int)p.Rectangle.X, (int)p.Rectangle.Y, (int)p.Rectangle.Width, (int)p.Rectangle.Height); | ||||
| //                    g.DrawRectangle(ngPen, rect); | ||||
| //                    g.DrawString($"{p.Label} ({p.Confidence:P})", font, brush, rect.X, rect.Y - 20); | ||||
| //                } | ||||
| //            } | ||||
| //            return resultBmp; | ||||
| //        } | ||||
|  | ||||
| //        public void Dispose() | ||||
| //        { | ||||
| //            // YOLO 模型生命周期由 YoloModelManager 管理,这里不需要额外释放 | ||||
| //        } | ||||
| //    } | ||||
| //} | ||||
|  | ||||
|  | ||||
| //public DetectionResult Detect(Bitmap image) | ||||
| //{ | ||||
| //    if (_yoloModel == null) | ||||
| //        throw new InvalidOperationException("YoloDetector 未初始化或模型未加载。"); | ||||
|  | ||||
| //    using (var skBitmap = CameraProcessor.ToSKBitmapFast(image)) | ||||
| //    using (var skImage = SKImage.FromBitmap(skBitmap)) | ||||
| //    { | ||||
| //        //注意深拷贝浅拷贝的概念,复制的图片别忘了释放 | ||||
| //        var output = image.Clone(); | ||||
|  | ||||
| //        if (skImage == null) | ||||
| //            return new DetectionResult(false, "图像转换失败"); | ||||
|  | ||||
| //        //var results = _yoloModel.RunObjectDetection(skImage, confidence: 0.4f, iou: 0.5f); | ||||
|  | ||||
| //        var predictions = _yoloModel.RunObjectDetection( | ||||
| //            skImage, | ||||
| //            confidence: _confidenceThreshold, | ||||
| //            iou: _nmsThreshold | ||||
| //        ); | ||||
| //        var ExistBool = predictions.FirstOrDefault(res => res.Label.Name.Equals("logo", StringComparison.OrdinalIgnoreCase)); | ||||
| //        if (ExistBool != null) | ||||
| //        { | ||||
| //            var box = ExistBool.BoundingBox; | ||||
| //            var rect = new Rect(box.Left, box.Top, box.Width, box.Height); | ||||
|  | ||||
| //            //Cv2.Rectangle(output, rect, Scalar.Yellow, 2); | ||||
| //            //Cv2.PutText(output, $"{logoResult.Label.Name}: {logoResult.Confidence:P2}", new CvPoint(rect.X, rect.Y - 10), HersheyFonts.HersheySimplex, 0.6, Scalar.Yellow, 2); | ||||
| //        } | ||||
| //        bool isOk = !predictions.Any(); // 没有检测结果为OK | ||||
| //        string message = isOk ? "OK" : "NG"; | ||||
|  | ||||
| //        //var boundingBoxes = predictions | ||||
| //        //    .Select(p => new RectangleF(p.Rectangle.X, p.Rectangle.Y, p.Rectangle.Width, p.Rectangle.Height)) | ||||
| //        //    .ToList(); | ||||
|  | ||||
| //        //Bitmap resultImage = DrawYoloPredictions(image, predictions); | ||||
|  | ||||
| //        //return new DetectionResult(isOk, message, 0, boundingBoxes, resultImage); | ||||
| //    } | ||||
| //} | ||||
|  | ||||
| //// 注意:如果你使用的是 YoloResult,请改为 IEnumerable<YoloResult>     IEnumerable<YoloPrediction>  | ||||
| //private Bitmap DrawYoloPredictions(Bitmap originalImage, IEnumerable<YoloPrediction> predictions) | ||||
| //{ | ||||
| //    Bitmap resultBmp = (Bitmap)originalImage.Clone(); | ||||
| //    using (Graphics g = Graphics.FromImage(resultBmp)) | ||||
| //    { | ||||
| //        Pen boxPen = new Pen(Color.Red, 3); | ||||
| //        Font font = new Font("Arial", 12, FontStyle.Bold); | ||||
| //        Brush brush = new SolidBrush(Color.Red); | ||||
|  | ||||
| //        foreach (var p in predictions) | ||||
| //        { | ||||
| //            Rectangle rect = new Rectangle( | ||||
| //                (int)p.Rectangle.X, | ||||
| //                (int)p.Rectangle.Y, | ||||
| //                (int)p.Rectangle.Width, | ||||
| //                (int)p.Rectangle.Height | ||||
| //            ); | ||||
| //            g.DrawRectangle(boxPen, rect); | ||||
| //            g.DrawString($"{p.Label} ({p.Confidence:P0})", font, brush, rect.X, rect.Y - 20); | ||||
| //        } | ||||
|  | ||||
| //        boxPen.Dispose(); | ||||
| //        font.Dispose(); | ||||
| //        brush.Dispose(); | ||||
| //    } | ||||
| //    return resultBmp; | ||||
| //} | ||||
| // 错误②:CS0246 解决方法:确保 YoloPrediction 的完整命名空间正确引用。 | ||||
| // 由于你的文件开头已经有了 `using YoloDotNet.Models;` | ||||
| // 所以这里直接使用 `YoloPrediction` 应该是正确的,除非 `YoloPrediction` 不在该命名空间下。 | ||||
| // 如果问题依然存在,检查 YoloDotNet.Models 命名空间中 YoloPrediction 的具体定义。 | ||||
| //private Bitmap DrawYoloPredictions(Bitmap originalImage, IEnumerable<YoloPrediction> predictions) | ||||
| //{ | ||||
| //    Bitmap resultBmp = (Bitmap)originalImage.Clone(); | ||||
| //    using (Graphics g = Graphics.FromImage(resultBmp)) | ||||
| //    { | ||||
| //        Pen boxPen = new Pen(Color.Red, 3); | ||||
| //        Font font = new Font("Arial", 12, FontStyle.Bold); | ||||
| //        Brush brush = new SolidBrush(Color.Red); | ||||
|  | ||||
| //        foreach (var p in predictions) | ||||
| //        { | ||||
| //            Rectangle rect = new Rectangle( | ||||
| //                (int)p.Rectangle.X, | ||||
| //                (int)p.Rectangle.Y, | ||||
| //                (int)p.Rectangle.Width, | ||||
| //                (int)p.Rectangle.Height | ||||
| //            ); | ||||
| //            g.DrawRectangle(boxPen, rect); | ||||
| //            g.DrawString($"{p.Label} ({p.Confidence:P0})", font, brush, rect.X, rect.Y - 20); | ||||
| //        } | ||||
|  | ||||
| //        boxPen.Dispose(); | ||||
| //        font.Dispose(); | ||||
| //        brush.Dispose(); | ||||
| //    } | ||||
| //    return resultBmp; | ||||
| //} | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user