// 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
}
}