Prechádzať zdrojové kódy

20260206001 相机读取和历史数据保存优化,识别模式改为内部触发降低CPU消耗。

向羽 孟 2 mesiacov pred
rodič
commit
30ff8f3448

+ 61 - 1
TestWork.DLL/CameraClass.cs

@@ -296,6 +296,61 @@ namespace CCDCount.DLL
             }
         }
 
+        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);
+            }
+        }
+
         /// <summary>
         /// 获取一次图片
         /// </summary>
@@ -307,6 +362,11 @@ namespace CCDCount.DLL
             int BRet = device.StreamGrabber.GetImageBuffer(1000, out IFrameData);
             if (BRet == 0 && IFrameData != null) result = true;
             else return result;
+            var QutuYanshiTime = (DateTime.Now - FromUnixTimestamp((long)IFrameData.HostTimeStamp)).TotalMilliseconds;
+            if (QutuYanshiTime > 12)
+            {
+                Console.WriteLine($"GetOnceImage-识别延时超过了12ms,耗时{QutuYanshiTime}");
+            }
             if (lastframeNum == -1)
             {
                 lastframeNum = IFrameData.FrameNum;
@@ -408,7 +468,7 @@ namespace CCDCount.DLL
             try
             {
                 if(device == null) return result;
-                device.StreamGrabber.SetImageNodeNum(100);
+                device.StreamGrabber.SetImageNodeNum(300);
                 device.StreamGrabber.StartGrabbing();
                 result = true;
                 SystemAlarm.AlarmCancel(AlarmMessageList.相机采集开始失败);

+ 150 - 85
TestWork.DLL/MainThreadClass.cs

@@ -90,7 +90,7 @@ namespace CCDCount.DLL
         private bool _ShuLiState = true;
         public bool ShuLiState { get { return _ShuLiState; } }
 
-        private bool _IsDebug = true;
+        private bool _IsDebug = false;
         public bool IsDebug { get { return _IsDebug; } }
         private bool IsConnectModbus = false;
 
@@ -112,7 +112,8 @@ namespace CCDCount.DLL
         {
             Task.Run(() =>
             {
-                while(!modbusTcpClient.Connect(ipAddress))
+                int i = 10;
+                while(!modbusTcpClient.Connect(ipAddress)&&i>0)
                 {
                     IsConnectModbus = false;
                     //SystemAlarm.AlarmAlert(AlarmMessageList.数粒通讯连接失败, $"Modbus通讯连接失败,目标IP:{ipAddress}", "DLL:MainThreadClass-ConnectModbus");
@@ -120,6 +121,7 @@ namespace CCDCount.DLL
                         $"Number counting communication connection failed, target IP:{ipAddress}",
                         $"Modbus通讯连接失败,目标IP:{ipAddress}",
                         "DLL:MainThreadClass-ConnectModbus");
+                    i--;
                     Task.Delay(1000);
                 }
                 SystemAlarm.AlarmCancel(AlarmMessageList.数粒通讯连接失败);
@@ -233,16 +235,17 @@ namespace CCDCount.DLL
             bool result = false;
             try
             {
-                if(BatchNumber=="")
+                if (BatchNumber == "")
                 {
                     FaultLog.RecordErrorMessage($"Camera {cameraConfig.CamerNo} does not have a batch number, and it failed to start", "Dll:MainThreadClass-StartMianThread");
                     return result;
                 }
-                if (!IsConnectModbus)
-                {
-                    FaultLog.RecordErrorMessage($"Camera {cameraConfig.CamerNo} does not have a PLC connection, resulting in startup failure", "Dll:MainThreadClass-StartMianThread");
-                    return result;
-                }
+                //if (!IsConnectModbus)
+                //{
+                //    FaultLog.RecordErrorMessage($"Camera {cameraConfig.CamerNo} does not have a PLC connection, resulting in startup failure", "Dll:MainThreadClass-StartMianThread");
+                //    return result;
+                //}
+                timeBeginPeriod(1); // 设置为1ms精度
                 actionMesSqliteDataClass = new ActionMesSqliteDataClass($"{AppDomain.CurrentDomain.BaseDirectory}DATA\\ActiveObjectData\\Cam{cameraConfig.CamerNo}\\ActiveObjectData_{BatchNumber}.db");
                 //actionMesSqliteDataClass = new ActionMesSqliteDataClass($"{AppDomain.CurrentDomain.BaseDirectory}DATA\\ActiveObjectData\\Cam{cameraConfig.CamerNo}\\ActiveObjectData20250827.db");
                 actionMesSqliteDataClass.GetAllActionMinStartMaxEndLine(out int num, out int StartLine, out int EndLine);
@@ -258,9 +261,9 @@ namespace CCDCount.DLL
                 // 数据交换线程开启
                 StartSwitchThread();
                 // 为数粒算法的识别成功一粒回调函数添加方法
-                shuLiClass.WorkCompleted += Worker_OneGrainCompleted;
+                //shuLiClass.WorkCompleted += Worker_OneGrainCompleted;
                 // 开启识别线程
-                shuLiClass.StartIdentifyFuntion(cameraClass.GetCamereImageSize().Width);
+                shuLiClass.StartIdentifyFuntion2(cameraClass.GetCamereImageSize().Width);
                 result = true;
             }
             catch(Exception ex)
@@ -288,6 +291,7 @@ namespace CCDCount.DLL
                 shuLiClass.StopIdentifyFuntion();
                 StopSendBottLogicMessageThread();
                 result = true;
+                actionMesSqliteDataClass.Dispose();
             }
             catch(Exception ex)
             {
@@ -684,7 +688,7 @@ namespace CCDCount.DLL
                     LOG.log("参数训练-计算标定后的长度", 6);
                     foreach (var item in ListValues)
                     {
-                        item.MaxLength = shuLiClass.SizeCalculation2(item.RowsData).MaxLength;
+                        item.MaxLength = shuLiClass.SizeCalculation(item.RowsData).Height;
                     }
                     LOG.log("参数训练-长度数据筛选", 6);
                     if (ListValues.Count >= 1000)
@@ -721,7 +725,60 @@ namespace CCDCount.DLL
         #endregion
 
         #region 私有方法
+        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);
+            }
+        }
 
         //bool IsFill = false;
         //bool IsXuanZhuanCloseFaMen = false;
@@ -754,71 +811,85 @@ namespace CCDCount.DLL
             {
                 //往数组中计数
                 var UseTime = (oneActive.EndCheckTime - oneActive.StartCheckTime).TotalMilliseconds;
-                var AllPictureUseTime = (oneActive.PictureEndReadTime - oneActive.PictureStartReadTime).TotalMilliseconds;
-                var PictureUsetime = (oneActive.EndCheckTime - oneActive.PictureStartReadTime).TotalMilliseconds;
+                var QutuYanshiTime = (DateTime.Now - oneActive.PictureEndReadTime).TotalMilliseconds;
                 if (BatchNumber!="") oneActive.BatchNumber = BatchNumber;
                 LOG.log(string.Format("输出当前颗粒信息,颗粒编号:{0},开始时间:{1},第一张图像读取时间:{2},\n" +
-                    "识别耗时:{3},首尾取图时差:{4},颗粒状态:{5},通道数:{6}",
+                    "识别耗时:{3},尾图到输出的时间:{4},颗粒状态:{5},通道数:{6}",
                     oneActive.Num, oneActive.StartCheckTime.ToString("O"), oneActive.PictureStartReadTime.ToString("O"),
-                    UseTime.ToString(), AllPictureUseTime.ToString(), oneActive.StateCode, oneActive.ChannelNO), 6);
-                if (UseTime- AllPictureUseTime > 20)
-                    LOG.error("算法耗时超过了20ms");
-                switch(oneActive.StateCode)
+                    UseTime.ToString(), QutuYanshiTime.ToString(), oneActive.StateCode, oneActive.ChannelNO), 6);
+                if (QutuYanshiTime > 20)
                 {
-                    case 1:
-                        SystemAlarm.AlarmAlert(AlarmMessageList.数粒超长粒,
-                            "Counting extra-long particles",
-                            "数粒超长粒",
-                            "MianThreadClass-Worker_OneGrainCompleted");
-                        break;
-                    case 2:
-                        SystemAlarm.AlarmAlert(AlarmMessageList.数粒超短粒,
-                            "Counting ultra-short particles",
-                            "数粒超短粒",
-                            "MianThreadClass-Worker_OneGrainCompleted");
-                        break;
-                    case 5:
-                        SystemAlarm.AlarmAlert(AlarmMessageList.数粒超大粒,
-                            "Counting extra-large particles",
-                            "数粒超大粒",
-                            "MianThreadClass-Worker_OneGrainCompleted");
-                        break;
-                    case 6:
-                        SystemAlarm.AlarmAlert(AlarmMessageList.数粒超小粒,
-                            "Counting ultra-small particles",
-                            "数粒超小粒",
-                            "MianThreadClass-Worker_OneGrainCompleted");
-                        break;
-                    case 8:
-                        SystemAlarm.AlarmAlert(AlarmMessageList.疑似叠粒,
-                            "Count overlapping particles",
-                            "疑似叠粒",
-                            "MianThreadClass-Worker_OneGrainCompleted");
-                        break;
-                    case 10:
-                        SystemAlarm.AlarmAlert(AlarmMessageList.丢帧颗粒,
-                            "Counting frame loss particles",
-                            "丢帧颗粒",
-                            "MianThreadClass-Worker_OneGrainCompleted");
-                        break;
+                    LOG.error($"识别延时超过了20ms,耗时{QutuYanshiTime}");
                 }
