|
|
@@ -1,10 +1,12 @@
|
|
|
// CameraGroup.cs 相机组线程管理类,控制相机采集和识别的线程运行,开放有算法的接口
|
|
|
using MvCameraControl;
|
|
|
using MvvmScaffoldFrame48.DLL.CameraTools;
|
|
|
+using MvvmScaffoldFrame48.DLL.ImageAlgorithm;
|
|
|
using MvvmScaffoldFrame48.DLL.LogTools;
|
|
|
using MvvmScaffoldFrame48.DLL.SystemTools;
|
|
|
using MvvmScaffoldFrame48.Model.ResultModel;
|
|
|
using MvvmScaffoldFrame48.Model.StorageModel.Configs;
|
|
|
+using MvvmScaffoldFrame48.Model.StorageModel.HikVisionCamera;
|
|
|
using System;
|
|
|
using System.Collections.Concurrent;
|
|
|
using System.Collections.Generic;
|
|
|
@@ -74,25 +76,24 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
if (IsRunning)
|
|
|
return;
|
|
|
|
|
|
+ // 加载相机参数
|
|
|
+ LoadCameraConfiguration();
|
|
|
+
|
|
|
// 根据配置加载算法
|
|
|
LoadAlgorithmFromConfiguration();
|
|
|
|
|
|
+ //为相机增加回调方法
|
|
|
+ Camera.FrameGrabbedEvent += CameraCaptureLoop;
|
|
|
|
|
|
- //Camera.StartReceiveFuntion();
|
|
|
- Camera.FrameGrabbedEvent += CameraCaptureLoop2;
|
|
|
+ //开启相机采集
|
|
|
Camera.StartReceiveFuntionSetFrameGrabedEvent();
|
|
|
|
|
|
// 重置取消令牌
|
|
|
CancellationTokenSource = new CancellationTokenSource();
|
|
|
var token = CancellationTokenSource.Token;
|
|
|
|
|
|
- // 启动相机采集线程
|
|
|
- //CameraTask = Task.Factory.StartNew(() => CameraCaptureLoop(token),
|
|
|
- // token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
|
|
-
|
|
|
-
|
|
|
// 启动图像处理线程
|
|
|
- ProcessingTask = Task.Factory.StartNew(() => ImageProcessingbatchLoop2(token),
|
|
|
+ ProcessingTask = Task.Factory.StartNew(() => ImageProcessingbatchLoop(token),
|
|
|
token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
|
|
|
|
|
IsRunning = true;
|
|
|
@@ -206,7 +207,7 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
{
|
|
|
if(Configuration != null&& !string.IsNullOrEmpty(Configuration.CameraParameters))
|
|
|
{
|
|
|
-
|
|
|
+ Camera.LoadCameraConfig(Configuration.CameraParameters);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -267,70 +268,6 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
#endregion
|
|
|
|
|
|
#region 线程主体方法
|
|
|
- /// <summary>
|
|
|
- /// 相机采集循环
|
|
|
- /// </summary>
|
|
|
- private async void CameraCaptureLoop(CancellationToken token)
|
|
|
- {
|
|
|
- //int frameCount = 0;
|
|
|
- try
|
|
|
- {
|
|
|
- while (!token.IsCancellationRequested)
|
|
|
- {
|
|
|
- // 模拟相机图像采集(无休眠,持续采集)
|
|
|
- if (Camera.GetOnceImage(out IFrameOut imageData))
|
|
|
- {
|
|
|
- // 将图像放入队列
|
|
|
- ImageQueue.Enqueue(imageData.Clone() as IFrameOut);
|
|
|
- double QuTuYanshi = (DateTime.Now - TimeStampTools.FromUnixTimestamp((long)imageData.HostTimeStamp)).TotalMilliseconds;
|
|
|
- //Console.WriteLine($"相机 {CameraId} 采集到图像,帧号{imageData.FrameNum}");
|
|
|
- if(QuTuYanshi > 12)
|
|
|
- {
|
|
|
- Console.WriteLine($"识别落后时间{QuTuYanshi}");
|
|
|
- }
|
|
|
- QueueSemaphore.Release(); // 通知处理线程有新数据
|
|
|
- imageData.Dispose();
|
|
|
- }
|
|
|
- // 这里不添加休眠,保持最大帧率采集
|
|
|
- await Task.Delay(CameraSleepTime);
|
|
|
- }
|
|
|
- }
|
|
|
- catch (OperationCanceledException)
|
|
|
- {
|
|
|
- // 线程被取消,正常退出
|
|
|
- }
|
|
|
- catch (Exception ex)
|
|
|
- {
|
|
|
- Console.WriteLine($"相机 {CameraId} 采集异常: {ex.Message}");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// 相机回调取图
|
|
|
- /// 与循环取图二选一
|
|
|
- /// </summary>
|
|
|
- /// <param name="sender"></param>
|
|
|
- /// <param name="e"></param>
|
|
|
- private void CameraCaptureLoop(object sender, FrameGrabbedEventArgs e)
|
|
|
- {
|
|
|
- try
|
|
|
- {
|
|
|
- // 将图像放入队列
|
|
|
- ImageQueue.Enqueue(e.FrameOut.Clone() as IFrameOut);
|
|
|
- double QuTuYanshi = (DateTime.Now - TimeStampTools.FromUnixTimestamp((long)e.FrameOut.HostTimeStamp)).TotalMilliseconds;
|
|
|
- //Console.WriteLine($"相机 {CameraId} 采集到图像,帧号{imageData.FrameNum}");
|
|
|
- if (QuTuYanshi > 12)
|
|
|
- {
|
|
|
- Console.WriteLine($"识别落后时间{QuTuYanshi}");
|
|
|
- }
|
|
|
- QueueSemaphore.Release(); // 通知处理线程有新数据
|
|
|
- e.FrameOut.Dispose();
|
|
|
- }
|
|
|
- catch (Exception ex)
|
|
|
- {
|
|
|
- Console.WriteLine($"相机 {CameraId} 采集异常: {ex.Message}");
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 相机回调取图
|
|
|
@@ -338,7 +275,7 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
/// </summary>
|
|
|
/// <param name="sender"></param>
|
|
|
/// <param name="e"></param>
|
|
|
- private void CameraCaptureLoop2(object sender, FrameGrabbedEventArgs e)
|
|
|
+ private void CameraCaptureLoop(object sender, FrameGrabbedEventArgs e)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
@@ -350,25 +287,7 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
{
|
|
|
Console.WriteLine($"识别落后时间{QuTuYanshi}");
|
|
|
}
|
|
|
- if (lastframeNum == -1)
|
|
|
- {
|
|
|
- lastframeNum = e.FrameOut.FrameNum;
|
|
|
- }
|
|
|
- else if (lastframeNum == e.FrameOut.FrameNum - 1)
|
|
|
- {
|
|
|
- lastframeNum = e.FrameOut.FrameNum;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- //丢帧记录
|
|
|
- TxtLog.log(string.Format("lost frame: Width[{0}] , Height[{1}] , FrameNum[{2}] ,Frevous[{3}]",
|
|
|
- e.FrameOut.Image.Width, e.FrameOut.Image.Height, e.FrameOut.FrameNum, lastframeNum), 6);
|
|
|
- Console.WriteLine("lost frame: Width[{0}] , Height[{1}] , FrameNum[{2}] ,Frevous[{3}]",
|
|
|
- e.FrameOut.Image.Width, e.FrameOut.Image.Height, e.FrameOut.FrameNum, lastframeNum);
|
|
|
- lastframeNum = e.FrameOut.FrameNum;
|
|
|
- }
|
|
|
QueueSemaphore.Release(); // 通知处理线程有新数据
|
|
|
- e.FrameOut.Dispose();
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
@@ -376,48 +295,10 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// 图像处理循环
|
|
|
- /// 适用取图频率不高的处理,或者处理速度远快于取图速度的方法
|
|
|
- /// </summary>
|
|
|
- private async void ImageProcessingLoop(CancellationToken token)
|
|
|
- {
|
|
|
- try
|
|
|
- {
|
|
|
- while (!token.IsCancellationRequested)
|
|
|
- {
|
|
|
- // 等待图像数据
|
|
|
- await QueueSemaphore.WaitAsync(token);
|
|
|
-
|
|
|
- // 从队列获取图像
|
|
|
- if (ImageQueue.TryDequeue(out IFrameOut 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}");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
/// <summary>
|
|
|
/// 图像处理循环-引入批处理
|
|
|
/// 处理速度与取图速度的差不多的时候
|
|
|
+ /// 更换了存储图像的队列
|
|
|
/// </summary>
|
|
|
/// <param name="token"></param>
|
|
|
private async void ImageProcessingbatchLoop(CancellationToken token)
|
|
|
@@ -425,55 +306,6 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
const int batchSize = 5; // 每批处理的最大图像数量
|
|
|
var batch = new List<IFrameOut>(batchSize); // 存储当前批次的图像
|
|
|
|
|
|
- try
|
|
|
- {
|
|
|
- while (!token.IsCancellationRequested)
|
|
|
- {
|
|
|
- // 等待至少一张图像数据
|
|
|
- await QueueSemaphore.WaitAsync(token);
|
|
|
-
|
|
|
- // 收集一批图像(严格按队列顺序)
|
|
|
- while (batch.Count < batchSize && ImageQueue.TryDequeue(out IFrameOut imageData))
|
|
|
- {
|
|
|
- batch.Add(imageData);
|
|
|
- if (ImageQueue.Count > 0)
|
|
|
- {
|
|
|
- QueueSemaphore.Release(); // 提前释放信号量,唤醒其他等待线程
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 顺序处理当前批次的所有图像
|
|
|
- foreach (var image in batch)
|
|
|
- {
|
|
|
- ProcessImage(image, CameraId); // 严格按顺序执行处理逻辑
|
|
|
- image.Dispose(); // 处理完成后立即释放资源
|
|
|
- }
|
|
|
-
|
|
|
- // 清空当前批次,准备下一轮处理
|
|
|
- batch.Clear();
|
|
|
-
|
|
|
- // 如果队列为空,短暂休眠以避免过度占用CPU
|
|
|
- if (ImageQueue.Count == 0)
|
|
|
- {
|
|
|
- await Task.Delay(1, token); // 固定短时间休眠
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- catch (OperationCanceledException)
|
|
|
- {
|
|
|
- // 线程被取消,正常退出
|
|
|
- }
|
|
|
- catch (Exception ex)
|
|
|
- {
|
|
|
- Console.WriteLine($"相机 {CameraId} 处理异常: {ex.Message}");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private async void ImageProcessingbatchLoop2(CancellationToken token)
|
|
|
- {
|
|
|
- const int batchSize = 5; // 每批处理的最大图像数量
|
|
|
- var batch = new List<IFrameOut>(batchSize); // 存储当前批次的图像
|
|
|
-
|
|
|
try
|
|
|
{
|
|
|
while (!token.IsCancellationRequested)
|