视觉修改
This commit is contained in:
		
							
								
								
									
										149
									
								
								Check.Main/Infer/DetectionCoordinator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								Check.Main/Infer/DetectionCoordinator.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,149 @@ | ||||
| using Check.Main.Camera; | ||||
| using Check.Main.Common; | ||||
| using System; | ||||
| using System.Collections.Concurrent; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Check.Main.Infer | ||||
| { | ||||
|     public static class DetectionCoordinator | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// 定义存储所有相机处理器的字典 | ||||
|         /// 键是相机的唯一编号 (CameraIndex),值是对应的处理器实例。 | ||||
|         /// </summary> | ||||
|         private static ConcurrentDictionary<int, CameraProcessor> _processors = new ConcurrentDictionary<int, CameraProcessor>(); | ||||
|         /// <summary> | ||||
|         /// 用于在产品组装时进行同步,确保线程安全 | ||||
|         /// </summary> | ||||
|         private static ConcurrentDictionary<long, ProductAssembly> _productAssemblies = new ConcurrentDictionary<long, ProductAssembly>(); | ||||
|         /// <summary> | ||||
|         /// 可用的相机数量 | ||||
|         /// </summary> | ||||
|         private static int _enabledCameraCount = 0; | ||||
|  | ||||
|         public static event EventHandler<DetectionResultEventArgs> OnDetectionCompleted; | ||||
|         public static bool IsDetectionRunning { get; private set; } = false; | ||||
|  | ||||
|         // OnDetectionCompleted 事件现在也属于这里 | ||||
|         //public static event EventHandler<DetectionResultEventArgs> OnDetectionCompleted; | ||||
|  | ||||
|         public static void StartDetection() | ||||
|         { | ||||
|             if (!IsDetectionRunning) | ||||
|             { | ||||
|                 IsDetectionRunning = true; | ||||
|                 ThreadSafeLogger.Log("检测统计已启动。"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public static void StopDetection() | ||||
|         { | ||||
|             if (IsDetectionRunning) | ||||
|             { | ||||
|                 IsDetectionRunning = false; | ||||
|                 ThreadSafeLogger.Log("检测统计已停止。"); | ||||
|             } | ||||
|         } | ||||
|         public static void Initialize(List<CameraSettings> cameraSettings, List<ModelSettings> modelSettings) | ||||
|         { | ||||
|             Shutdown(); // 先关闭旧的 | ||||
|             var enabledCameras = cameraSettings.Where(c => c.IsEnabled).ToList(); | ||||
|             _enabledCameraCount = enabledCameras.Count; | ||||
|             if (_enabledCameraCount == 0) return; | ||||
|  | ||||
|             foreach (var camSetting in enabledCameras) | ||||
|             { | ||||
|                 // 找到与相机编号匹配的模型 | ||||
|                 var model = modelSettings.FirstOrDefault(m => m.Id == camSetting.ModelID); | ||||
|                 if (model == null) | ||||
|                 { | ||||
|                     ThreadSafeLogger.Log($"[警告] 找不到与相机 #{camSetting.CameraIndex} 匹配的模型,该相机将无法处理图像。"); | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 var processor = new CameraProcessor(camSetting.CameraIndex,camSetting.ModelID); | ||||
|                 _processors.TryAdd(camSetting.CameraIndex, processor); | ||||
|                 processor.Start(); | ||||
|             } | ||||
|             ThreadSafeLogger.Log($"检测协调器已初始化,启动了 {_processors.Count} 个相机处理线程。"); | ||||
|         } | ||||
|  | ||||
|         public static void EnqueueImage(int cameraIndex, Bitmap bmp) | ||||
|         { | ||||
|             if (_processors.TryGetValue(cameraIndex, out var processor)) | ||||
|             { | ||||
|                 processor.EnqueueImage(bmp); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 // 如果找不到处理器,必须释放Bitmap防止泄漏 | ||||
|                 bmp?.Dispose(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // 供 CameraProcessor 回调,用以组装产品 | ||||
|         public static void AssembleProduct(ImageData data, string result) | ||||
|         { | ||||
|             var assembly = _productAssemblies.GetOrAdd(data.ProductId, (id) => new ProductAssembly(id, _enabledCameraCount)); | ||||
|  | ||||
|             if (assembly.AddResult(data.CameraIndex, result)) | ||||
|             { | ||||
|                 string finalResult = assembly.GetFinalResult(); | ||||
|                 ThreadSafeLogger.Log($"产品 #{assembly.ProductId} 已检测完毕,最终结果: {finalResult}"); | ||||
|  | ||||
|                 // 只有在检测运行时,才触发事件 | ||||
|                 if (IsDetectionRunning) | ||||
|                 { | ||||
|                     OnDetectionCompleted?.Invoke(null, new DetectionResultEventArgs(finalResult == "OK")); | ||||
|                 } | ||||
|  | ||||
|                 if (_productAssemblies.TryRemove(assembly.ProductId, out var finishedAssembly)) | ||||
|                 { | ||||
|                     finishedAssembly.Dispose(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         /// <summary> | ||||
|         /// 命令所有活动的相机处理器重置它们的内部计数器。 | ||||
|         /// </summary> | ||||
|         public static void ResetAllCounters() | ||||
|         { | ||||
|             foreach (var processor in _processors.Values) | ||||
|             { | ||||
|                 processor.ResetCounter(); | ||||
|             } | ||||
|             ThreadSafeLogger.Log("所有相机处理器的产品计数器已重置。"); | ||||
|         } | ||||
|  | ||||
|         public static CameraProcessor GetProcessor(int cameraIndex) | ||||
|         { | ||||
|             _processors.TryGetValue(cameraIndex, out var p); | ||||
|             return p; | ||||
|         } | ||||
|         public static IEnumerable<CameraProcessor> GetAllProcessors() | ||||
|         { | ||||
|             return _processors.Values; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         public static void Shutdown() | ||||
|         { | ||||
|             foreach (var processor in _processors.Values) | ||||
|             { | ||||
|                 processor.Dispose(); | ||||
|             } | ||||
|             _processors.Clear(); | ||||
|  | ||||
|             foreach (var assembly in _productAssemblies.Values) | ||||
|             { | ||||
|                 assembly.Dispose(); | ||||
|             } | ||||
|             _productAssemblies.Clear(); | ||||
|             ThreadSafeLogger.Log("检测协调器已关闭。"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										131
									
								
								Check.Main/Infer/ModelSettings.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								Check.Main/Infer/ModelSettings.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,131 @@ | ||||
| using Check.Main.Common; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.ComponentModel; | ||||
| using System.Linq; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.Serialization; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Check.Main.Infer | ||||
| { | ||||
|     public enum DetectDevice | ||||
|     { | ||||
|         [Description("CPU")] | ||||
|         CPU = 0, | ||||
|  | ||||
|         [Description("GPU")] | ||||
|         GPU, | ||||
|  | ||||
|         [Description("VPU")] | ||||
|         VPU, | ||||
|     } | ||||
|     public enum ModelVersion | ||||
|     { | ||||
|         [Description("v8")] | ||||
|         V8 = 0, | ||||
|  | ||||
|         [Description("v11")] | ||||
|         V11, | ||||
|     } | ||||
|     public enum CheckModelType | ||||
|     { | ||||
|         [Description("分类")] | ||||
|         Classification, | ||||
|  | ||||
|         [Description("检测")] | ||||
|         ObjectDetection, | ||||
|  | ||||
|         [Description("OBB")] | ||||
|         ObbDetection, | ||||
|  | ||||
|         [Description("分割")] | ||||
|         Segmentation, | ||||
|  | ||||
|         [Description("位姿")] | ||||
|         PoseEstimation | ||||
|     } | ||||
|  | ||||
|     [Serializable] // 确保可被XML序列化 | ||||
|     public class ModelSettings : INotifyPropertyChanged, ICloneable | ||||
|     { | ||||
|         public event PropertyChangedEventHandler PropertyChanged; | ||||
|  | ||||
|         private int _id; | ||||
|         private string _name = "New Model"; | ||||
|         private string _path = ""; | ||||
|         private DetectDevice _checkDevice=DetectDevice.CPU; | ||||
|         private ModelVersion _mVersion=ModelVersion.V8; | ||||
|         private CheckModelType _mType = CheckModelType.Classification; | ||||
|         private bool _isEnabled = true; | ||||
|  | ||||
|         [Category("基本信息"), DisplayName("模型编号"), Description("模型的唯一标识符,用于与相机编号对应。")] | ||||
|         public int Id | ||||
|         { | ||||
|             get => _id; | ||||
|             set { if (_id != value) { _id = value; OnPropertyChanged(); } } | ||||
|         } | ||||
|  | ||||
|         [Category("基本信息"), DisplayName("模型名称"), Description("给模型起一个易于识别的别名。")] | ||||
|         public string Name | ||||
|         { | ||||
|             get => _name; | ||||
|             set { if (_name != value) { _name = value; OnPropertyChanged(); } } | ||||
|         } | ||||
|         [Category("基本信息"), DisplayName("推理设备"), Description("推理模型的设备。")] | ||||
|         [TypeConverter(typeof(EnumDescriptionTypeConverter))] | ||||
|         public DetectDevice CheckDevice | ||||
|         { | ||||
|             get => _checkDevice; | ||||
|             set { if (_checkDevice != value) { _checkDevice = value; OnPropertyChanged(); } } | ||||
|         } | ||||
|  | ||||
|         [Category("基本信息"), DisplayName("模型版本"), Description("推理模型的版本。")] | ||||
|         [TypeConverter(typeof(EnumDescriptionTypeConverter))] | ||||
|         public ModelVersion MVersion | ||||
|         { | ||||
|             get => _mVersion; | ||||
|             set { if (_mVersion != value) { _mVersion = value; OnPropertyChanged(); } } | ||||
|         } | ||||
|         [Category("基本信息"), DisplayName("模型类型"), Description("推理模型的类型。")] | ||||
|         [TypeConverter(typeof(EnumDescriptionTypeConverter))] | ||||
|         public CheckModelType MType | ||||
|         { | ||||
|             get => _mType; | ||||
|             set { if (_mType != value) { _mType = value; OnPropertyChanged(); } } | ||||
|         } | ||||
|  | ||||
|         [Category("基本信息"), DisplayName("是否启用"), Description("是否在程序启动时是否启用模型")] | ||||
|         public bool IsEnabled | ||||
|         { | ||||
|             get => _isEnabled; | ||||
|             set | ||||
|             { | ||||
|                 if (_isEnabled != value) | ||||
|                 { | ||||
|                     _isEnabled = value; | ||||
|                     OnPropertyChanged(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         [Category("文件"), DisplayName("模型路径"), Description("选择模型文件(.onnx, .bin, etc., .pt)。")] | ||||
|         [Editor(typeof(System.Windows.Forms.Design.FileNameEditor), typeof(System.Drawing.Design.UITypeEditor))] | ||||
|         public string Path | ||||
|         { | ||||
|             get => _path; | ||||
|             set { if (_path != value) { _path = value; OnPropertyChanged(); } } | ||||
|         } | ||||
|  | ||||
|         protected void OnPropertyChanged([CallerMemberName] string propertyName = null) | ||||
|         { | ||||
|             PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); | ||||
|         } | ||||
|  | ||||
|         public object Clone() | ||||
|         { | ||||
|             return this.MemberwiseClone(); // 浅克隆对于这个类足够了 | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										102
									
								
								Check.Main/Infer/YoloModelManager.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								Check.Main/Infer/YoloModelManager.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | ||||
| using Check.Main.Common; | ||||
| using System; | ||||
| using System.Collections.Concurrent; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
| using YoloDotNet; | ||||
| using YoloDotNet.Models; | ||||
|  | ||||
| namespace Check.Main.Infer | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 静态全局YOLO模型管理器。 | ||||
|     /// 负责在程序启动时加载所有模型,并在关闭时释放资源。 | ||||
|     /// </summary> | ||||
|     public static class YoloModelManager | ||||
|     { | ||||
|         // 使用 ConcurrentDictionary 保证线程安全 | ||||
|         private static readonly ConcurrentDictionary<int, Yolo> _loadedModels = new ConcurrentDictionary<int, Yolo>(); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 根据模型配置列表初始化所有YOLO模型实例。 | ||||
|         /// 应在程序启动时调用一次。 | ||||
|         /// </summary> | ||||
|         /// <param name="modelSettings">模型配置列表。</param> | ||||
|         public static void Initialize(List<ModelSettings> modelSettings) | ||||
|         { | ||||
|             Shutdown(); // 先确保清理掉旧实例 | ||||
|  | ||||
|             if (modelSettings == null) return; | ||||
|  | ||||
|             ThreadSafeLogger.Log("开始加载YOLO模型..."); | ||||
|             foreach (var setting in modelSettings) | ||||
|             { | ||||
|                 bool gpuUse = false; | ||||
|                 if (setting.CheckDevice == DetectDevice.GPU) | ||||
|                 { | ||||
|                     gpuUse = true; | ||||
|                 } | ||||
|  | ||||
|                 if (string.IsNullOrEmpty(setting.Path) || !File.Exists(setting.Path)) | ||||
|                 { | ||||
|                     ThreadSafeLogger.Log($"[警告] 模型 '{setting.Name}' (ID: {setting.Id}) 路径无效或文件不存在,已跳过加载。"); | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 try | ||||
|                 { | ||||
|                     // 创建YOLO实例 | ||||
|                     var yolo = new Yolo(new YoloOptions | ||||
|                     { | ||||
|                         OnnxModel = setting.Path, | ||||
|                         // 您可以根据需要从配置中读取这些值 | ||||
|                         ModelType = (YoloDotNet.Enums.ModelType)setting.MType, | ||||
|                         Cuda = gpuUse, // 推荐使用GPU | ||||
|                         PrimeGpu = false | ||||
|                     }); | ||||
|  | ||||
|                     if (_loadedModels.TryAdd(setting.Id, yolo)) | ||||
|                     { | ||||
|                         ThreadSafeLogger.Log($"成功加载模型 '{setting.Name}' (ID: {setting.Id})。"); | ||||
|                     } | ||||
|                 } | ||||
|                 catch (Exception ex) | ||||
|                 { | ||||
|                     ThreadSafeLogger.Log($"[错误] 加载模型 '{setting.Name}' (ID: {setting.Id}) 失败: {ex.Message}"); | ||||
|                 } | ||||
|             } | ||||
|             ThreadSafeLogger.Log($"YOLO模型加载完成,共成功加载 {_loadedModels.Count} 个模型。"); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 获取指定ID的已加载YOLO模型。 | ||||
|         /// </summary> | ||||
|         /// <param name="modelId">模型编号。</param> | ||||
|         /// <returns>Yolo实例,如果未找到则返回null。</returns> | ||||
|         public static Yolo GetModel(int modelId) | ||||
|         { | ||||
|             _loadedModels.TryGetValue(modelId, out var yolo); | ||||
|             return yolo; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 释放所有已加载的YOLO模型资源。 | ||||
|         /// 应在程序关闭时调用。 | ||||
|         /// </summary> | ||||
|         public static void Shutdown() | ||||
|         { | ||||
|             if (_loadedModels.Count > 0) | ||||
|             { | ||||
|                 ThreadSafeLogger.Log("正在释放所有YOLO模型..."); | ||||
|                 foreach (var yolo in _loadedModels.Values) | ||||
|                 { | ||||
|                     yolo?.Dispose(); | ||||
|                 } | ||||
|                 _loadedModels.Clear(); | ||||
|                 ThreadSafeLogger.Log("所有YOLO模型已释放。"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user