using Bro.Common.Base; using Bro.Common.Helper; using Bro.Common.Interface; using Bro.Common.Model; using Bro.Device.InsCamera; using Bro.M135.Common; using Bro.M135.DBManager; using Bro.Process; using Bro.Process.DataBase.Models; using Bro.UI.Model.Winform; using HalconDotNet; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NPOI.SS.Formula.Functions; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Ocsp; using ScottPlot.Drawing.Colormaps; using Sunny.UI; using Sunny.UI.Win32; using System.Collections.Concurrent; using System.Collections.Generic; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Text; using Windows.ApplicationModel.Appointments; using Windows.Networking; using static Org.BouncyCastle.Math.EC.ECCurve; namespace Bro.M141.Process { public partial class M141Process : ProcessControl { #region constructor public M141Process() { } public M141Process(string productCode) : base(productCode) { } #endregion TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning); protected M141Config M141Config => Config as M141Config; public static object _productListLock = new object(); public List ProductList = new List(); MachineLearningBase ML = null; public event Action> RefreshUIplc; public event Action RefreshState; List ZipImages = new List(); public override void InitialProcessMethods() { base.InitialProcessMethods(); if (ThHeartPlc == null) { ThHeartPlc = new Thread(Heartplc); ThHeartPlc.IsBackground = true; ThHeartPlc.Start(); } } public override void ProcessRunStateChanged() { base.ProcessRunStateChanged(); } public PLCBase Plc1; Thread ThHeartPlc; Spec _errorSpec; bool isstart = false; public override void Open() { base.Open(); ML = DeviceCollection.FirstOrDefault(u => u is MachineLearningBase) as MachineLearningBase; if (ML == null) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Information, $"未设置ML实例"); } Plc1 = DeviceCollection.FirstOrDefault(u => u is PLCBase) as PLCBase; if (Plc1 == null) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"未设置plc"); } _errorSpec = M141Config.SpecCollection.FirstOrDefault(u => u.Code == M141Config.CheckErrorSpecCode) as Spec; NetWarmUp(); _positionCheckTimeDict.Clear(); _positionSpecHeads.Clear(); InitialContinuousNGAlarm(); int vava = 0; if (M141Config.channelva == 3) { vava = 0; } else if (M141Config.channelva == 2) { vava = 1; } Plc1.WriteSingleAddress(3006, vava, out _); isstart = true; } public override void Close() { isstart = false; base.Close(); } public void Heartplc() { Thread.Sleep(1000); string _statisticFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Statistic.json"); if (File.Exists(_statisticFilePath)) { try { string dataStr = ""; using (StreamReader reader = new StreamReader(_statisticFilePath, System.Text.Encoding.UTF8)) { dataStr = reader.ReadToEnd(); } lock (StatisticRecordsFull) { var temRecords = JsonConvert.DeserializeObject(dataStr); if (StatisticRecordsFull != null && temRecords != null) { StatisticRecordsFull.CurRecord = temRecords.CurRecord; StatisticRecordsFull.HistoryRecord = temRecords.HistoryRecord; } } } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"产品统计信息反序列化异常"); StatisticRecordsFull = new StatisticRecords_Full(); } } int state = 0; int state2 = 0; int numsum = 0; DateTime dtday = DateTime.Now; while (true) { Thread.Sleep(1000); if (!isstart) { continue; } numsum++; try { Plc1.WriteSingleAddress(3009, 2, out _); } catch { } try { if (M141Config.WorkShiftList != null && M141Config.WorkShiftList.Count > 0 && numsum >= 0) { for (int i = 0; i < M141Config.WorkShiftList.Count; i++) { double timeshap = (DateTime.Now - M141Config.WorkShiftList[i].ShiftTime_Start).TotalMinutes % 1440; double timeshap2 = (DateTime.Now - M141Config.WorkShiftList[i].ShiftTime_End).TotalMinutes % 1440; if (timeshap2 > 0 && timeshap2 < 1) { if (M141Config.WorkShiftList[i].IsRecordProductSummary) { string csvPathAll = Path.Combine(M141Config.LogPath, "Alldata.csv"); using (StreamWriter writer = new StreamWriter(csvPathAll, true, Encoding.UTF8)) { try { int sum = StatisticRecordsFull.CurRecord.ProductSummary.RecordsList.Where(u => u.IsStatistic).Sum(u => u.Amount); int OKnum = 0; string okpercent = ""; string headcsv = "日期,班次,总数,OK,OK占比"; string datacsv = ""; StatisticRecordsFull.CurRecord.ProductSummary.RecordsList.ForEach(u => { if (u.ClassDesc.ToUpper() == "OK") { OKnum = u.Amount; okpercent = u.PercentStr; } else { headcsv += $",{u.ClassDesc},{u.ClassDesc}占比"; datacsv += $",{u.Amount},{u.PercentStr}"; } }); string daystr = DateTime.Now.ToString("yyyyMMdd"); if (M141Config.WorkShiftList[i].ShiftTime_End.TimeOfDay < M141Config.WorkShiftList[i].ShiftTime_Start.TimeOfDay) { daystr = DateTime.Now.AddDays(-1).ToString("yyyyMMdd"); } datacsv = $"{daystr}T,{M141Config.WorkShiftList[i].ShiftName},{sum},{OKnum},{OKnum}" + datacsv; writer.WriteLine(headcsv); writer.WriteLine(datacsv); } catch (Exception exx) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, exx.ToString()); } } } numsum = -62; } if (timeshap > 0 && timeshap < 1) { if (M141Config.WorkShiftList[i].IsClearProductSummary) { StatisticRecordsFull.CurRecord.ProductSummary.RecordsList.Clear(); StatisticRecordsFull.CurRecord.DefectSummary.RecordsList.Clear(); } numsum = -62; } } } lock (StatisticRecordsFull) { if (numsum > 20) { numsum = 0; using (FileStream fileStream = new FileStream(_statisticFilePath, FileMode.OpenOrCreate, FileAccess.Write)) { fileStream.Seek(0L, SeekOrigin.Begin); string s = JsonConvert.SerializeObject(StatisticRecordsFull); byte[] bytes = Encoding.UTF8.GetBytes(s); fileStream.Write(bytes, 0, bytes.Length); fileStream.SetLength(bytes.Length); fileStream.Flush(); fileStream.Close(); } } } } catch (Exception ex) { } try { var tem = Plc1.Read(3030, 18, out _); if (tem != null && RefreshUIplc != null) { RefreshUIplc.Invoke(tem); } } catch { } try { var tem = Plc1.Read(3010, 8, out _); if (tem != null && RefreshUIplc != null) { RefreshUIplc.Invoke(tem); } } catch { } try { var tem = Plc1.Read(3027, 1, out _)[0]; var tem2 = Plc1.Read(3028, 1, out _)[0]; if (state != tem || state2 != tem2) { state = tem; state2 = tem2; if (RefreshState != null) { if (state == 1) { RefreshState.Invoke("调试模式"); } else if (state2 == 1) { RefreshState.Invoke("离线模式"); } else { RefreshState.Invoke("正常模式"); } } } } catch { } } } public void PlcWrite(int add, int va) { try { Plc1.WriteSingleAddress(add, va, out _); var tem = Plc1.Read(3030, 18, out _); if (tem != null && RefreshUIplc != null) { RefreshUIplc.Invoke(tem); } } catch { } } /// /// 网络预热 /// /// private void NetWarmUp() { string warmUpImageFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WarmUp"); if (!Directory.Exists(warmUpImageFolder)) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"程序根目录下没有\"WarmUp\"预热图片文件夹"); return; } var ml = DeviceCollection.FirstOrDefault(u => u is MachineLearningBase && u.CurrentState == EnumHelper.DeviceState.DSOpen) as MachineLearningBase; if (ml == null) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"预热时未能获取开启的深度学习驱动"); return; } var netNames = ml.IConfig.NetCollections.Where(u => u.IsEnabled).Select(u => u.Name).ToList(); var imageFiles = new DirectoryInfo(warmUpImageFolder).GetFiles().Select(u => u.FullName).ToList(); Parallel.ForEach(netNames, n => { Parallel.ForEach(imageFiles, i => { HImage hImage = new HImage(); hImage.ReadImage(i); ml.RunNetEvaluate(n, hImage); hImage.Dispose(); hImage = null; }); }); LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, "深度学习驱动预热完成"); if (M141Config.WarmUp && M141Config.WarmUpList.Count > 0) { M141Config.WarmUpList.AsParallel().ForAll(x => { try { HImage im = new HImage(x.PicFilePath); var tool = GetHalconTool(null, "", x.HalconFilePath); if (tool != null) { //int num = 0; //for (int i = 0; i < 10; i++) //{ try { var res = tool.RunProcedure(null, new Dictionary() { { "INPUT_Image", im } }, new List() { "OUTPUT_Results_1", "OUTPUT_Results_2" }, null); //if (res != null) //{ // if (res.Item1&& res.Item2[$"OUTPUT_Results_{i}"].HTupleToDouble()[0]!=-1234) // { // num++; // if (num >= 2) // { // LogAsync(DateTime.Now, EnumHelper.LogLevel.Detail, $"算法{x.HalconFilePath}预热完成{i}"); // break; // } // } //} } catch { } //if (i==9) //{ // LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"算法{x.HalconFilePath}预热失败{num}"); //} //} } im.Dispose(); } catch { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"算法{x.HalconFilePath}预热失败"); } }); } LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, "算法预热完成"); } static object _positionCheckTimeLock = new object(); Dictionary> _positionCheckTimeDict = new Dictionary>(); Dictionary> _positionSpecHeads = new Dictionary>(); volatile int uploadId = 0; public void NewProductIntoList(ProductModel p, bool isSaveDB) { lock (_productListLock) { ProductList.RemoveAll(u => u.PID == p.PID || u.SEQUENCE == p.SEQUENCE); ProductList.Insert(0, p); while (ProductList.Count > 200) { ProductList.RemoveAt(ProductList.Count - 1); } } //if (isSaveDB) //{ // var isNewDone = _manager_P_Product.NewProduct(p, p.Details, out string msg); // if (!isNewDone) // { // LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"产品{p.PID}数据库新增异常,{msg}"); // } //} LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"{p.PID}_{p.SEQUENCE}产品入列完成"); } public virtual ProductModel FindProductBySequence(string sequence, bool isEnabelQueue) { ProductModel p = null; if (isEnabelQueue) { lock (_productListLock) { p = ProductList.FirstOrDefault(u => u.SEQUENCE == sequence); } } if (p != null) { return p; } else { //var pDB = _manager_P_Product.QueryProductBySequence(sequence); //if (pDB != null) //{ // p = new ProductModel(pDB); // LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"从数据库获取产品对象{pDB.PID},序号{pDB.SEQUENCE},条码{pDB.SN}"); //} if (p == null) { p = new ProductModel(); p.SEQUENCE = sequence; p.PID = p.PID + "_" + sequence.Split('_')[sequence.Split('_').Length - 1]; p.Initial(M141Config.StationCode, M141Config.WorkPositionCollection.Where(u => u.IsEnabled).Select(u => u.PositionName).ToList()); LogAsync(DateTime.Now, EnumHelper.LogLevel.Warning, $"未能获取产品对象,使用临时新建产品对象"); } NewProductIntoList(p, false); } return p; } public async Task RunImageCheckAsync(List products, string triggerText, string triggerSource, IImageSet imgSet, MeasureBind measureBind) { await Task.Run(() => { List resultList = new List(); if (products == null || products.Count == 0) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"工位{measureBind.WorkPosition}检测时产品信息为空"); imgSet.HImage?.Dispose(); imgSet.HImage = null; return; } try { List pidList = products.Select(u => u.PID).OrderBy(u => u).ToList(); if (imgSet == null || imgSet.HImage == null) { throw new Exception($"产品{string.Join(",", pidList)}检测{measureBind.GetDisplayText()}未能获取图片对象"); } //检测顺序 ML->自定义检测 if (!string.IsNullOrWhiteSpace(measureBind.DetectionId)) { string detectionName = (ML.InitialConfig as MLInitialConfigBase).DetectionConfigs.FirstOrDefault(u => u.Id == measureBind.DetectionId)?.Name; //List pidList2 = new List();//pidList.Select(u => u.Split('_')[u.Split('_').Length - 1]).ToList(); //Dictionary dicpid = new Dictionary(); //for (int i = 0; i < pidList.Count; i++) //{ // var tem = pidList[i].Split('_')[pidList[i].Split('_').Length - 1]; // pidList2.Add(tem); // dicpid[tem] = pidList[i]; //} List detectResults = ML?.RunMLDetectionSync(imgSet, pidList, measureBind.DetectionId); List ngResults = new List(); //for (int i = 0; i < detectResults.Count; i++) //{ // detectResults[i].PID = dicpid[detectResults[i].PID]; //} detectResults.GroupBy(u => u.PID).ToList().ForEach(u => { if (u.ToList().Count > 0 && u.ToList().Any(m => m.ResultState != EnumHelper.ResultState.OK)) { if (u.ToList().GetDefectDescList().Count == 0) { var errorSpec = _errorSpec.Copy(); errorSpec.Code = "检测TBD"; errorSpec.ActualValue = -999; DetectResult ngResult = new DetectResult() { Specs = new List() { errorSpec }, PID = u.Key }; ngResults.Add(ngResult); } } }); detectResults.AddRange(ngResults); resultList.AddRange(detectResults); //detectResults[0].ActionForAllNetResults(n => //{ // if (n.DetectDetails.Count == 0) // { // string data = $"{n.DetectTime.ToString("HH:mm:ss.fff")},{pid},,,,{detectResult.DetectionName},{n.IsAbandoned},{n.NetName},{set.ImageIndex},OK,OK,,,,,,,,"; // CSVHelper.CSVOutputAsync(csvpartfilename, data, Part_CSV_Head); // } // else // { // n.DetectDetails.ForEach(d => // { // string data = $"{n.DetectTime.ToString("HH:mm:ss.fff")},{pid},{d.Id},{string.Join("|", d.ParentIds)},{d.Remark},{detectResult.DetectionName},{d.IsAbandoned},{n.NetName},{set.ImageIndex},{d.FinalResult},{d.DetectResult},{d.ClassName},{(d.Rect.Width * d.PixelSize).ToString("f4")},{(d.Rect.Height * d.PixelSize).ToString("f4")},{d.Probability},{d.Uncertainty},{d.Area},{d.AreaInCrop},{d.AreaInActual.ToString("f4")},{d.Rect.X.ToString("f4")},{d.Rect.Y.ToString("f4")}"; // CSVHelper.CSVOutputAsync(csvpartfilename, data, Part_CSV_Head); // }); // } //}); } RunCustomizedMethod(products, triggerText, triggerSource, imgSet, measureBind.CustomizedMonitorId, resultList); RunCustomizedMethod(products, triggerText, triggerSource, imgSet, measureBind.CustomizedCombineMethodId, resultList); } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{measureBind.WorkPosition}检测过程异常,{ex.ToString()}"); var errorSpec = _errorSpec.Copy(); errorSpec.ActualValue = -999; products.ForEach(p => { p.AddNewDetectResults(M141Config.StationCode, measureBind.WorkPosition, new List() { new DetectResult() { Specs = new List() { errorSpec }, PID = p.PID, } }); }); } finally { try { if (resultList.Count > 0) { products.ForEach(p => { var pResults = resultList.Where(u => u.PID == p.PID).ToList(); p.AddNewDetectResults(M141Config.StationCode, measureBind.WorkPosition, pResults); LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}添加工位{measureBind.WorkPosition}检测结果,数量{pResults.Count}"); }); } products.ForEach(p => { if (p.PositoinCheckDone(measureBind.WorkPosition, measureBind.CheckIndex, out string msg)) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}工位{measureBind.WorkPosition}的第{measureBind.CheckIndex}检测完成,该工位检测全部结束"); } else { LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}工位{measureBind.WorkPosition}的第{measureBind.CheckIndex}检测完成,{msg}"); } }); if (resultList.Any(u => u.ResultState != EnumHelper.ResultState.OK)) { if (!products[0].SEQUENCE.ToLower().Contains("test")) { SaveZipPreparation(string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}", imgSet, measureBind.WorkPosition); } if (measureBind.NGImageSwitch) { if (string.IsNullOrWhiteSpace(M141Config.NGImageFolder)) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"未配置NG图片保存目录"); } else { string folder = Path.Combine(M141Config.NGImageFolder, DateTime.Now.ToString("yyyyMMdd"), measureBind.WorkPosition, "NG"); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } string id = string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}"; string post = ""; if (ImageSet.ImageFormatPostDict.ContainsKey(M141Config.ImageFormatNG)) { post = ImageSet.ImageFormatPostDict[M141Config.ImageFormatNG]; } else { post = M141Config.ImageFormatNG.ToString().ToLower(); } string ngImageFile = Path.Combine(folder, $"{id}.{post}"); var bitmap = imgSet.HImage.ConvertHImageToBitmap(); bitmap.Save(ngImageFile, M141Config.ImageFormatNG); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}NG图片已保存"); bitmap.Dispose(); } } } else { if (!products[0].SEQUENCE.ToLower().Contains("test")) { SaveZipPreparation(string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}", imgSet, measureBind.WorkPosition); } if (measureBind.OKImageSwitch) { if (string.IsNullOrWhiteSpace(M141Config.NGImageFolder)) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"未配置NG图片保存目录"); } else { string folder = Path.Combine(M141Config.NGImageFolder, DateTime.Now.ToString("yyyyMMdd"), measureBind.WorkPosition, "OK"); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } string id = string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}"; string post = ""; if (ImageSet.ImageFormatPostDict.ContainsKey(M141Config.ImageFormatOK)) { post = ImageSet.ImageFormatPostDict[M141Config.ImageFormatOK]; } else { post = M141Config.ImageFormatOK.ToString().ToLower(); } string ngImageFile = Path.Combine(folder, $"{id}.{post}"); var bitmap = imgSet.HImage.ConvertHImageToBitmap(); bitmap.Save(ngImageFile, M141Config.ImageFormatOK); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}OK图片已保存"); bitmap.Dispose(); } } } } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"{measureBind.WorkPosition},产品{string.Join(",", products.Select(u => u.PID))}的NG图片保存异常,{ex.GetExceptionMessage()}"); } LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"图片{imgSet.PID}开始释放"); imgSet.HImage?.Dispose(); imgSet.HImage = null; imgSet.Dispose(); imgSet = null; LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"图片已释放"); } }); } private void RunCustomizedMethod(List products, string triggerText, string triggerSource, IImageSet imgSet, string methodId, List resultList) { try { if (!string.IsNullOrWhiteSpace(methodId)) { var monitorSet = Config.GetAllMonitorSet().FirstOrDefault(u => u.Id == methodId); if (monitorSet.OpConfig is IImageCheckOperationConfig iConfig) { var opConfig = iConfig.Clone(); opConfig.Products = new List(products); opConfig.ImageSet = imgSet; opConfig.TriggerStr = triggerText; opConfig.TriggerSource = triggerSource; opConfig.ExecuteDevice = iConfig.ExecuteDevice; //LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"图片id,{imgSet.id}"); var res = RunSelectedMonitorSetByManual(methodId, opConfig); if (res.DataObj is List dr) { dr.ForEach(r => { r.IsPreTreatDone = r.IsNetCheckDone = r.IsAfterTreatDone = true; r.SetResult(); }); resultList.AddRange(dr); } if (res.Result != 1) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"自定义检测过程异常,{res.Message}"); } } } } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"自定义检测过程异常,{ex.GetExceptionMessage()}"); } } public void SaveZipPreparation(string id, IImageSet imgSet, string workstation) { try { if (M141Config.SaveStateZip) { if (M141Config.PositionZip.Any(u => u.WorkPosition == workstation)) { if (M141Config.SaveTwoPathZip) { if (!string.IsNullOrEmpty(M141Config.SavePathZip) || !string.IsNullOrEmpty(M141Config.SavePathZip2)) { if (string.IsNullOrEmpty(M141Config.CurrPathZip)) { M141Config.CurrPathZip = M141Config.SavePathZip; } if (M141Config.CurrPathZip != M141Config.SavePathZip && M141Config.CurrPathZip != M141Config.SavePathZip2) { M141Config.CurrPathZip = M141Config.SavePathZip; } DriveInfo driveInfo3 = DriveInfo.GetDrives().First(d => M141Config.CurrPathZip.StartsWith(d.Name)); double freespace3 = (double)driveInfo3.AvailableFreeSpace / (double)driveInfo3.TotalSize * 100; if (freespace3 < M141Config.SaveMinPercentZip) { DriveInfo driveInfo1 = DriveInfo.GetDrives().First(d => M141Config.SavePathZip.StartsWith(d.Name)); double freespace1 = (double)driveInfo1.AvailableFreeSpace / (double)driveInfo1.TotalSize * 100; DriveInfo driveInfo2 = DriveInfo.GetDrives().First(d => M141Config.SavePathZip2.StartsWith(d.Name)); double freespace2 = (double)driveInfo2.AvailableFreeSpace / (double)driveInfo2.TotalSize * 100; if (freespace1 > M141Config.SaveMinPercentZip) { M141Config.CurrPathZip = M141Config.SavePathZip; SaveProcessConfig(M141Config); } else if (freespace2 > M141Config.SaveMinPercentZip) { M141Config.CurrPathZip = M141Config.SavePathZip2; SaveProcessConfig(M141Config); } else { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"双磁盘都达到存储极限,不再保存压缩图片"); return; } } string folder = Path.Combine(M141Config.CurrPathZip, DateTime.Now.ToString("yyyyMMdd"), workstation); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } string post = ""; if (ImageSet.ImageFormatPostDict.ContainsKey(M141Config.ImageFormatZip)) { post = ImageSet.ImageFormatPostDict[M141Config.ImageFormatZip]; } else { post = M141Config.ImageFormatZip.ToString().ToLower(); } HImage zoomimage; if ((int)M141Config.SavezipZip != 10) { //// 调用zoom_image_factor算子 HOperatorSet.ZoomImageFactor(imgSet.HImage, out HObject zoomHob, ((double)M141Config.SavezipZip) / 10, ((double)M141Config.SavezipZip) / 10, "constant"); zoomimage = zoomHob.ConvertHObjectToHImage(); } else { zoomimage = imgSet.HImage; } //string ngImageFile = Path.Combine(folder, $"{id}.{post}"); //var bitmap = zoomimage.ConvertHImageToBitmap(); //bitmap.Save(ngImageFile, M141Config.ImageFormatZip); //LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}压缩图片已保存"); //zoomimage.Dispose(); //bitmap.Dispose(); lock (ZipImages) { ZipImages.Add(new ZipImage { path = folder, name = id, post = post, image = zoomimage, }); } } else { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"压缩图片保存双路径为空"); } } else { if (!string.IsNullOrEmpty(M141Config.SavePathZip)) { string folder = Path.Combine(M141Config.SavePathZip, DateTime.Now.ToString("yyyyMMdd"), workstation); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } string post = ""; if (ImageSet.ImageFormatPostDict.ContainsKey(M141Config.ImageFormatZip)) { post = ImageSet.ImageFormatPostDict[M141Config.ImageFormatZip]; } else { post = M141Config.ImageFormatZip.ToString().ToLower(); } //// 调用zoom_image_factor算子 HOperatorSet.ZoomImageFactor(imgSet.HImage, out HObject zoomHob, ((double)M141Config.SavezipZip) / 10, ((double)M141Config.SavezipZip) / 10, "constant"); HImage zoomimage = zoomHob.ConvertHObjectToHImage(); //string ngImageFile = Path.Combine(folder, $"{id}_{Result}.{post}"); //var bitmap = zoomimage.ConvertHImageToBitmap(); //bitmap.Save(ngImageFile, M141Config.ImageFormatZip); //LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}压缩图片已保存"); //zoomimage.Dispose(); lock (ZipImages) { ZipImages.Add(new ZipImage { path = folder, name = id, post = post, image = zoomimage, }); } } else { LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"压缩图片保存路径为空"); } } } } } catch (Exception e) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"压缩图片整理异常{e.ToString()}"); } } #region plc public ResponseMessage RunImageCheck_plc(IOperationConfig config, int plcnum) { ResponseMessage msg = new ResponseMessage(); msg.Result = 1; List measureBinds = new List(); string inputSequence = ""; var triggerDatas = config.TriggerStr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); try { RunImageCheckPreTreat_plc(config, out measureBinds, out inputSequence); } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测预处理异常,{ex.GetExceptionMessage()}"); msg.Result = -1; msg.Message = ex.Message; return msg; } List cameraIds = measureBinds.Select(u => u.CameraId).ToList(); try { ConcurrentDictionary imgSetDicts = new ConcurrentDictionary(); measureBinds.AsParallel().ForAll(b => { var camera = DeviceCollection.FirstOrDefault(u => u.Id == b.CameraId) as CameraBase; if (camera == null) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测配置{b.GetDisplayText()}未能获取相机设备"); imgSetDicts[b] = null; return; } imgSetDicts[b] = null; try { imgSetDicts[b] = CollectHImage(camera, b.SnapshotOpConfig); } catch (Exception ea) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{measureBinds[0].WorkPosition}的第{measureBinds[0].CheckIndex}检测获取图像信息异常 {ea.ToString()}"); } var pList = b.ProductIndices.Select(pi => { string pid = $"{inputSequence}_{pi}"; return FindProductBySequence(pid, true); }).ToList(); RunImageCheckAsync(pList, config.TriggerStr, config.TriggerSource, imgSetDicts[b], b); }); } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测处理异常,{ex.GetExceptionMessage()}"); msg.Result = -1; msg.Message = ex.Message; return msg; } CheckPositionDoneAsync_plc(measureBinds[0].WorkPosition, inputSequence, config, cameraIds, plcnum); return msg; } public void RunImageCheckPreTreat_plc(IOperationConfig config, out List measureBinds, out string inputSequence) { Task.Run(() => { SetProcessRunState(EnumHelper.RunState.Running); }); measureBinds = new List(); inputSequence = ""; var triggerDatas = config.TriggerStr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (triggerDatas.Length < 2) { throw new ProcessException($"触发文本{config.TriggerStr}解析失败,数据长度小于2"); } string positionValue = triggerDatas[0]; int checkIndex = -1; if (!int.TryParse(triggerDatas[1].Replace("Scan", ""), out checkIndex)) { throw new ProcessException($"触发文本{config.TriggerStr}解析失败,未能获取检测序号"); } var positionSet = M141Config.WorkPositionCollection.Where(u => u.IsEnabled).FirstOrDefault(u => u.TriggerValue == positionValue); if (positionSet == null) { throw new ProcessException($"触发文本{config.TriggerStr}未能获取{positionValue}对应的可用工位信息"); } measureBinds = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == positionSet.PositionName && u.CheckIndex == checkIndex).ToList(); if (measureBinds.Count == 0) { throw new ProcessException($"未能获取工位{positionSet.PositionName}的第{checkIndex}检测配置信息"); } measureBinds.Select(u => u.CameraId).ToList().ForEach(c => { var camera = DeviceCollection.FirstOrDefault(u => u.Id == c) as CameraBase; if (camera != null) { camera.ClearImageBufferQueue(); LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"相机{camera.Name}检测前清理缓存完成"); } }); inputSequence = triggerDatas[triggerDatas.Length - 1]; string tempPID = inputSequence; string pidstr = DateTime.Now.ToString("yyyyMMddHHmmssfff"); measureBinds.Where(b => b.IsFirstPosition).ToList().ForEach(b => { b.ProductIndices.ForEach(i => { ProductModel p = new ProductModel(); p.SEQUENCE = $"{tempPID}_{i}"; p.PID = $"{pidstr}T_{i}"; p.Initial(M141Config.StationCode, M141Config.WorkPositionCollection.Select(u => u.PositionName).ToList()); NewProductIntoList(p, true); }); }); int de = 0; measureBinds.Where(b => (b.CheckIndex == de || b.CheckIndex == 1) && b.ImageIndex == 0).AsParallel().ForAll(b => { List temint = new List(); temint = new List() { 1, 2, 3 }; temint.ForEach(i => { string sequence = $"{tempPID}_{i}"; var p = FindProductBySequence(sequence, b.IsEnabelQueryFromQueue); //初始化产品的检测次数 var checkIndexList = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == b.WorkPosition && u.ProductIndices.Contains(i)).Select(u => u.CheckIndex).OrderBy(u => u).ToList(); p.InitialPositionCheckList(b.WorkPosition, checkIndexList); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"产品{p.PID}_{p.SEQUENCE}已清理{b.WorkPosition}检测数据。当前已完成工位{string.Join(",", p.Details.Select(u => u.PositionName))}"); }); //初始化工位的检测次数 var positionCheckTimes = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == b.WorkPosition).Select(u => u.CheckIndex).ToList(); lock (_positionCheckTimeLock) { _positionCheckTimeDict[b.WorkPosition] = positionCheckTimes; LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{b.WorkPosition}初始化检测次数:{string.Join(",", positionCheckTimes)}"); } }); measureBinds.AsParallel().ForAll(b => { lock (_positionCheckTimeLock) { _positionCheckTimeDict[b.WorkPosition].RemoveAll(u => u == b.CheckIndex); LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{b.WorkPosition}开始第{b.CheckIndex}次检测,待检测序号:{string.Join(",", _positionCheckTimeDict[b.WorkPosition])}"); } }); } public async Task> CheckPositionDoneAsync_plc(string positionName, string inputSequence, IOperationConfig config, List cameraIds, int plcnum) { string triggerSource = config.TriggerSource; return await _taskFactory.StartNew(() => { try { string index = config.TriggerStr.Split(',')[1]; var positionSet = M141Config.WorkPositionCollection.FirstOrDefault(u => u.PositionName == positionName); var checkRemains = _positionCheckTimeDict[positionName]; var pIndices = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == positionName).SelectMany(u => u.ProductIndices).Distinct().OrderBy(u => u).ToList(); pIndices = new List { 1, 2, 3 }; var pList = pIndices.Select(u => { string sequence = $"{inputSequence}_{u}"; return FindProductBySequence(sequence, true); }).ToList(); List plcresult = new List(); if (pList.Any(u => u == null)) { plcresult = new List() { false, false, false }; LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"获取工位{positionName}汇总结果时产品信息为空"); } else { int waitInterval = 20; int repeatTime = M141Config.DetectTimeout / waitInterval; do { if (!pList.All(p => { p.GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail); return detail?.IsDone ?? false; })) { Thread.Sleep(waitInterval); repeatTime--; } else { //Thread.Sleep(50); LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"成功完成工位{positionName}产品{string.Join(",", pList.Select(u => $"{u.PID}_{u.SEQUENCE}"))}检测"); break; } if (repeatTime < 0) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{positionName}产品{string.Join(",", pList.Select(u => $"{u.PID}_{u.SEQUENCE}"))}检测获取结果超时"); break; } } while (true); } pList.ForEach(p => { var isOK = p.GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail); plcresult.Add(isOK); //List specHeads = new List(); //string head = p.GetCSVHead(ref specHeads, positionName); //if (!_positionSpecHeads.ContainsKey(positionName)) //{ // _positionSpecHeads[positionName] = specHeads; //} //string data = p.GetCSVData(_positionSpecHeads[positionName], positionName); //CSVRecordAsync($"{positionName}_Record_{DateTime.Now.ToString("yyyyMMdd")}.csv", data, head); ////UpdatePositionResultToDB(detail); //var seqData = p.SEQUENCE.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries).ToList(); //UpdatePositionResultDisplay(detail, isOK, positionName, seqData[seqData.Count - 1]); //if (IsInspectionDoing) //{ // OnSinglePostionDetectResultUpdate.Invoke(positionName, detail, seqData[seqData.Count - 1]); //} if (positionSet.IsLastPosition) { UpdateProductResultAsync(p); //UpdateOverAllProductResultToUI(p, isOK); //OnNewProductEnqueued?.Invoke(p); //OnProductDequeued?.Invoke(p); CheckContinuousNGAlarmAsync(p); } //SetSpecResult(p); }); ReplyPlcData(plcresult, plcnum); if (positionSet.IsLastPosition) { if (_ct != null) { UpdateCT(null, (float)((DateTime.Now - _ct.Value).TotalSeconds) / 3); } _ct = DateTime.Now; } //ReplyPlcData(positionName, config.TriggerValue); //cameraIds.ForEach(c => //{ // var camera = DeviceCollection.FirstOrDefault(u => u.Id == c) as CameraBase; // if (camera != null) // { // camera.ClearImageBufferQueue(); // LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"相机{camera.Name}清理缓存"); // } //}); return pList; } catch (Exception ex) { LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, ex.ToString()); return null; } }); } public virtual void ReplyPlcData(List result, int plcnum) { } #endregion public void wirtePLC(int add, int value) { Plc1?.WriteSingleAddress(add, value, out _); } } public class ZipImage { public string path { set; get; } public string name { set; get; } public string post { set; get; } public HImage image { set; get; } } public class OKNGImage { public string pid { set; get; } public string path { set; get; } public string name { set; get; } public string post { set; get; } public string result { set; get; } public Bitmap bitmap { set; get; } public ImageFormat ImageFormat { set; get; } public bool issave { set; get; } } }