|
|
@@ -1,11 +1,10 @@
|
|
|
-using MvCameraControl;
|
|
|
+// 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.Collections.Generic;
|
|
|
-using System.Linq;
|
|
|
-using System.Text;
|
|
|
using System.Threading;
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
@@ -17,39 +16,34 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
/// </summary>
|
|
|
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 CancellationTokenSource CancellationTokenSource { get; set; }
|
|
|
+ //相机处理线程
|
|
|
public Task CameraTask { get; set; }
|
|
|
+ //图像处理线程
|
|
|
public Task ProcessingTask { get; set; }
|
|
|
+ //图像队列
|
|
|
public ConcurrentQueue<IImage> ImageQueue { get; set; }
|
|
|
+ //信号量
|
|
|
public SemaphoreSlim QueueSemaphore { get; set; }
|
|
|
-
|
|
|
+ //取消令牌
|
|
|
+ public CancellationTokenSource CancellationTokenSource { get; set; }
|
|
|
// 图像处理算法(接口方式)
|
|
|
public IImageProcessingAlgorithmHikVision ImageProcessor { get; set; }
|
|
|
-
|
|
|
// 结果发送事件,当图像处理完成时触发
|
|
|
public event EventHandler<CameraProcessEventArgsResultModel> ProcessResultAvailable;
|
|
|
+ // 相机配置
|
|
|
+ public CameraProcessConfigModel Configuration { get; set; }
|
|
|
+ #endregion
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// 发送处理结果到通信线程的方法
|
|
|
- /// 多个线程可以共用此方法
|
|
|
- /// </summary>
|
|
|
- /// <param name="resultData">处理结果数据</param>
|
|
|
- public void SendProcessResult(object resultData)
|
|
|
- {
|
|
|
- var eventArgs = new CameraProcessEventArgsResultModel
|
|
|
- {
|
|
|
- CameraId = this.CameraId,
|
|
|
- ResultData = resultData,
|
|
|
- Timestamp = DateTime.Now
|
|
|
- };
|
|
|
-
|
|
|
- // 触发事件,通知订阅者有新的处理结果
|
|
|
- ProcessResultAvailable?.Invoke(this, eventArgs);
|
|
|
- }
|
|
|
-
|
|
|
+ #region 公共方法
|
|
|
/// <summary>
|
|
|
/// 启动相机组(包括采集和处理线程)
|
|
|
/// </summary>
|
|
|
@@ -60,7 +54,7 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
Console.WriteLine($"相机 {CameraId} 未初始化");
|
|
|
return;
|
|
|
}
|
|
|
- if(Camera.Device == null)
|
|
|
+ if (Camera.Device == null)
|
|
|
{
|
|
|
Console.WriteLine($"相机 {CameraId} 未初始化");
|
|
|
}
|
|
|
@@ -72,6 +66,9 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
if (IsRunning)
|
|
|
return;
|
|
|
|
|
|
+ // 根据配置加载算法
|
|
|
+ LoadAlgorithmFromConfiguration();
|
|
|
+
|
|
|
Camera.StartReceiveFuntion();
|
|
|
|
|
|
// 重置取消令牌
|
|
|
@@ -120,10 +117,134 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
Console.WriteLine($"相机组 {CameraId} 已停止");
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// 更新算法参数
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="parameters">新参数</param>
|
|
|
+ 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 私有方法
|
|
|
+ /// <summary>
|
|
|
+ /// 设置图像处理算法
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="algorithmName">算法名称</param>
|
|
|
+ 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}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 根据配置动态加载算法
|
|
|
+ /// </summary>
|
|
|
+ private void LoadAlgorithmFromConfiguration()
|
|
|
+ {
|
|
|
+ if (Configuration != null && !string.IsNullOrEmpty(Configuration.ProcessingAlgorithmName))
|
|
|
+ {
|
|
|
+ SetProcessingAlgorithm(Configuration.ProcessingAlgorithmName, Configuration.AlgorithmParameters);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // 使用默认算法(无参数)
|
|
|
+ SetProcessingAlgorithm("Default");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 发送处理结果到通信线程的方法
|
|
|
+ /// 多个线程可以共用此方法
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="resultData">处理结果数据</param>
|
|
|
+ private void SendProcessResult(object resultData)
|
|
|
+ {
|
|
|
+ var eventArgs = new CameraProcessEventArgsResultModel
|
|
|
+ {
|
|
|
+ CameraId = this.CameraId,
|
|
|
+ ResultData = resultData,
|
|
|
+ Timestamp = DateTime.Now
|
|
|
+ };
|
|
|
+
|
|
|
+ // 触发事件,通知订阅者有新的处理结果
|
|
|
+ ProcessResultAvailable?.Invoke(this, eventArgs);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 图像处理实现
|
|
|
+ /// </summary>
|
|
|
+ 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 线程主体方法
|
|
|
/// <summary>
|
|
|
/// 相机采集循环
|
|
|
/// </summary>
|
|
|
- private void CameraCaptureLoop(CancellationToken token)
|
|
|
+ private async void CameraCaptureLoop(CancellationToken token)
|
|
|
{
|
|
|
//int frameCount = 0;
|
|
|
try
|
|
|
@@ -131,7 +252,7 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
while (!token.IsCancellationRequested)
|
|
|
{
|
|
|
// 模拟相机图像采集(无休眠,持续采集)
|
|
|
- if(Camera.GetOnceImage(out IFrameOut imageData))
|
|
|
+ if (Camera.GetOnceImage(out IFrameOut imageData))
|
|
|
{
|
|
|
// 将图像放入队列
|
|
|
ImageQueue.Enqueue(imageData.Image.Clone() as IImage);
|
|
|
@@ -140,6 +261,7 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
imageData.Dispose();
|
|
|
}
|
|
|
// 这里不添加休眠,保持最大帧率采集
|
|
|
+ await Task.Delay(CameraSleepTime);
|
|
|
}
|
|
|
}
|
|
|
catch (OperationCanceledException)
|
|
|
@@ -188,46 +310,6 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
Console.WriteLine($"相机 {CameraId} 处理异常: {ex.Message}");
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// 图像处理实现
|
|
|
- /// </summary>
|
|
|
- private void ProcessImage(IImage imageData,int cameraId)
|
|
|
- {
|
|
|
- object resultData = null;
|
|
|
-
|
|
|
- try
|
|
|
- {
|
|
|
- // 优先使用接口方式的算法
|
|
|
- if (ImageProcessor != null)
|
|
|
- {
|
|
|
- resultData = ImageProcessor.ProcessImage(imageData,cameraId);
|
|
|
- }
|
|
|
- // 如果都没有设置,则使用默认处理
|
|
|
- else
|
|
|
- {
|
|
|
- // 默认处理逻辑
|
|
|
- }
|
|
|
-
|
|
|
- // 发送处理结果
|
|
|
- SendProcessResult(resultData);
|
|
|
-
|
|
|
- // 输出处理结果
|
|
|
- //Console.WriteLine($"相机 {CameraId} 处理时间 {DateTime.Now.ToString("g")}");
|
|
|
- }
|
|
|
- catch (Exception ex)
|
|
|
- {
|
|
|
- Console.WriteLine($"相机 {CameraId} 图像处理错误: {ex.Message}");
|
|
|
-
|
|
|
- // 发送错误结果
|
|
|
- //var errorResult = new ProcessResultData
|
|
|
- //{
|
|
|
- // Result = $"Error_Camera{CameraId}_Frame{imageData.FrameNumber}_{ex.Message}",
|
|
|
- // ProcessingTime = DateTime.Now
|
|
|
- //};
|
|
|
-
|
|
|
- //SendProcessResult(errorResult);
|
|
|
- }
|
|
|
- }
|
|
|
+ #endregion
|
|
|
}
|
|
|
}
|