-
+                //switch (oneActive.StateCode)
+                //{
+                //    case 1:
+                //        SystemAlarm.AlarmAlert(AlarmMessageList.数粒超长粒,
+                //            "Counting extra-long particles",
+                //            "数粒超长粒",
+                //            "MianThreadClass-Worker_OneGrainCompleted");
+                //        break;
+                //    case 2:
+                //        SystemAlarm.AlarmAlert(AlarmMessageList.数粒超短粒,
+                //            "Counting ultra-short particles",
+                //            "数粒超短粒",
+                //            "MianThreadClass-Worker_OneGrainCompleted");
+                //        break;
+                //    case 5:
+                //        SystemAlarm.AlarmAlert(AlarmMessageList.数粒超大粒,
+                //            "Counting extra-large particles",
+                //            "数粒超大粒",
+                //            "MianThreadClass-Worker_OneGrainCompleted");
+                //        break;
+                //    case 6:
+                //        SystemAlarm.AlarmAlert(AlarmMessageList.数粒超小粒,
+                //            "Counting ultra-small particles",
+                //            "数粒超小粒",
+                //            "MianThreadClass-Worker_OneGrainCompleted");
+                //        break;
+                //    case 8:
+                //        SystemAlarm.AlarmAlert(AlarmMessageList.疑似叠粒,
+                //            "Count overlapping particles",
+                //            "疑似叠粒",
+                //            "MianThreadClass-Worker_OneGrainCompleted");
+                //        break;
+                //    case 10:
+                //        SystemAlarm.AlarmAlert(AlarmMessageList.丢帧颗粒,
+                //            "Counting frame loss particles",
+                //            "丢帧颗粒",
+                //            "MianThreadClass-Worker_OneGrainCompleted");
+                //        break;
+                //}
+                //ThreadPool.QueueUserWorkItem(_ =>
+                //{
+                //    if (actionMesSqliteDataClass != null)
+                //    {
+                //        try
+                //        {
+                //            actionMesSqliteDataClass.AddData(oneActive);
+                //        }
+                //        catch (Exception ex)
+                //        {
+                //            LOG.error("MianThread-Worker_OneGrainCompleted-Task:" + ex.Message);
+                //        }
+                //    }
+                //});
 
                 //记录到数据库
