// CameraGroup.cs 相机组线程管理类,控制相机采集和识别的线程运行,开放有算法的接口 using MvCameraControl; using MvvmScaffoldFrame48.DLL.CameraTools; using MvvmScaffoldFrame48.Model.ResultModel; using MvvmScaffoldFrame48.Model.StorageModel.SystemConfig; using System; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; namespace MvvmScaffoldFrame48.DLL.ThreadManager { /// /// 相机组配置和状态管理类 /// 管理单个相机的采集和处理线程及相关资源 /// public class CameraGroup { #region 变量与实例 //相机线程的休眠时间,默认为0,即不休眠。在采集节拍没有那么高时,增加此值降低性能消耗 private int CameraSleepTime = 0; //相机 public HikCamera Camera { get; set; } //相机ID public int CameraId { get; set; } //是否运行中 public bool IsRunning { get; set; } //相机处理线程 public Task CameraTask { get; set; } //图像处理线程 public Task ProcessingTask { get; set; } //图像队列 public ConcurrentQueue ImageQueue { get; set; } //信号量 public SemaphoreSlim QueueSemaphore { get; set; } //取消令牌 public CancellationTokenSource CancellationTokenSource { get; set; } // 图像处理算法(接口方式) public IImageProcessingAlgorithmHikVision ImageProcessor { get; set; } // 结果发送事件,当图像处理完成时触发 public event EventHandler ProcessResultAvailable; // 相机配置 public CameraProcessConfigModel Configuration { get; set; } #endregion #region 公共方法 /// /// 启动相机组(包括采集和处理线程) /// public void Start() { if (Camera == null) { Console.WriteLine($"相机 {CameraId} 未初始化"); return; } if (Camera.Device == null) { Console.WriteLine($"相机 {CameraId} 未初始化"); } if (Camera.Device.IsConnected == false) { Console.WriteLine($"相机 {CameraId} 未打开"); return; } if (IsRunning) return; // 根据配置加载算法 LoadAlgorithmFromConfiguration(); Camera.StartReceiveFuntion(); // 重置取消令牌 CancellationTokenSource = new CancellationTokenSource(); var token = CancellationTokenSource.Token; // 启动相机采集线程 CameraTask = Task.Factory.StartNew(() => CameraCaptureLoop(token), token, TaskCreationOptions.LongRunning, TaskScheduler.Default); // 启动图像处理线程 ProcessingTask = Task.Factory.StartNew(() => ImageProcessingLoop(token), token, TaskCreationOptions.LongRunning, TaskScheduler.Default); IsRunning = true; Console.WriteLine($"相机组 {CameraId} 已启动"); } /// /// 停止相机组 /// public async void Stop() { if (!IsRunning) return; // 发送取消信号 CancellationTokenSource.Cancel(); // 等待线程完成 try { if (CameraTask != null) await CameraTask; if (ProcessingTask != null) await ProcessingTask; } catch (OperationCanceledException) { // 正常取消,忽略异常 } IsRunning = false; Camera.StopReceiveFuntion(); Console.WriteLine($"相机组 {CameraId} 已停止"); } /// /// 更新算法参数 /// /// 新参数 public void UpdateAlgorithmParameters(object parameters) { if (ImageProcessor != null && parameters != null) { string parametersjson = ImageProcessor.GetSaveJson(); ImageProcessor.Configure(parametersjson); // 更新配置 if (Configuration != null) { Configuration.AlgorithmParameters = parametersjson; } Console.WriteLine($"相机 {CameraId} 算法参数已更新"); } } #endregion #region 私有方法 /// /// 设置图像处理算法 /// /// 算法名称 private void SetProcessingAlgorithm(string algorithmName, string parameters = null) { if (string.IsNullOrEmpty(algorithmName)) { ImageProcessor = null; return; } try { // 根据算法名称创建实例(这里可以使用简单的工厂方法或反射) ImageProcessor = ImageProcessingAlgorithmHikVisionFactory.CreateAlgorithm(algorithmName); // 配置参数 if (parameters != null && ImageProcessor != null) { ImageProcessor.Configure(parameters); } Console.WriteLine($"相机 {CameraId} 成功设置算法: {algorithmName}"); } catch (Exception ex) { Console.WriteLine($"相机 {CameraId} 设置算法 {algorithmName} 失败: {ex.Message}"); } } /// /// 根据配置动态加载算法 /// private void LoadAlgorithmFromConfiguration() { if (Configuration != null && !string.IsNullOrEmpty(Configuration.ProcessingAlgorithmName)) { SetProcessingAlgorithm(Configuration.ProcessingAlgorithmName, Configuration.AlgorithmParameters); } else { // 使用默认算法(无参数) SetProcessingAlgorithm("Default"); } } /// /// 发送处理结果到通信线程的方法 /// 多个线程可以共用此方法 /// /// 处理结果数据 private void SendProcessResult(object resultData) { var eventArgs = new CameraProcessEventArgsResultModel { CameraId = this.CameraId, ResultData = resultData, Timestamp = DateTime.Now }; // 触发事件,通知订阅者有新的处理结果 ProcessResultAvailable?.Invoke(this, eventArgs); } /// /// 图像处理实现 /// private void ProcessImage(IImage imageData, int cameraId) { object resultData = null; try { // 优先使用接口方式的算法 if (ImageProcessor != null) { resultData = ImageProcessor.ProcessImage(imageData, cameraId); } // 如果都没有设置,则使用默认处理 else { Console.WriteLine($"相机 {CameraId} 未加载算法"); // 默认处理逻辑 } // 发送处理结果 SendProcessResult(resultData); // 输出处理结果 } catch (Exception ex) { Console.WriteLine($"相机 {CameraId} 图像处理错误: {ex.Message}"); // 发送错误结果 } } #endregion #region 线程主体方法 /// /// 相机采集循环 /// private async void CameraCaptureLoop(CancellationToken token) { //int frameCount = 0; try { while (!token.IsCancellationRequested) { // 模拟相机图像采集(无休眠,持续采集) if (Camera.GetOnceImage(out IFrameOut imageData)) { // 将图像放入队列 ImageQueue.Enqueue(imageData.Image.Clone() as IImage); Console.WriteLine($"相机 {CameraId} 采集到图像,帧号{imageData.FrameNum}"); QueueSemaphore.Release(); // 通知处理线程有新数据 imageData.Dispose(); } // 这里不添加休眠,保持最大帧率采集 await Task.Delay(CameraSleepTime); } } catch (OperationCanceledException) { // 线程被取消,正常退出 } catch (Exception ex) { Console.WriteLine($"相机 {CameraId} 采集异常: {ex.Message}"); } } /// /// 图像处理循环 /// private async void ImageProcessingLoop(CancellationToken token) { try { while (!token.IsCancellationRequested) { // 等待图像数据 await QueueSemaphore.WaitAsync(token); // 从队列获取图像 if (ImageQueue.TryDequeue(out IImage imageData)) { // 执行图像处理逻辑 ProcessImage(imageData, CameraId); imageData.Dispose(); // 可以根据队列长度决定是否短暂休眠以避免过度占用CPU if (ImageQueue.Count == 0) { await Task.Delay(1, token); // 短暂让出CPU } } } } catch (OperationCanceledException) { // 线程被取消,正常退出 } catch (Exception ex) { Console.WriteLine($"相机 {CameraId} 处理异常: {ex.Message}"); } } #endregion } }