|
@@ -1,6 +1,7 @@
|
|
|
// CameraGroup.cs 相机组线程管理类,控制相机采集和识别的线程运行,开放有算法的接口
|
|
// CameraGroup.cs 相机组线程管理类,控制相机采集和识别的线程运行,开放有算法的接口
|
|
|
using MvCameraControl;
|
|
using MvCameraControl;
|
|
|
using MvvmScaffoldFrame48.DLL.CameraTools;
|
|
using MvvmScaffoldFrame48.DLL.CameraTools;
|
|
|
|
|
+using MvvmScaffoldFrame48.DLL.LogTools;
|
|
|
using MvvmScaffoldFrame48.DLL.SystemTools;
|
|
using MvvmScaffoldFrame48.DLL.SystemTools;
|
|
|
using MvvmScaffoldFrame48.Model.ResultModel;
|
|
using MvvmScaffoldFrame48.Model.ResultModel;
|
|
|
using MvvmScaffoldFrame48.Model.StorageModel.SystemConfig;
|
|
using MvvmScaffoldFrame48.Model.StorageModel.SystemConfig;
|
|
@@ -21,6 +22,8 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
#region 变量与实例
|
|
#region 变量与实例
|
|
|
//相机线程的休眠时间,默认为0,即不休眠。在采集节拍没有那么高时,增加此值降低性能消耗
|
|
//相机线程的休眠时间,默认为0,即不休眠。在采集节拍没有那么高时,增加此值降低性能消耗
|
|
|
private int CameraSleepTime = 0;
|
|
private int CameraSleepTime = 0;
|
|
|
|
|
+ //帧编号记录
|
|
|
|
|
+ private long lastframeNum = -1;
|
|
|
//相机
|
|
//相机
|
|
|
public HikCamera Camera { get; set; }
|
|
public HikCamera Camera { get; set; }
|
|
|
//相机ID
|
|
//相机ID
|
|
@@ -34,7 +37,7 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
//图像队列-ConcurrentQueue
|
|
//图像队列-ConcurrentQueue
|
|
|
public ConcurrentQueue<IImage> ImageQueue { get; set; }
|
|
public ConcurrentQueue<IImage> ImageQueue { get; set; }
|
|
|
//图像队列-自定义RingBuffer
|
|
//图像队列-自定义RingBuffer
|
|
|
- public RingBuffer<IImage> ImageRingBuffer { get; set; }
|
|
|
|
|
|
|
+ public LockFreeRingBuffer<IImage> ImageRingBuffer = new LockFreeRingBuffer<IImage>(300);
|
|
|
//信号量
|
|
//信号量
|
|
|
public SemaphoreSlim QueueSemaphore { get; set; }
|
|
public SemaphoreSlim QueueSemaphore { get; set; }
|
|
|
//取消令牌
|
|
//取消令牌
|
|
@@ -74,10 +77,9 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
// 根据配置加载算法
|
|
// 根据配置加载算法
|
|
|
LoadAlgorithmFromConfiguration();
|
|
LoadAlgorithmFromConfiguration();
|
|
|
|
|
|
|
|
- //ImageRingBuffer = new RingBuffer<IImage>(300);
|
|
|
|
|
|
|
|
|
|
//Camera.StartReceiveFuntion();
|
|
//Camera.StartReceiveFuntion();
|
|
|
- Camera.FrameGrabbedEvent += CameraCaptureLoop;
|
|
|
|
|
|
|
+ Camera.FrameGrabbedEvent += CameraCaptureLoop2;
|
|
|
Camera.StartReceiveFuntionSetFrameGrabedEvent();
|
|
Camera.StartReceiveFuntionSetFrameGrabedEvent();
|
|
|
|
|
|
|
|
// 重置取消令牌
|
|
// 重置取消令牌
|
|
@@ -90,7 +92,7 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
|
|
|
|
|
|
|
|
|
|
// 启动图像处理线程
|
|
// 启动图像处理线程
|
|
|
- ProcessingTask = Task.Factory.StartNew(() => ImageProcessingbatchLoop(token),
|
|
|
|
|
|
|
+ ProcessingTask = Task.Factory.StartNew(() => ImageProcessingbatchLoop2(token),
|
|
|
token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
|
token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
|
|
|
|
|
|
|
IsRunning = true;
|
|
IsRunning = true;
|
|
@@ -236,7 +238,7 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
try
|
|
try
|
|
|
{
|
|
{
|
|
|
// 优先使用接口方式的算法
|
|
// 优先使用接口方式的算法
|
|
|
- if (ImageProcessor != null)
|
|
|
|
|
|
|
+ if (ImageProcessor != null && imageData!=null)
|
|
|
{
|
|
{
|
|
|
resultData = ImageProcessor.ProcessImage(imageData, cameraId);
|
|
resultData = ImageProcessor.ProcessImage(imageData, cameraId);
|
|
|
}
|
|
}
|
|
@@ -280,7 +282,7 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
{
|
|
{
|
|
|
// 将图像放入队列
|
|
// 将图像放入队列
|
|
|
ImageQueue.Enqueue(imageData.Image.Clone() as IImage);
|
|
ImageQueue.Enqueue(imageData.Image.Clone() as IImage);
|
|
|
- double QuTuYanshi = (DateTime.Now - FromUnixTimestamp((long)imageData.HostTimeStamp)).TotalMilliseconds;
|
|
|
|
|
|
|
+ double QuTuYanshi = (DateTime.Now - TimeStampTools.FromUnixTimestamp((long)imageData.HostTimeStamp)).TotalMilliseconds;
|
|
|
//Console.WriteLine($"相机 {CameraId} 采集到图像,帧号{imageData.FrameNum}");
|
|
//Console.WriteLine($"相机 {CameraId} 采集到图像,帧号{imageData.FrameNum}");
|
|
|
if(QuTuYanshi > 12)
|
|
if(QuTuYanshi > 12)
|
|
|
{
|
|
{
|
|
@@ -315,7 +317,7 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
{
|
|
{
|
|
|
// 将图像放入队列
|
|
// 将图像放入队列
|
|
|
ImageQueue.Enqueue(e.FrameOut.Image.Clone() as IImage);
|
|
ImageQueue.Enqueue(e.FrameOut.Image.Clone() as IImage);
|
|
|
- double QuTuYanshi = (DateTime.Now - FromUnixTimestamp((long)e.FrameOut.HostTimeStamp)).TotalMilliseconds;
|
|
|
|
|
|
|
+ double QuTuYanshi = (DateTime.Now - TimeStampTools.FromUnixTimestamp((long)e.FrameOut.HostTimeStamp)).TotalMilliseconds;
|
|
|
//Console.WriteLine($"相机 {CameraId} 采集到图像,帧号{imageData.FrameNum}");
|
|
//Console.WriteLine($"相机 {CameraId} 采集到图像,帧号{imageData.FrameNum}");
|
|
|
if (QuTuYanshi > 12)
|
|
if (QuTuYanshi > 12)
|
|
|
{
|
|
{
|
|
@@ -342,12 +344,29 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
{
|
|
{
|
|
|
// 将图像放入队列
|
|
// 将图像放入队列
|
|
|
ImageRingBuffer.TryEnqueue(e.FrameOut.Image.Clone() as IImage);
|
|
ImageRingBuffer.TryEnqueue(e.FrameOut.Image.Clone() as IImage);
|
|
|
- double QuTuYanshi = (DateTime.Now - FromUnixTimestamp((long)e.FrameOut.HostTimeStamp)).TotalMilliseconds;
|
|
|
|
|
|
|
+ double QuTuYanshi = (DateTime.Now - TimeStampTools.FromUnixTimestamp((long)e.FrameOut.HostTimeStamp)).TotalMilliseconds;
|
|
|
//Console.WriteLine($"相机 {CameraId} 采集到图像,帧号{imageData.FrameNum}");
|
|
//Console.WriteLine($"相机 {CameraId} 采集到图像,帧号{imageData.FrameNum}");
|
|
|
if (QuTuYanshi > 12)
|
|
if (QuTuYanshi > 12)
|
|
|
{
|
|
{
|
|
|
Console.WriteLine($"识别落后时间{QuTuYanshi}");
|
|
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(); // 通知处理线程有新数据
|
|
QueueSemaphore.Release(); // 通知处理线程有新数据
|
|
|
e.FrameOut.Dispose();
|
|
e.FrameOut.Dispose();
|
|
|
}
|
|
}
|
|
@@ -465,6 +484,7 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
// 收集一批图像(严格按队列顺序)
|
|
// 收集一批图像(严格按队列顺序)
|
|
|
while (batch.Count < batchSize && ImageRingBuffer.TryDequeue(out IImage imageData))
|
|
while (batch.Count < batchSize && ImageRingBuffer.TryDequeue(out IImage imageData))
|
|
|
{
|
|
{
|
|
|
|
|
+ if (imageData == null) continue;
|
|
|
batch.Add(imageData);
|
|
batch.Add(imageData);
|
|
|
if (ImageRingBuffer.Count > 0)
|
|
if (ImageRingBuffer.Count > 0)
|
|
|
{
|
|
{
|
|
@@ -499,60 +519,5 @@ namespace MvvmScaffoldFrame48.DLL.ThreadManager
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
#endregion
|
|
#endregion
|
|
|
-
|
|
|
|
|
- public DateTime FromUnixTimestamp(long timestamp, bool isMilliseconds = false)
|
|
|
|
|
- {
|
|
|
|
|
- try
|
|
|
|
|
- {
|
|
|
|
|
- // 如果未指定单位,尝试自动检测
|
|
|
|
|
- if (!isMilliseconds)
|
|
|
|
|
- {
|
|
|
|
|
- // 如果时间戳看起来像毫秒级(13位数字)
|
|
|
|
|
- if (timestamp.ToString().Length > 10)
|
|
|
|
|
- {
|
|
|
|
|
- isMilliseconds = true;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (isMilliseconds)
|
|
|
|
|
- {
|
|
|
|
|
- // 验证毫秒级时间戳范围
|
|
|
|
|
- const long minMilliTimestamp = -62135596800000; // 0001-01-01 00:00:00 UTC
|
|
|
|
|
- const long maxMilliTimestamp = 253402300799999; // 9999-12-31 23:59:59 UTC
|
|
|
|
|
-
|
|
|
|
|
- if (timestamp < minMilliTimestamp || timestamp > maxMilliTimestamp)
|
|
|
|
|
- {
|
|
|
|
|
- throw new ArgumentOutOfRangeException(nameof(timestamp),
|
|
|
|
|
- "毫秒级时间戳超出有效范围");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(timestamp);
|
|
|
|
|
- return TimeZoneInfo.ConvertTimeFromUtc(origin, TimeZoneInfo.Local);
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- // 验证秒级时间戳范围
|
|
|
|
|
- const long minTimestamp = -62135596800;
|
|
|
|
|
- const long maxTimestamp = 253402300799;
|
|
|
|
|
-
|
|
|
|
|
- if (timestamp < minTimestamp || timestamp > maxTimestamp)
|
|
|
|
|
- {
|
|
|
|
|
- throw new ArgumentOutOfRangeException(nameof(timestamp),
|
|
|
|
|
- "秒级时间戳超出有效范围");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(timestamp);
|
|
|
|
|
- return TimeZoneInfo.ConvertTimeFromUtc(origin, TimeZoneInfo.Local);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- catch (ArgumentOutOfRangeException)
|
|
|
|
|
- {
|
|
|
|
|
- throw;
|
|
|
|
|
- }
|
|
|
|
|
- catch (Exception ex)
|
|
|
|
|
- {
|
|
|
|
|
- throw new ArgumentException($"无法转换时间戳 {timestamp}: {ex.Message}", ex);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|