using CCDCount.DLL.SqlDataClass; using CCDCount.DLL.Tools; using CCDCount.MODEL.CameraClass; using CCDCount.MODEL.ConfigModel; using CCDCount.MODEL.ResultModel; using CCDCount.MODEL.ShuLiModel; using LogClass; using MvCameraControl; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Remoting.Messaging; using System.Text; using System.Threading; namespace CCDCount.DLL { public class MainThreadClass { #region 变量与实例 Thread SwitchIdentifyImageThread = null; private bool IsSwitch = false; public ShuLiClass shuLiClass = null; CameraClass cameraClass = new CameraClass(); public ShuLiConfigClass shuLiConfig = null; public CameraConfig cameraConfig = null; public bool CameraConfigIsChange = false; public int ThisCamerNo = -1; public bool CameraStatic { get { return _CameraStatic; } } private bool _CameraStatic = false; // 返回交换线程状态 public bool CameraRunStatic { get { return IsSwitch; } } public bool IsOpenLoadThread { get { return _IsOpenLoadThread; }} private bool _IsOpenLoadThread = false; public int HistoryActiveNum { get { return shuLiClass.GetHistoryActiveNum(); } } public int OkHistoryNum { get { return shuLiClass.GetOkHistoryNum(); } } public int NgHistoryNum { get { return shuLiClass.GetNgHistoryNum(); } } // 数粒信息发送线程 Thread SendBottLogicMessageThread = null; bool IsSend = false; // Modbus客户端实例 public ModbusTcpClient modbusTcpClient = new ModbusTcpClient(); // 颗粒结果待发送队列 ConcurrentQueue SendQueue = new ConcurrentQueue(); /// /// 数粒状态计时器 /// Stopwatch stopwatch = Stopwatch.StartNew(); /// /// 数粒状态 /// private bool _ShuLiState = true; public bool ShuLiState { get { return _ShuLiState; } } private bool _IsDebug = true; public bool IsDebug { get { return _IsDebug; } } private bool IsConnectModbus = false; public static ActionMesSqliteDataClass actionMesSqliteDataClass = null; ConcurrentQueue _images = new ConcurrentQueue(); public string FormulationName { get; set; } = string.Empty; public bool IsLoadFormulation = false; #endregion #region 公共方法 /// /// 设置ModbusTcpClient /// /// public void ConnectModbus(string ipAddress) { if (!modbusTcpClient.Connect(ipAddress)) { FaultLog.RecordErrorMessage($"MianThread{cameraConfig.CamerNo}-Modbus通讯连接失败,目标IP:{ipAddress}"); return; } IsConnectModbus = true; } /// /// 初始化构造方法 /// /// /// public MainThreadClass(ShuLiConfigClass configClass,CameraConfig CameraConfig) { shuLiConfig = configClass; cameraConfig = CameraConfig; // 数粒配置文件地址 if (configClass!=null) { // 创建数粒对象(配置文件) shuLiClass = new ShuLiClass(shuLiConfig); } else { // 创建数粒对象(默认) shuLiClass = new ShuLiClass(); } _IsOpenLoadThread = cameraConfig.IsOpenLoad; ThisCamerNo = cameraConfig.CamerNo; actionMesSqliteDataClass = new ActionMesSqliteDataClass($"{AppDomain.CurrentDomain.BaseDirectory}DATA\\ActiveObjectData\\Cam{cameraConfig.CamerNo}\\ActiveObjectData{DateTime.Now:yyyyMMdd}.db"); actionMesSqliteDataClass.GetAllActionMinStartMaxEndLine(out int num, out int StartLine, out int EndLine); shuLiClass.InitCurrentLine(EndLine); //shuLiClass.InitNum(num); } /// /// 加载相机 /// /// public bool LoadCamera() { bool result = false; // 相机列表 try { // 获取相机列表 cameraClass.GetCameraList(out List list); if (list.Count == 0) { FaultLog.RecordErrorMessage(string.Format("{0}:没有相机", "MainThreadClass-StartMianThread")); // 如果没有相机,则退出 return result; } // 加载相机 // cameraClass.LoadCamereDevice(list.First().DeviceSN); if (!cameraClass.LoadCamereDevice(cameraConfig)) { FaultLog.RecordErrorMessage(string.Format("{0}:相机加载失败", "MainThreadClass-StartMianThread")); return result; } CameraConfigIsChange = false; } catch { } return result; } /// /// 重新加载相机配置 /// public void ReLoadCameraConfig() { if(CameraConfigIsChange) { CameraConfig OldcameraConfig = cameraClass.GetConfigValue(); if(OldcameraConfig.CameraSNNum != cameraConfig.CameraSNNum) { cameraClass.LoadCamereDevice(cameraConfig); } else { cameraClass.ReLoadCameraConfig(cameraConfig); } } } /// /// 开始主线程 /// public bool StartMianThread() { bool result = false; try { // 取图线程开启 if(!cameraClass.StartCamera()) { return result; } _CameraStatic = true; StartSendBottLogicMessageThread(); // 数据交换线程开启 StartSwitchThread(); // 为数粒算法的识别成功一粒回调函数添加方法 shuLiClass.WorkCompleted += Worker_OneGrainCompleted; // 开启识别线程 shuLiClass.StartIdentifyFuntion(cameraClass.GetCamereImageSize().Width); result = true; } catch { } return result; } /// /// 停止主线程 /// public bool StopMianThread() { bool result = false; try { _CameraStatic = false; shuLiClass.WorkCompleted -= Worker_OneGrainCompleted; // 相机取图关闭 cameraClass.StopCamera(); // 数据交换线程关闭 StopSwitchThread(); // 数粒识别线程关闭 shuLiClass.StopIdentifyFuntion(); StopSendBottLogicMessageThread(); result = true; } catch { } return result; } /// /// 释放相机资源 /// public void DisposeCamera() { cameraClass.StopCamera(); cameraClass.DisPoseCamera(); } /// /// 重加载相机 /// /// /// public bool ReLoadCamera(string CameraSN) { bool result = false; result = cameraClass.ReLoadCameraDevice(CameraSN); if (result) { cameraConfig = cameraClass.GetConfigValue(); } return result; } /// /// 获取显示用的图片数据 /// /// /// public void GetShowImage(int ImageHeight,out Bitmap ImageData) { List RowsShowList = new List(); ActiveObjectClass NewActive = shuLiClass.GetLastActive(); if (NewActive == null) { LOG.log(string.Format("{0}:没有获取到数粒数据", "MainThreadClass-GetShowImage")); ImageData = GetNullShowImage(4096, 2000); return; } List Data = shuLiClass.GetHistoryActive().Where(o => o.LastSeenLine > NewActive.LastSeenLine - ImageHeight).ToList(); Bitmap BitmapImage = new Bitmap(NewActive.ImageWidth, ImageHeight); if (Data.Count > 0) { int ThisImageStartLine = (int)Data.Max(o => o.LastSeenLine) - ImageHeight; using (Graphics g = Graphics.FromImage(BitmapImage)) { g.Clear(Color.White); var redPen = new Pen(Color.Red, 1); var bluePen = new Pen(Color.FromArgb(0,146,255), 1); var GreenPen = new Pen(Color.SeaGreen, 5); using (Pen RedPan = new Pen(Color.Red, 5)) { for (int i = 0; i < shuLiClass.ChannelsRoi.Count - 1; i++) { g.DrawLine(RedPan, new Point(shuLiClass.ChannelsRoi[i], 0), new Point(shuLiClass.ChannelsRoi[i], BitmapImage.Height)); } } foreach (var item in Data) { int roix = item.MinStartCol - 5; int roiy = (int)(item.StartLine - ThisImageStartLine) - 5 < 0 ? 0 : (int)(item.StartLine - ThisImageStartLine) - 5; int roiheight = (int)(item.LastSeenLine - ThisImageStartLine - roiy) + 10; int roiwidth = item.MaxEndCol - item.MinStartCol + 10; g.DrawRectangle(GreenPen, new Rectangle(roix, roiy, roiwidth, roiheight)); Font font = new Font("Arial", 40); g.DrawString(item.Num.ToString(), font, Brushes.Black, new Point(roix - 50*item.Num.ToString().Length, roiy - 20)); foreach (var item1 in item.RowsData) { if((int)(item1.RowsCol - ThisImageStartLine)<0) continue; int yPos = (int)(item1.RowsCol - ThisImageStartLine); g.DrawLine(item.StateCode == 0 ? bluePen : redPen, new Point(item1.StartCol, yPos), new Point(item1.EndCol, yPos)); } } } } ImageData = BitmapImage.Clone() as Bitmap; BitmapImage.Dispose(); //GC.Collect(); } /// /// 获取无数据的图片 /// /// /// /// public Bitmap GetNullShowImage(int ImageWidth, int ImageHeight) { Bitmap BitmapImage = new Bitmap(ImageWidth, ImageHeight); using (Graphics g = Graphics.FromImage(BitmapImage)) { g.Clear(Color.White); using (Pen RedPan = new Pen(Color.Red, 8)) { for (int i = 0; i < shuLiClass.ChannelsRoi.Count - 1; i++) { g.DrawLine(RedPan, new Point(shuLiClass.ChannelsRoi[i], 0), new Point(shuLiClass.ChannelsRoi[i], BitmapImage.Height)); } } } return BitmapImage; } /// /// 获取此刻的Config数据 /// /// public void GetAllConfigValue(out CameraConfig Camconfig,out ShuLiConfigClass shuLiConfig) { //判断是否加载了相机 if(cameraClass.IsLoadCamera()) { //获取已经加载的相机的配置 cameraConfig = cameraClass.GetConfigValue(); Camconfig = cameraConfig; } else { cameraConfig = new CameraConfig(); Camconfig = cameraConfig; } //读取视觉配置 shuLiConfig = shuLiClass.GetConfigValue(); this.shuLiConfig = shuLiConfig; } /// /// 获取相机此刻的Config数据 /// /// public CameraConfig GetCameraConfig() { CameraConfig result = null; //判断是否加载了相机 if (cameraClass.IsLoadCamera()) { //获取已经加载的相机的配置 result = cameraClass.GetConfigValue(); cameraConfig = result; } return result; } /// /// 保存所有Config /// public void SaveAllConfig() { shuLiClass.SaveConfig(); } /// /// 获取相机连接状态 /// /// public bool GetCameraConnectStatic() { bool result = false; if(cameraClass != null) result = cameraClass.IsConnectCamera(); return result; } /// /// 清除历史数据 /// /// public bool ClearHistoryActive() { bool result = false; if(shuLiClass != null) result = shuLiClass.ClearHistoryActive(); return result; } /// /// 获取过去一秒内颗粒数量 /// /// public int GetOneSecondActiveNum() { int result = 0; if(shuLiClass != null) result = shuLiClass.GetHistoryActive().Where(o=>o.EndCheckTime>DateTime.Now-TimeSpan.FromSeconds(1)).Count(); return result; } /// /// 获取相机原图一张 /// /// public Bitmap GetCamImageOnce() { Bitmap result = null; if(_images.Count>0) { _images.TryDequeue(out IImage image); if(image != null) result = image.ToBitmap(); } return result; } /// /// 获取相机原图拼接图-50张拼一张 /// /// public Bitmap GetSpliceCamImageOnce() { Bitmap result = null; if (_images.Count >= 50) { CameraImageSizeClass cameraImageSize = cameraClass.GetCamereImageSize(); if (cameraImageSize.Width == 0 || cameraImageSize.Height == 0) return null; result = new Bitmap(cameraImageSize.Width, cameraImageSize.Height * 50); using (Graphics g = Graphics.FromImage(result)) { g.Clear(Color.White); // 设置背景色 int currentY = 0; for (int i = 0; i < 50; i++) { Bitmap OutImage = GetCamImageOnce(); // 将每个图像绘制到新Bitmap上 g.DrawImage(OutImage, new Point(0, currentY)); currentY += OutImage.Height; } } } return result; } public void ParameterTrain(List ListValues) { if(ListValues.Count() > 0) { if(ListValues.Count()>500) { ListValues = ListValues.Take(500).OrderByDescending(o=>o.Area).ToList(); } int MaxArea = ListValues.Max(x => x.Area); int MinArea = ListValues.Min(x => x.Area); double MaxLength = ListValues.Max(x => x.MaxLength); double MinLength = ListValues.Min(x => x.MaxLength); if(ListValues.Count<2) return; int ChazhiId = -1; int MaxChazhi = 0; for (int i = 1; i < ListValues.Count; i++) { int Chazhi = (ListValues[i - 1].Area - ListValues[i].Area); if (Chazhi > MaxChazhi*10) { MaxChazhi = Chazhi; ChazhiId = i; } } if(ChazhiId == -1) return; int yuzhi = (int)Math.Sqrt(2) + 2; } } public ParaTrainResultClass ParameterTrain() { var ListValues = shuLiClass.GetHistoryActive(); ParaTrainResultClass Result = new ParaTrainResultClass(); if (ListValues.Count() > 0) { if (ListValues.Count() > 500) { ListValues = ListValues.Skip(ListValues.Count - 500).OrderByDescending(o => o.Area).ToList(); } if (ListValues.Count < 2) return Result; int ChazhiId = -1; int MaxChazhi = 0; for (int i = 1; i < ListValues.Count; i++) { if ((ListValues[i - 1].Area*3 <= ListValues[i].Area)) { int Chazhi = (ListValues[i - 1].Area - ListValues[i].Area); if (Chazhi > MaxChazhi) { MaxChazhi = Chazhi; ChazhiId = i; } } } if (ChazhiId != -1) { Result.NoiseFilterThreshold = ListValues[ChazhiId].Area>=200?200:(int)(ListValues[ChazhiId].Area * 1.1); } else { Result.NoiseFilterThreshold = 200; } if (Result.NoiseFilterThreshold != -1) { ListValues = ListValues.Where(o => o.Area >= Result.NoiseFilterThreshold).ToList(); } Result.MaxArea = ListValues.Max(x => x.Area); Result.MinArea = ListValues.Min(x => x.Area); Result.MaxLength = ListValues.Max(x => x.MaxLength); Result.MinLength = ListValues.Min(x => x.MaxLength); } return Result; } #endregion #region 私有方法 //bool IsFill = false; //bool IsXuanZhuanCloseFaMen = false; /// /// 每数完一粒识别线程执行的事件 /// /// /// private void Worker_OneGrainCompleted(object sender, ActiveObjectEventArgsClass e) { LOG.log("有活跃物体转换为了历史物体,回调事件被触发!", 6); LOG.log(string.Format("图像处理实例中的待识别图像缓存队列长度{0}", shuLiClass.ImageNum), 6); if (e.Actives.Where(o => o.StateCode == 7).Count() > 0) { stopwatch.Restart(); _ShuLiState = false; } else if (stopwatch.ElapsedMilliseconds > 1000) { stopwatch.Stop(); _ShuLiState = true; } //往数组中计数 ushort result = new ushort(); // 事件处理逻辑 foreach (ActiveObjectClass oneActive in e.Actives) { Console.WriteLine(string.Format("输出当前颗粒信息,开始行:{0},结束行:{1},开始时间:{2}结束时间:{3},颗粒状态:{4},通道数:{5}", oneActive.StartLine, oneActive.LastSeenLine, oneActive.StartCheckTime.ToString("O"), oneActive.EndCheckTime.ToString("O"), oneActive.StateCode, oneActive.ChannelNO)); LOG.log(string.Format("输出当前颗粒信息,开始行:{0},结束行:{1},开始时间:{2}结束时间:{3},颗粒状态:{4},通道数:{5}", oneActive.StartLine, oneActive.LastSeenLine, oneActive.StartCheckTime.ToString("O"), oneActive.EndCheckTime.ToString("O"), oneActive.StateCode, oneActive.ChannelNO), 6); if(actionMesSqliteDataClass!=null) { actionMesSqliteDataClass.InsertActiveObject(oneActive); } if (oneActive.StateCode != 7 && oneActive.ChannelNO != -1) { //单通道合格计数 result |= (ushort)(1 << oneActive.ChannelNO); } else { //单通道不合格计数 result |= (ushort)(1 << (8 + oneActive.ChannelNO)); } } LOG.log("当前待发送队列数量:" + SendQueue.Count, 6); if(IsSend) { SendQueue.Enqueue(result); } } #endregion #region 线程方法 /// /// 开启交换线程 /// private void StartSwitchThread() { IsSwitch = true; SwitchIdentifyImageThread = new Thread(SwitchIdentifyImageProcess); SwitchIdentifyImageThread.Start(); } /// /// 关闭交换线程 /// private void StopSwitchThread() { try { // 标志位设为false IsSwitch = false; if (SwitchIdentifyImageThread != null && SwitchIdentifyImageThread.IsAlive) SwitchIdentifyImageThread.Join(); } catch (Exception ex) { FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message); throw; } } /// /// 交换线程 /// private void SwitchIdentifyImageProcess() { IFrameOut IFramedata = null; Stopwatch stopwatch = Stopwatch.StartNew(); stopwatch.Start(); while (IsSwitch) { if (stopwatch.ElapsedMilliseconds > 1000) { //Console.WriteLine("交换线程-图像处理实例中的待识别图像缓存队列长度{0}", shuLiClass.ImageNum); GC.Collect(); stopwatch.Restart(); } //Thread.Sleep(5); bool result = cameraClass.GetOnceImage(out IFramedata); if (result) { //Debug模式,不进行图像处理 if (_IsDebug) { _images.Enqueue(IFramedata.Image); if (_images.Count > 5) { _images.TryDequeue(out IImage image); image.Dispose(); } } if (IFramedata == null) continue; shuLiClass.SetOnceIdentifyImageData(IFramedata.Image); } else continue; IFramedata.Dispose(); } stopwatch.Stop(); } /// /// 启动发送消息线程 /// private void StartSendBottLogicMessageThread() { try { if(!IsConnectModbus) return; //zmcauxClass.OpenZmcauxCard(); timeBeginPeriod(1); // 设置为1ms精度 IsSend = true; SendBottLogicMessageThread = new Thread(SendBottLogicMessageProcess); SendBottLogicMessageThread.Start(); } catch (Exception ex) { FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message); throw; } } /// /// 停止发送消息线程 /// private void StopSendBottLogicMessageThread() { try { // 标志位设为false IsSend = false; if (SendBottLogicMessageThread != null && SendBottLogicMessageThread.IsAlive) SendBottLogicMessageThread.Join(); //if (modbusTcpClient != null) modbusTcpClient.Disconnect(); } catch (Exception ex) { FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message); throw; } } /// /// 信息发送线程 /// private void SendBottLogicMessageProcess() { //获取数据 ushort sendMessage = 0; bool AllowTransfer = false; bool TransferDone = false; Stopwatch sw = Stopwatch.StartNew(); while (IsSend) { //LOG.log("进入线程", 6); sw.Restart(); sendMessage = new ushort(); //读取装瓶状态 AllowTransfer = false; TransferDone = false; bool[] ReadResult = modbusTcpClient.ReadCoilsRegister(slaveId: 1, startAddress: 11, numRegisters: 2); if (ReadResult == null) { continue; } AllowTransfer = ReadResult[1]; TransferDone = ReadResult[0]; //LOG.log(string.Format("读取值:AllowTransfer[0]:{0},TransferDone[1]:{1}", AllowTransfer, TransferDone), 6); //当允许写入且处于未写入的状态时 if (AllowTransfer && !TransferDone) { if (SendQueue.Count() > 0) { if (!SendQueue.TryDequeue(out sendMessage)) { FaultLog.RecordErrorMessage("MainThreadClass-SendBottLogicMessageProcess-SendQueue.TryDequeue failed!"); } } if (sendMessage != 0) { //写入数据 modbusTcpClient.WriteSingleRegister(slaveId: 1, registerAddress: 100, value: sendMessage); modbusTcpClient.WriteCoilsRegister(slaveId: 1, CoilsAddress: 11, values: true); } sw.Stop(); FaultLog.RecordLogMessage(string.Format("sendMessage[1]:{0},此次写值耗时:{1}", sendMessage, sw.Elapsed),1); } Thread.Sleep(1); } } #endregion #region 外部函数 [DllImport("winmm.dll")] static extern uint timeBeginPeriod(uint period); #endregion } }