视觉修改

This commit is contained in:
17860779768
2025-08-25 16:33:58 +08:00
commit 2e46747ba9
49 changed files with 11062 additions and 0 deletions

View 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("检测协调器已关闭。");
}
}
}

View 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(); // 浅克隆对于这个类足够了
}
}
}

View 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模型已释放。");
}
}
}
}