-                ThreadPool.QueueUserWorkItem(_ =>
-                {
-                    if (actionMesSqliteDataClass != null)
-                    {
-                        try
-                        {
-                            actionMesSqliteDataClass.InsertActiveObject(oneActive);
-                        }
-                        catch (Exception ex)
-                        {
-                            LOG.error("MianThread-Worker_OneGrainCompleted-Task:" + ex.Message);
-                        }
-                    }
-                });
+                //ThreadPool.QueueUserWorkItem(_ =>
+                //{
+                //    if (actionMesSqliteDataClass != null)
+                //    {
+                //        try
+                //        {
+                //            actionMesSqliteDataClass.InsertActiveObject(oneActive);
+                //        }
+                //        catch (Exception ex)
+                //        {
+                //            LOG.error("MianThread-Worker_OneGrainCompleted-Task:" + ex.Message);
+                //        }
+                //    }
+                //});
 
                 if (!Hset.Add(oneActive.ChannelNO))
                 {
@@ -911,8 +982,11 @@ namespace CCDCount.DLL
         private void StartSwitchThread()
         {
             IsSwitch = true;
-
-            SwitchIdentifyImageThread = new Thread(SwitchIdentifyImageProcess);
+            shuLiClass.QueueSemaphore = new SemaphoreSlim(0);
+            SwitchIdentifyImageThread = new Thread(SwitchIdentifyImageProcess)
+            {
+                Priority = ThreadPriority.AboveNormal
+            };
             SwitchIdentifyImageThread.Start();
         }
 
@@ -946,18 +1020,8 @@ namespace CCDCount.DLL
         /// </summary>
         private void SwitchIdentifyImageProcess()
         {
-            //Stopwatch stopwatch = Stopwatch.StartNew();
-            //stopwatch.Start();
             while (IsSwitch)
             {
-
-                //if (stopwatch.ElapsedMilliseconds > 1000)
-                //{
-                    //Console.WriteLine("交换线程-图像处理实例中的待识别图像缓存队列长度{0}", shuLiClass.ImageNum);
-                    //LOG.log(string.Format("交换线程-图像处理实例中的待识别图像缓存队列长度{0}", shuLiClass.ImageNum),6);
-                    //GC.Collect();
-                    //stopwatch.Restart();
-                //}
                 bool result = cameraClass.GetOnceImage(out IFrameOut IFramedata);
                 if (result)
                 {
@@ -974,6 +1038,7 @@ namespace CCDCount.DLL
                     if (IFramedata == null)
                         continue;
                     shuLiClass.SetOnceIdentifyImageData(IFramedata);
+                    shuLiClass.QueueSemaphore.Release(); // 通知处理线程有新数据
                 }
                 else
                     continue;
@@ -991,8 +1056,6 @@ namespace CCDCount.DLL
             try
             {
                 if(!IsConnectModbus) return result;
-
-                timeBeginPeriod(1); // 设置为1ms精度
                 IsSend = true;
                 SendBottLogicMessageThread = new Thread(SendBottLogicMessageProcess);
                 SendBottLogicMessageThread.Start();
@@ -1025,7 +1088,9 @@ namespace CCDCount.DLL
                 {
                     try
                     {
-                        SendBottLogicMessageThread.Interrupt();
+                        IsSend = false;
+                        SendBottLogicMessageThread.Join();
+                        //SendBottLogicMessageThread.Interrupt();
                     }
                     catch (ThreadStateException)
                     {
@@ -1125,7 +1190,7 @@ namespace CCDCount.DLL
                 if ((ReturnValue[0] & 1) == 0)
                 {
                     WriteDoneTime.Restart();
-                    while (SendQueue.Count==0)
+                    while (SendQueue.Count==0&& IsSend)
                     {
                         //Thread.Sleep(1);
                     }

+ 3 - 1
TestWork.DLL/PLCManagementClass.cs

@@ -34,7 +34,8 @@ namespace CCDCount.DLL
         {
             Task.Run(() =>
             {
-                while (!modbusTcpClient.Connect(ipAddress))
+                int i = 10;
+                while (!modbusTcpClient.Connect(ipAddress)&&i>0)
                 {
                     isConnect = false;
                     //SystemAlarm.AlarmAlert(AlarmMessageList.PLC通讯连接失败, $"Modbus通讯连接失败,目标IP:{ipAddress}", "DLL:MainThreadClass-ConnectModbus");
@@ -42,6 +43,7 @@ namespace CCDCount.DLL
                         $"PLC communication connection failed, target IP:{ipAddress}",
                         $"PLC通讯连接失败, IP地址:{ipAddress}",
                         "DLL:MainThreadClass-ConnectModbus");
+                    i--;
                     Task.Delay(1000);
                 }
                 SystemAlarm.AlarmCancel(AlarmMessageList.PLC通讯连接失败);

+ 413 - 39
TestWork.DLL/ShuLiClass.cs

@@ -4,9 +4,11 @@ using CCDCount.MODEL.ResultModel;
 using CCDCount.MODEL.ShuLiModel;
 using LogClass;
 using MvCameraControl;
+using Org.BouncyCastle.Utilities;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
+using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder;
 using System.Diagnostics;
 using System.Drawing;
 using System.IO;
@@ -14,6 +16,8 @@ using System.Linq;
 using System.Runtime.InteropServices.WindowsRuntime;
 using System.Threading;
 using System.Threading.Tasks;
+using System.Windows.Media.Media3D;
+using static iTextSharp.text.pdf.AcroFields;
 
 namespace CCDCount.DLL
 {
@@ -109,39 +113,40 @@ namespace CCDCount.DLL
         public bool ProcessImageSequence(IFrameOut image)
         {
             bool result = false;
+            ReadOnlySpan<byte> spanFromArr = image.Image.PixelData.AsSpan();
             for (int i = 0; i < image.Image.Height; i++)
             {
-                result = ProcessLine(image, i);
+                result = ProcessLine2(spanFromArr,image.HostTimeStamp,image.Image.Width, i);
                 currentLine += 1;
             }
 
-
-            //Stopwatch stopwatch = Stopwatch.StartNew();
             //识别到结果并输出
-            //lock (_lockObj)
-            //{
+
             _rwLock.EnterReadLock();
             // 清理超时未更新的物体
             lostObjects = activeObjects
                 .Where(o => (currentLine - o.LastSeenLine) > shuLiConfig.MAX_GAP || (o.LastSeenLine - o.StartLine) > shuLiConfig.MAX_Idetify_Height)
                 .ToList();
             _rwLock.ExitReadLock();
-            //}
-            //if (stopwatch.ElapsedMilliseconds > 1)
-            //{
-            //    FaultLog.RecordErrorMessage($"ShuLiClass-ProcessImageSequence:图像结果分析-结果筛选,此次识别耗时:{stopwatch.Elapsed}");
-            //}
+
 
             List<ActiveObjectClass> OneActive = new List<ActiveObjectClass>();
 
             // 有物体转变为活跃物体,返回值转为true
             if (lostObjects.Count > 0)
             {
+                Stopwatch stopwatch = Stopwatch.StartNew();
                 result = true;
                 //stopwatch.Restart();
                 foreach (var item in lostObjects)
                 {
+
                     item.PictureEndReadTime = FromUnixTimestamp((long)image.HostTimeStamp);
+                    DateTime NowTime = DateTime.Now;
+                    var AllPictureUseTime = (item.PictureEndReadTime - item.PictureStartReadTime).TotalMilliseconds;
+                    var PictureUsetime = (NowTime - item.PictureStartReadTime).TotalMilliseconds;
+                    if (PictureUsetime - AllPictureUseTime > 20)
+                        LOG.error($"算法耗时超过了20ms,相机取图总耗时:{AllPictureUseTime},从取第一张图到现在的耗时{PictureUsetime}");
                     //噪点判定
                     if (item.Area < shuLiConfig.NoiseFilter_Threshold)
                     {
@@ -159,8 +164,11 @@ namespace CCDCount.DLL
                     {
                         if((item.LastSeenLine - item.StartLine) < shuLiConfig.MAX_Idetify_Height)
                         {
-                            var CalculationResult = SizeCalculation2(item.RowsData);
-                            item.MaxLength = CalculationResult.MaxLength;
+                            var CalculationResult = SizeCalculation(item.RowsData);
+                            if(CalculationResult!=null)
+                            {
+                                item.MaxLength = CalculationResult.Height;
+                            }
                             //item.hasSignificantConcavity = CalculationResult.hasSignificantConcavity;
                             //item.concavityRatio = CalculationResult.concavityRatio;
                             //if(CalculationResult.hasSignificantConcavity)
@@ -182,46 +190,46 @@ namespace CCDCount.DLL
                         {
                             if (item.StateCode == 8)
                             {
-                                LOG.log(string.Format("颗粒编号{0}:疑似叠片或缺损", item.Num));
+                                //LOG.log(string.Format("颗粒编号{0}:疑似叠片或缺损", item.Num));
                             }
                             else if (item.StateCode == 7)
                             {
-                                LOG.log(string.Format("颗粒编号{0}:视野被遮挡", item.Num));
+                                //LOG.log(string.Format("颗粒编号{0}:视野被遮挡", item.Num));
                             }
                         }
                         else if (item.Area < shuLiConfig.MinArea
                             && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 1))
                         {
                             item.StateCode = 6;
-                            LOG.log(string.Format("颗粒编号{0}:面积过小", item.Num));
-                            Console.WriteLine("颗粒编号{0}:面积过小", item.Num);
+                            //LOG.log(string.Format("颗粒编号{0}:面积过小", item.Num));
+                            //Console.WriteLine("颗粒编号{0}:面积过小", item.Num);
                         }
                         else if (item.Area > shuLiConfig.MaxArea
                             && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 1))
                         {
                             item.StateCode = 5;
-                            LOG.log(string.Format("颗粒编号{0}:面积过大", item.Num));
-                            Console.WriteLine("颗粒编号{0}:面积过大", item.Num);
+                            //LOG.log(string.Format("颗粒编号{0}:面积过大", item.Num));
+                            //Console.WriteLine("颗粒编号{0}:面积过大", item.Num);
                         }
                         else if (item.MaxLength < shuLiConfig.MIN_Object_LENGTH
                             && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
                         {
                             item.StateCode = 2;
-                            LOG.log(string.Format("颗粒编号{0}:超短粒", item.Num));
-                            Console.WriteLine("颗粒编号{0}:超短粒", item.Num);
+                            //LOG.log(string.Format("颗粒编号{0}:超短粒", item.Num));
+                            //Console.WriteLine("颗粒编号{0}:超短粒", item.Num);
                         }
                         else if (item.MaxLength > shuLiConfig.MAX_Object_LENGTH
                             && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
                         {
                             item.StateCode = 1;
-                            LOG.log(string.Format("颗粒编号{0}:超长粒", item.Num));
-                            Console.WriteLine("颗粒编号{0}:超长粒", item.Num);
+                            //LOG.log(string.Format("颗粒编号{0}:超长粒", item.Num));
+                            //Console.WriteLine("颗粒编号{0}:超长粒", item.Num);
                         }
                         else
                         {
                             item.StateCode = 0;
-                            LOG.log(string.Format("颗粒编号{0}:正常粒", item.Num));
-                            Console.WriteLine("颗粒编号{0}:正常粒", item.Num);
+                            //LOG.log(string.Format("颗粒编号{0}:正常粒", item.Num));
+                            //Console.WriteLine("颗粒编号{0}:正常粒", item.Num);
                         }
                     }
                     if(item.StateCode != 7&&item.StateCode!=9)
@@ -234,11 +242,12 @@ namespace CCDCount.DLL
                     if(item.StateCode != 9)
                         OneActive.Add(item);
                 }
-                //stopwatch.Stop();
-                //if (stopwatch.ElapsedMilliseconds > 1)
-                //{
-                //    FaultLog.RecordErrorMessage($"ShuLiClass-ProcessImageSequence:图像结果分析-结果参数补全,此次识别耗时:{stopwatch.Elapsed}");
-                //}
+                stopwatch.Stop();
+                if (stopwatch.ElapsedMilliseconds > 1)
+                {
+                    Console.WriteLine($"ShuLiClass-ProcessImageSequence:图像结果分析-结果参数补全,此次识别耗时:{stopwatch.Elapsed}");
+                    //FaultLog.RecordErrorMessage($"ShuLiClass-ProcessImageSequence:图像结果分析-结果参数补全,此次识别耗时:{stopwatch.Elapsed}");
+                }
                 //stopwatch.Restart();
                 if (OneActive.Count > 0)
                 {
@@ -266,6 +275,199 @@ namespace CCDCount.DLL
             return result;
         }
 
+        /// <summary>
+        /// 处理图像序列的主入口
+        /// </summary>
+        /// <param name="image">图像像素数据</param>
+        /// <returns>检测到的物体总数</returns>
+        public bool ProcessImageSequence2(IFrameOut image)
+        {
+            bool result = false;
+            ReadOnlySpan<byte> spanFromArr = image.Image.PixelData.AsSpan();
+            for (int i = 0; i < image.Image.Height; i++)
+            {
+                result = ProcessLine2(spanFromArr, image.HostTimeStamp, image.Image.Width, i);
+                currentLine += 1;
+            }
+
+            // 优化: 减少锁的使用频率,批量处理逻辑
+            List<ActiveObjectClass> objectsToProcess = null;
+            _rwLock.EnterReadLock();
+            try
+            {
+                // 使用ToList()避免在锁内进行复杂查询
+                objectsToProcess = activeObjects
+                    .Where(o => (currentLine - o.LastSeenLine) > shuLiConfig.MAX_GAP ||
+                               (o.LastSeenLine - o.StartLine) > shuLiConfig.MAX_Idetify_Height)
+                    .ToList();
+            }
+            finally
+            {
+                _rwLock.ExitReadLock();
+            }
+
+            // 优化: 提前返回,避免不必要的处理
+            if (objectsToProcess.Count == 0)
+            {
+                return result;
+            }
+
+            // 优化: 预分配容量,减少内存重新分配
+            var processedObjects = new List<ActiveObjectClass>(objectsToProcess.Count);
+
+            // 优化: 将耗时的计算移到循环外
+            var endTime = DateTime.Now;
+            var pictureEndTime = FromUnixTimestamp((long)image.HostTimeStamp);
+
+            foreach (var item in objectsToProcess)
+            {
+                // 优化: 将耗时的计算移到循环外
+                ProcessSingleObject(item, pictureEndTime, endTime, processedObjects);
+            }
+
+            result = true;
+
+            // 优化: 批量操作减少锁的持有时间
+            if (processedObjects.Count > 0)
+            {
+                _rwLock.EnterWriteLock();
+                try
+                {
+                    // 批量转移对象
+                    foreach (var item in processedObjects)
+                    {
+                        TryAdd(historyActiveObjects, item, 2500);
+                    }
+
+                    // 批量移除
+                    foreach (var item in objectsToProcess)
+                    {
+                        activeObjects.Remove(item);
+                    }
+                }
+                finally
+                {
+                    _rwLock.ExitWriteLock();
+                }
+
+                // 优化: 异步触发事件,避免阻塞主线程
+                ThreadPool.QueueUserWorkItem(_ =>
+                {
+                    OnWorkCompleted(processedObjects);
+                });
+            }
+
+            return result;
+        }
+
+        // 抽取的单个对象处理方法
+        private void ProcessSingleObject(ActiveObjectClass item, DateTime pictureEndTime,
+                                       DateTime endTime,  List<ActiveObjectClass> processedObjects)
+        {
+            item.PictureEndReadTime = pictureEndTime;
+            var nowTime = DateTime.Now;
+            var ShiBieLuoHouTime = (nowTime - item.PictureEndReadTime).TotalMilliseconds;
+            // 优化: 将日志记录改为条件执行
+            if (ShiBieLuoHouTime > 30)
+            {
+                LOG.error($"算法落后了超过30ms,相机取图总耗时:{ShiBieLuoHouTime}");
+            }
+
+            // 快速滤除噪点
+            if (item.Area < shuLiConfig.NoiseFilter_Threshold)
+            {
+                item.StateCode = 9;
+                return;
+            }
+
+            // 计算长度
+            if (item.StartLine == item.LastSeenLine)
+            {
+                item.MaxLength = item.MaxEndCol - item.MinStartCol;
+                item.StateCode = 10;
+                LOG.log(string.Format("颗粒{0}的有效高度仅一行", item.Num));
+            }
+            else
+            {
+                if ((item.LastSeenLine - item.StartLine) < shuLiConfig.MAX_Idetify_Height)
+                {
+                    var calculationResult = SizeCalculation(item.RowsData);
+                    if(calculationResult!=null)
+                    {
+                        item.MaxLength = calculationResult.Height;
+                    }
+                }
+                else
+                {
+                    item.StateCode = 7;
+                }
+            }
+
+            // 分类处理
+            ApplyClassificationRules(item);
+
+            // 添加到历史记录
+            if (item.StateCode != 7 && item.StateCode != 9)
+            {
+                item.Num = Interlocked.Increment(ref ObjectNum);
+                item.ChannelNO = ActiveChannel(item);
+            }
+
+            item.EndCheckTime = endTime;
+
+            if (item.StateCode != 9)
+            {
+                processedObjects.Add(item);
+            }
+        }
+
+        // 抽取分类规则,便于维护
+        private void ApplyClassificationRules(ActiveObjectClass item)
+        {
+            if (shuLiConfig.PandingCode == -1) return;
+
+            if (item.StateCode != -1)
+            {
+                if (item.StateCode == 8)
+                {
+                    LOG.log(string.Format("颗粒编号{0}:疑似叠片或缺损", item.Num));
+                }
+                else if (item.StateCode == 7)
+                {
+                    LOG.log(string.Format("颗粒编号{0}:视野被遮挡", item.Num));
+                }
+            }
+            else if (item.Area < shuLiConfig.MinArea &&
+                     (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 1))
+            {
+                item.StateCode = 6;
+                LOG.log(string.Format("颗粒编号{0}:面积过小", item.Num));
+            }
+            else if (item.Area > shuLiConfig.MaxArea &&
+                     (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 1))
+            {
+                item.StateCode = 5;
+                LOG.log(string.Format("颗粒编号{0}:面积过大", item.Num));
+            }
+            else if (item.MaxLength < shuLiConfig.MIN_Object_LENGTH &&
+                     (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
+            {
+                item.StateCode = 2;
+                LOG.log(string.Format("颗粒编号{0}:超短粒", item.Num));
+            }
+            else if (item.MaxLength > shuLiConfig.MAX_Object_LENGTH &&
+                     (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
+            {
+                item.StateCode = 1;
+                LOG.log(string.Format("颗粒编号{0}:超长粒", item.Num));
+            }
+            else
+            {
+                item.StateCode = 0;
+                LOG.log(string.Format("颗粒编号{0}:正常粒", item.Num));
+            }
+        }
+
         /// <summary>
         /// 返回最后一个历史物品
         /// </summary>
@@ -360,7 +562,7 @@ namespace CCDCount.DLL
                 // 打开识别线程
                 IdentifyImageProcessThread = new Thread(IdentifyImageProcess)
                 {
-                    Priority = ThreadPriority.Highest
+                    Priority = ThreadPriority.AboveNormal
                 };
                 IdentifyImageProcessThread.Start();
                 SystemAlarm.AlarmCancel(AlarmMessageList.识别线程启动失败);
@@ -376,6 +578,31 @@ namespace CCDCount.DLL
             }
         }
 
+        public void StartIdentifyFuntion2(int ImaageWidth)
+        {
+            UpdateIdentifyImageWidth(ImaageWidth);
+            InitChannel();
+            try
+            {
+                CancellationTokenSource = new CancellationTokenSource();
+                var token = CancellationTokenSource.Token;
+
+                // 启动图像处理线程
+                ProcessingTask = Task.Factory.StartNew(() => IdentifyImageProcessTask(token),
+                    token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+                SystemAlarm.AlarmCancel(AlarmMessageList.识别线程启动失败);
+            }
+            catch (Exception ex)
+            {
+                SystemAlarm.AlarmAlert(AlarmMessageList.识别线程启动失败,
+                    "Start thread failed!, " + ex.Message,
+                    "识别线程启动失败, " + ex.Message,
+                    "DLL:ShuLiClass-StartIdentifyFuntion");
+                //FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message);
+                throw;
+            }
+        }
+
         /// <summary>
         /// 关闭识别
         /// </summary>
@@ -399,6 +626,35 @@ namespace CCDCount.DLL
                 throw;
             }
         }
+        public async void StopIdentifyFuntion2()
+        {
+            try
+            {
+                // 发送取消信号
+                CancellationTokenSource.Cancel();
+
+                // 等待线程完成
+                try
+                {
+                    if (ProcessingTask != null)
+                        await ProcessingTask;
+                }
+                catch (OperationCanceledException)
+                {
+                    // 正常取消,忽略异常
+                }
+                SystemAlarm.AlarmCancel(AlarmMessageList.识别线程停止失败);
+            }
+            catch (Exception ex)
+            {
+                //FaultLog.RecordErrorMessage("Stop thread failed!, " + ex.Message);
+                SystemAlarm.AlarmAlert(AlarmMessageList.识别线程停止失败,
+                    "Stop thread failed!, " + ex.Message,
+                    "识别线程停止失败, " + ex.Message,
+                    "DLL:ShuLiClass-StopIdentifyFuntion");
+                throw;
+            }
+        }
 
         /// <summary>
         /// 向识别队列添加一个数据
@@ -407,6 +663,7 @@ namespace CCDCount.DLL
         public void SetOnceIdentifyImageData(IFrameOut items)
         {
             IFrameDatas.Enqueue(items.Clone() as IFrameOut);
+            //IFrameDatas.Enqueue(items );
         }
 
         /// <summary>
@@ -679,7 +936,7 @@ namespace CCDCount.DLL
         }
 
         private bool IsPrintLightOnError = false;
-
+        List<ValidRegionModelClass> currentRegions = null;
         /// <summary>
         /// 处理单行像素数据
         /// 返回值为false的时候无活跃物体转变为历史物体
@@ -807,19 +1064,20 @@ namespace CCDCount.DLL
             //}
             return result;
         }
-        private bool ProcessLine2(IFrameOut imagedata, int RowNo)
+        private bool ProcessLine2(ReadOnlySpan<byte> image, ulong ImageHostTime, uint imageWidth, int RowNo)
         {
             // 缓存配置值
             int maxGap = shuLiConfig.MAX_GAP;
             long currentTimeLine = currentLine;
 
             // 步骤1:检测当前行的有效区域
-            var currentRegions = FindValidRegions(imagedata.Image, RowNo);
-            if (currentRegions.Count == 0) return false;
+            currentRegions = FindValidRegions(image, (int)imageWidth, RowNo);
+
+            if (currentRegions.Count == 0|| currentRegions == null) return false;
 
             if (currentRegions.Count == 1)
             {
-                if (currentRegions[0].End - (currentRegions[0]).Start + 1 == imagedata.Image.Width)
+                if (currentRegions[0].End - (currentRegions[0]).Start + 1 == imageWidth)
                 {
                     if (!IsPrintLightOnError)
                     {
@@ -869,6 +1127,7 @@ namespace CCDCount.DLL
                         LastSeenLineEndCol = aggregateResult.maxLastSeenEndCol,
                         StartCheckTime = aggregateResult.minStartTime,
                         EndCheckTime = aggregateResult.maxEndTime,
+                        PictureStartReadTime = aggregateResult.pictureMinReadTime,
                         Area = aggregateResult.totalArea,
                         RowsData = aggregateResult.mergedRowsData,
                         ImageWidth = aggregateResult.imageWidth,
@@ -913,7 +1172,7 @@ namespace CCDCount.DLL
                             LastSeenLineStartCol = region.Start,
                             LastSeenLineEndCol = region.End,
                             StartCheckTime = DateTime.Now,
-                            PictureStartReadTime = FromUnixTimestamp((long)imagedata.HostTimeStamp),
+                            PictureStartReadTime = FromUnixTimestamp((long)ImageHostTime),
                             Area = region.End - region.Start + 1,
                             ImageWidth = IdentifyImageWidth,
                             RowsData = new List<RowStartEndCol> {
@@ -933,6 +1192,7 @@ namespace CCDCount.DLL
                 }
             }
 
+            currentRegions.Clear();
             // 执行所有操作(最小化锁持有时间)
             bool hasChanges = false;
             if (operations.Count > 0)
@@ -1008,7 +1268,7 @@ namespace CCDCount.DLL
         // 计算聚合值的方法
         private (int minStartCol, int maxEndCol, long minStartLine, long maxLastSeenLine,
                  int minLastSeenStartCol, int maxLastSeenEndCol, DateTime minStartTime,
-                 DateTime maxEndTime, int totalArea, List<RowStartEndCol> mergedRowsData, int imageWidth)
+                 DateTime maxEndTime,DateTime pictureMinReadTime,int totalArea, List<RowStartEndCol> mergedRowsData, int imageWidth)
         CalculateAggregates(List<ActiveObjectClass> objects)
         {
             int minStartCol = int.MaxValue;
@@ -1019,6 +1279,7 @@ namespace CCDCount.DLL
             int maxLastSeenEndCol = int.MinValue;
             DateTime minStartTime = DateTime.MaxValue;
             DateTime maxEndTime = DateTime.MinValue;
+            DateTime pictureMinReadTime = DateTime.MaxValue;
             int totalArea = 0;
             int imageWidth = objects.FirstOrDefault()?.ImageWidth ?? IdentifyImageWidth;
 
@@ -1035,6 +1296,7 @@ namespace CCDCount.DLL
 
                 if (obj.StartCheckTime < minStartTime) minStartTime = obj.StartCheckTime;
                 if (obj.EndCheckTime > maxEndTime) maxEndTime = obj.EndCheckTime;
+                if (obj.PictureStartReadTime<pictureMinReadTime) pictureMinReadTime = obj.PictureStartReadTime;
 
                 totalArea += obj.Area;
                 mergedRowsData.AddRange(obj.RowsData);
@@ -1042,7 +1304,7 @@ namespace CCDCount.DLL
 
             return (minStartCol, maxEndCol, minStartLine, maxLastSeenLine,
                     minLastSeenStartCol, maxLastSeenEndCol, minStartTime,
-                    maxEndTime, totalArea, mergedRowsData, imageWidth);
+                    maxEndTime,pictureMinReadTime,totalArea, mergedRowsData, imageWidth);
         }
 
         List<ValidRegionModelClass> regions = new List<ValidRegionModelClass>();
@@ -1116,6 +1378,48 @@ namespace CCDCount.DLL
             return new List<ValidRegionModelClass>(regions);
         }
 
+        private List<ValidRegionModelClass> FindValidRegions(ReadOnlySpan<byte> image,int imageWidth, int RowNo)
+        {
+            regions.Clear();
+            regions.Capacity = 10;
+
+            ReadOnlySpan<byte> rowSpan;
+            if (shuLiConfig.IsIdentifyRoiOpen)
+            {
+                int offset = RowNo * imageWidth + shuLiConfig.IdentifyStartX;
+                int length = Math.Min(shuLiConfig.IdentifyStopX - shuLiConfig.IdentifyStartX,
+                                     imageWidth - shuLiConfig.IdentifyStartX);
+                rowSpan = image.Slice(offset, length);
+            }
+            else
+            {
+                rowSpan = image.Slice(RowNo * imageWidth, imageWidth);
+            }
+
+            int start = -1;
+            byte threshold = (byte)shuLiConfig.RegionThreshold;
+
+            for (int i = 0; i < rowSpan.Length; i++)
+            {
+                if (rowSpan[i] < threshold)
+                {
+                    if (start == -1) start = i;
+                }
+                else if (start != -1)
+                {
+                    regions.Add(new ValidRegionModelClass { Start = start, End = i - 1 });
+                    start = -1;
+                }
+            }
+
+            if (start != -1)
+            {
+                regions.Add(new ValidRegionModelClass { Start = start, End = rowSpan.Length - 1 });
+            }
+
+            return new List<ValidRegionModelClass>(regions);
+        }
+
         /// <summary>
         /// 判断区域重叠(与活跃物体的横向坐标重叠检测)
         /// </summary>
@@ -1605,6 +1909,12 @@ namespace CCDCount.DLL
         #endregion
 
         #region 线程方法
+        //信号量
+        public SemaphoreSlim QueueSemaphore { get; set; }
+        //取消令牌
+        public CancellationTokenSource CancellationTokenSource { get; set; }
+        //图像处理线程
+        public Task ProcessingTask { get; set; }
         /// <summary>
         /// 识别图像线程
         /// </summary>
@@ -1635,6 +1945,12 @@ namespace CCDCount.DLL
                     }
                     IFrameDatas.TryDequeue(out IFrameOut IframeData);
                     stopwatch.Stop();
+                    var ShiBieLuoHouTime = (DateTime.Now - FromUnixTimestamp((long)IframeData.HostTimeStamp)).TotalMilliseconds;
+                    // 优化: 将日志记录改为条件执行
+                    if (ShiBieLuoHouTime > 30)
+                    {
+                        LOG.error($"算法落后了超过30ms,相机取图总耗时:{ShiBieLuoHouTime}");
+                    }
                     if (stopwatch.ElapsedMilliseconds > 5)
                     {
                         FaultLog.RecordErrorMessage($"ShuLiClass-IdentifyImageProcess:Image reading timed out, this recognition took time:{stopwatch.Elapsed}");
@@ -1642,13 +1958,71 @@ namespace CCDCount.DLL
                     if (IframeData != null)
                     {
                         //识别
-                        ProcessImageSequence(IframeData);
+                        ProcessImageSequence2(IframeData);
+                        IframeData.Dispose();
+                    }
+                    else
+                    {
+                        continue;
+                    }
+                }
+                else
+                {
+                    Thread.Sleep(1);
+                }
+            }
+        }
+
+        private async void IdentifyImageProcessTask(CancellationToken token)
+        {
+            Stopwatch stopwatch = Stopwatch.StartNew();
+            const int batchSize = 5; // 每批处理的最大图像数量
+            var batch = new List<IFrameOut>(batchSize); // 存储当前批次的图像
+            while (!token.IsCancellationRequested)
+            {
+                // 等待图像数据
+                await QueueSemaphore.WaitAsync(token);
+                //判断队列中是否有数据
+                if (IFrameDatas.Count() > 5)
+                {
+                    //FaultLog.RecordErrorMessage($"图像数据队列中数据过多,请及时处理!当前数据数量为:{IFrameDatas.Count()}");
+                    FaultLog.RecordErrorMessage($"There is too much data in the image data queue. Please handle it in a timely manner! The current data quantity is:{IFrameDatas.Count()}");
+                    if (IFrameDatas.Count() > 100)
+                    {
+                        SystemAlarm.AlarmAlert(AlarmMessageList.待识别队列数据堆积,
+                            $"The image data queue is blocked. Please check the configuration and images",
+                            "待识别队列数据堆积,请检查设置和图像",
+                            "DLL:ShuLIClass-IdentifyImageProcess");
+                    }
+                    else
+                    {
+                        SystemAlarm.AlarmCancel(AlarmMessageList.待识别队列数据堆积);
+                    }
+                }
+                // 收集一批图像(严格按队列顺序)
+                while (batch.Count < batchSize && IFrameDatas.TryDequeue(out IFrameOut imageData))
+                {
+                    batch.Add(imageData);
+                    if (IFrameDatas.Count > 0)
+                    {
+                        QueueSemaphore.Release(); // 提前释放信号量,唤醒其他等待线程
+                    }
+                }
+                // 顺序处理当前批次的所有图像
+                foreach (var image in batch)
+                {
+                    if (image != null)
+                    {
+                        //识别
+                        ProcessImageSequence2(image);
+                        image.Dispose();
                     }
                     else
                     {
                         continue;
                     }
                 }
+                batch.Clear();
             }
         }
         #endregion

+ 111 - 2
TestWork.DLL/SqlDataClass/ActionMesSqliteDataClass.cs

@@ -1,8 +1,11 @@
-using System;
+using CCDCount.MODEL.ShuLiModel; // 确保引用ActiveObjectClass所在命名空间
+using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Data.SQLite;
 using System.IO;
-using CCDCount.MODEL.ShuLiModel; // 确保引用ActiveObjectClass所在命名空间
+using System.Text;
+using System.Threading;
 
 namespace CCDCount.DLL.SqlDataClass
 {
@@ -12,6 +15,11 @@ namespace CCDCount.DLL.SqlDataClass
         private readonly string _connectionString;
         private object locker = new object();
 
+        private readonly ConcurrentQueue<ActiveObjectClass> _dataQueue = new ConcurrentQueue<ActiveObjectClass>();
+        private readonly Timer _timer;
+        private const int MaxBatchSize = 1000; // 单次最大插入条数(受 SQLite 参数上限限制)
+        private const int FlushIntervalMs = 5000; // 最大等待时间(毫秒)
+
         public ActionMesSqliteDataClass(string dbPath)
         {
             DatabaseFile = dbPath;
@@ -28,6 +36,7 @@ namespace CCDCount.DLL.SqlDataClass
                 Directory.CreateDirectory(directoryPath);
             }
             InitializeDatabase();
+            _timer = new Timer(FlushData, null, FlushIntervalMs, FlushIntervalMs);
         }
 
         private void InitializeDatabase()
@@ -88,6 +97,99 @@ namespace CCDCount.DLL.SqlDataClass
         }
 
         // 插入ActiveObjectClass对象及其关联数据
+        public void AddData(ActiveObjectClass data)
+        {
+            _dataQueue.Enqueue(data);
+
+            // 如果缓存数量达到上限,则立即触发写入
+            if (_dataQueue.Count >= MaxBatchSize)
+            {
+                FlushData(null);
+            }
+        }
+
+        // 强制刷新缓存数据到数据库
+        private void FlushData(object state)
+        {
+            lock (locker)
+            {
+                if (_dataQueue.IsEmpty) return;
+
+                var batch = new List<ActiveObjectClass>();
+                while (_dataQueue.TryDequeue(out var item))
+                {
+                    batch.Add(item);
+                }
+
+                WriteBatchToDatabase(batch);
+            }
+        }
+        private void WriteBatchToDatabase(List<ActiveObjectClass> batch)
+        {
+            using (var conn = new SQLiteConnection(_connectionString))
+            {
+                conn.Open();
+                using (var transaction = conn.BeginTransaction())
+                {
+                    try
+                    {
+                        // 构建批量插入语句
+                        var sqlBuilder = new StringBuilder();
+                        sqlBuilder.Append(@"
+                        INSERT INTO ActiveObject (
+                            Num, MinStartCol, MaxEndCol, LastSeenLineStartCol, 
+                            LastSeenLineEndCol, StartLine, LastSeenLine, 
+                            StartCheckTime, EndCheckTime, Area, MaxLength,
+                            ChannelNO, ImageWidth, StateCode, BatchNumber,
+                            hasSignificantConcavity, concavityRatio
+                        ) VALUES ");
+
+                        var parameters = new List<object>();
+                        for (int i = 0; i < batch.Count; i++)
+                        {
+                            var obj = batch[i];
+                            sqlBuilder.Append($"(@p{i * 17}, @p{i * 17 + 1}, @p{i * 17 + 2}, @p{i * 17 + 3}, " +
+                                              $"@p{i * 17 + 4}, @p{i * 17 + 5}, @p{i * 17 + 6}, " +
+                                              $"@p{i * 17 + 7}, @p{i * 17 + 8}, @p{i * 17 + 9}, " +
+                                              $"@p{i * 17 + 10}, @p{i * 17 + 11}, @p{i * 17 + 12}, " +
+                                              $"@p{i * 17 + 13}, @p{i * 17 + 14}, @p{i * 17 + 15}, @p{i * 17 + 16})");
+
+                            if (i < batch.Count - 1)
+                                sqlBuilder.Append(", ");
+
+                            // 绑定参数值
+                            parameters.AddRange(new object[]
+                            {
+                            obj.Num, obj.MinStartCol, obj.MaxEndCol, obj.LastSeenLineStartCol,
+                            obj.LastSeenLineEndCol, obj.StartLine, obj.LastSeenLine,
+                            obj.StartCheckTime.ToString("o"), obj.EndCheckTime.ToString("o"),
+                            obj.Area, obj.MaxLength, obj.ChannelNO, obj.ImageWidth,
+                            obj.StateCode, obj.BatchNumber, obj.hasSignificantConcavity, obj.concavityRatio
+                            });
+                        }
+
+                        // 执行批量插入
+                        using (var cmd = new SQLiteCommand(sqlBuilder.ToString(), conn))
+                        {
+                            for (int i = 0; i < parameters.Count; i++)
+                            {
+                                cmd.Parameters.AddWithValue($"@p{i}", parameters[i]);
+                            }
+
+                            cmd.ExecuteNonQuery();
+                        }
+
+                        transaction.Commit();
+                    }
+                    catch
+                    {
+                        transaction.Rollback();
+                        throw;
+                    }
+                }
+            }
+        }
+
         public void InsertActiveObject(ActiveObjectClass activeObject)
         {
             lock (locker)
@@ -470,5 +572,12 @@ namespace CCDCount.DLL.SqlDataClass
             }
             return result;
         }
+
+        // 关闭定时器并释放资源
+        public void Dispose()
+        {
+            _timer?.Dispose();
+            FlushData(null); // 确保最后一批数据被写入
+        }
     }
 }

+ 1 - 1
TestWork.DLL/Tools/LogClass.cs

@@ -19,7 +19,7 @@ namespace LogClass
         }
         static public void error(object str)
         {
-            log("Erorr:" + str, 10);
+            log("Error:" + str, 10);
         }
         //static object syn = new object();
         /// <summary>

+ 16 - 10
WpfSwitchLanguage/WpfPage/MainPage.xaml.cs

@@ -148,8 +148,14 @@ namespace CCDCountWpf.WpfPage
                         DateTime RecordTime = DateTime.Now;
                         var OutTimeBatch = batchRecordModels.Where(x => x.RecordTime.AddMinutes(1) < RecordTime).ToList();
                         OutTimeBatch.ForEach(x => batchRecordModels.Remove(x));
-                        PlcSettingMessageBus.pLCManagement.ReadBottingVibrationTableHighSpeedValue(out ushort BottingVibrationTableHighSpeedValue, out ushort FilterVibrationTableHighSpeedValue, out ushort CountVibrationTableHighSpeedValue);
-                        PlcSettingMessageBus.pLCManagement.ReadBottingCount(out ushort BottingCount);
+                        if(!PlcSettingMessageBus.pLCManagement.ReadBottingVibrationTableHighSpeedValue(out ushort BottingVibrationTableHighSpeedValue, out ushort FilterVibrationTableHighSpeedValue, out ushort CountVibrationTableHighSpeedValue))
+                        {
+                            continue ;
+                        }
+                        if(!PlcSettingMessageBus.pLCManagement.ReadBottingCount(out ushort BottingCount))
+                        {
+                            continue ;
+                        }
                         ushort CountSPeed = (ushort)(batchRecordModels.Count() > 0 ? (BottingCount - batchRecordModels.Min(o => o.BottingCount)) > 0 ? BottingCount - batchRecordModels.Min(o => o.BottingCount) : 0 : 0);
                         ShowMessageBus.ShowBinding.BottingSpeed = CountSPeed;
                         BatchRecordModel batchRecordModel = new BatchRecordModel
@@ -186,13 +192,13 @@ namespace CCDCountWpf.WpfPage
 
         private void StartIdentifyBtn_Click(object sender, RoutedEventArgs e)
         {
-            if(String.IsNullOrWhiteSpace(ShowMessageBus.ShowBinding.BatchNumber))
+            if (String.IsNullOrWhiteSpace(ShowMessageBus.ShowBinding.BatchNumber))
             {
                 MessageBox.Show("请输入批次号!");
                 return;
             }
             RunBatchRecord(ShowMessageBus.ShowBinding.BatchNumber);
-            if(!RunCameraIdentify())
+            if (!RunCameraIdentify())
             {
                 return;
             }
@@ -200,7 +206,7 @@ namespace CCDCountWpf.WpfPage
             StartIdentifyBtn.Opacity = 0.5;
             StopIdentifyBtn.IsEnabled = true;
             StopIdentifyBtn.Opacity = 1;
-            if(PlcSettingMessageBus.pLCManagement.IsConnect)
+            if (PlcSettingMessageBus.pLCManagement.IsConnect)
             {
                 PlcSettingMessageBus.pLCManagement.MachineRunToTrue();
             }
@@ -210,15 +216,15 @@ namespace CCDCountWpf.WpfPage
         {
             StopCameraIdentify();
             LOG.log("停止相机成功");
-            StopBatchRecord();
+            //StopBatchRecord();
             StartIdentifyBtn.IsEnabled = true;
             StartIdentifyBtn.Opacity = 1;
             StopIdentifyBtn.IsEnabled = false;
             StopIdentifyBtn.Opacity = 0.5;
-            if (PlcSettingMessageBus.pLCManagement.IsConnect)
-            {
-                PlcSettingMessageBus.pLCManagement.MachineStopToTrue();
-            }
+            //if (PlcSettingMessageBus.pLCManagement.IsConnect)
+            //{
+            //    PlcSettingMessageBus.pLCManagement.MachineStopToTrue();
+            //}
         }
 
         private void BottingMaterialCylinderVibrationTableHighSpeedValueUpUpBtn_Click(object sender, RoutedEventArgs e)