using Bro.Common.Base; using Bro.Common.Helper; using Bro.Common.Interface; using Bro.Common.Model; using Bro.Process; using HalconDotNet; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Bro.M071.Process { [Process("M071", EnumHelper.DeviceAttributeType.Device)] public partial class M071Process : ProcessControl { #region 构造函数 public M071Process() : base() { } public M071Process(string productionCode) : base(productionCode) { } #endregion #region 配置 M071Config Config { get => IConfig as M071Config; } #endregion #region 事件 public event Action OnMeasureStart; public event Action OnBarcodeChanged; public event Action OnElementUpdated; #endregion public override void Open() { InitialSetting(); base.Open(); } private void InitialSetting() { Config.SnapshotPointCollection.ForEach(u => { u.GetHalconToolPathList().ForEach(path => { LoadHalconTool(path, u.Id); }); }); Config.KeyUnitCollection.ForEach(u => { if (!u.IsEnabled) return; var snapshotPoint = Config.SnapshotPointCollection.FirstOrDefault(s => s.Id == u.SnapshotPointId && s.IsEnabled); if (snapshotPoint == null) throw new ProcessException($"{u.AlignName}未设置可用拍照点位"); if (u.ImageSeq < 1) throw new ProcessException($"{u.AlignName}图片序号小于1"); var algo = Config.KeyAlgorithemCollection.FirstOrDefault(a => a.Id == u.KeyAlgorithemId); if (algo == null) throw new ProcessException($"{u.AlignName}未设置检测算法"); u.KeyAlgorithemPath = algo.AlgorithemPath; LoadHalconTool(u.KeyAlgorithemPath, u.AlignName); var resultSet = Config.KeyResultCollection.FirstOrDefault(r => r.Id == u.KeyResultId); if (resultSet == null) throw new ProcessException($"{u.AlignName}未设置检测结果配置"); u.KeyResultList = new List(resultSet.Results); }); Config.MeasurementUnitCollection.ForEach(u => { if (!u.IsEnabled) return; var spec = Config.MeasureTypeCollection.FirstOrDefault(s => s.Code == u.MeasureType); if (spec == null) throw new ProcessException($"{u.GetDisplayText()}未设置检测类型"); u.Spec = new MeasureType(); u.Spec.DataFrom(spec); LoadHalconTool(u.Spec.AlgorithemPath, u.Id); u.KeyUnitCollection.ForEach(b => { var keyRespone = Config.KeyUnitCollection.Where(ku => ku.IsEnabled && ku.Key == b.Key).ToList(); if (keyRespone.Count == 0) throw new ProcessException($"{u.GetDisplayText()}对应的单键不存在或不可用"); if (b.KeyResult == "All") { keyRespone.SelectMany(kr => kr.KeyResultList).ToList().ForEach(r => { b.MeasureValueDict[r] = null; }); } else { b.MeasureValueDict[b.KeyResult] = null; } }); }); } #region InitialHalconTool //protected override void InitialHalconTool() //{ // base.InitialHalconTool(); // Config.SnapshotPointCollection.ForEach(u => // { // u.GetHalconToolPathList().ForEach(path => // { // if (!string.IsNullOrWhiteSpace(path)) // { // string directoryPath = Path.GetDirectoryName(path); // string fileName = Path.GetFileNameWithoutExtension(path); // HDevEngineTool tool = new HDevEngineTool(directoryPath); // tool.LoadProcedure(fileName); // //使用“|”作为间隔符 // _halconToolDict[u.Id + "|" + path] = tool; // } // }); // }); //} #endregion private string barCode = ""; public string BarCode { get => barCode; set { if (barCode != value) { barCode = value; OnBarcodeChanged?.Invoke(value); } } } List productionList = new List(); [ProcessMethod("", "StartJob", "开始扫描", InvokeType.TestInvoke)] public ProcessResponse StartJob(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) { if (string.IsNullOrWhiteSpace(BarCode)) { throw new ProcessException("未输入产品条码,请勿开始测量"); } //检查产品放置OK //气缸推动压板移动到产品上方 //压板压紧产品 OnMeasureStart?.BeginInvoke(null, null); var measurements = Config.MeasurementUnitCollection.Where(u => u.IsEnabled).ToList().DeepSerializeClone(); measurements.ForEach(m => { m.InitialKeyUnitMeasureChanged(); }); var pMeasure = new ProductionMeasurement() { Barcode = BarCode, Measurements = measurements, }; var existedProduction = productionList.FirstOrDefault(u => u.Barcode == pMeasure.Barcode); if (existedProduction != null) { productionList.Remove(existedProduction); existedProduction.Dispose(); existedProduction = null; } productionList.Add(pMeasure); pMeasure.InitialMeasurementsPropertyChanged(); pMeasure.PropertyChanged += MeasureProduction_PropertyChanged; Config.SnapshotPointCollection.Where(u => u.IsEnabled).ToList().ForEach(s => { _pauseHandle.WaitHandle.WaitOne(); IDevice device = DeviceCollection.FirstOrDefault(u => u.Id == s.MotionDevice); if (device == null) throw new ProcessException($"{s.Name}拍照点位未设置运动设备"); IMotion motionDevice = device as IMotion; if (motionDevice == null) throw new ProcessException($"{s.Name}拍照点位设置{device.Name}不是运动设备"); if (!motionDevice.MoveToPoint(null)) { throw new ProcessException("运动中止", null, ExceptionLevel.Info); } CameraBase camera = DeviceCollection.FirstOrDefault(u => u.Id == s.CameraOp.Device) as CameraBase; if (camera == null) return; HImage hImage = CollectHImage(camera, s.CameraOp.OpConfig, out string imgSetId); if (string.IsNullOrWhiteSpace(imgSetId)) { return; } RunImageHandle(camera, s.CameraOp.OpConfig, hImage, s.Id, s.Name, pMeasure.Measurements); }); BarCode = ""; return new ProcessResponse(true); } /// /// 暂停标志 /// WaitHandle 暂停句柄 默认为非阻塞 可执行 /// WaitResult 暂停标志 true 正常执行 false 暂停中 /// ManualWaitConfirm _pauseHandle = new ManualWaitConfirm() { WaitHandle = new ManualResetEvent(true), WaitResult = true, }; [ProcessMethod("", "PauseJob", "暂停流程", InvokeType.TestInvoke)] public ProcessResponse PauseJob(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) { if (_pauseHandle.WaitResult) { #region 板卡暂停动作 #endregion _pauseHandle.WaitHandle.Reset(); } else { #region 板卡恢复动作 #endregion _pauseHandle.WaitHandle.Set(); } _pauseHandle.WaitResult = !_pauseHandle.WaitResult; return new ProcessResponse(_pauseHandle.WaitResult); } #region 私有方法 private void MeasureProduction_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (sender is ProductionMeasurement pMeasure) { lock (pMeasure) { //检查是否全部完成 pMeasure.Measurements.ForEach(m => { if (m.KeyUnitCollection.All(k => k.IsDone != null)) { if (!m.IsUpdated) { if (m.KeyUnitCollection.Any(k => k.IsDone == false)) { m.Spec.ActualValue = -999; } else { string toolKey = m.Id + "|" + m.Spec.AlgorithemPath; if (!_halconToolDict.ContainsKey(toolKey)) { LogAsync(DateTime.Now, $"{m.GetDisplayText()}{m.Spec.Code}算法未初始化", ""); m.Spec.ActualValue = -999; } else { var array = m.KeyUnitCollection.SelectMany(u => u.MeasureValueDict.Values.ToList().ConvertAll(v => v ?? -999)).ToArray(); _halconToolDict[toolKey].InputTupleDic["INPUT_Params"] = new HTuple(array); if (!_halconToolDict[toolKey].RunProcedure(out string error)) { LogAsync(DateTime.Now, $"{m.GetDisplayText()}{m.Spec.Code}算法异常,{error}", ""); m.Spec.ActualValue = -999; } else { m.Spec.ActualValue = _halconToolDict[toolKey].GetResultTuple("OUTPUT_Result").D; LogAsync(DateTime.Now, $"{m.GetDisplayText()}数据{m.Spec.ActualValue},结果{(m.Spec.MeasureResult == null ? "TBD" : (m.Spec.MeasureResult == true ? "OK" : "NG"))}", ""); } } } LogAsync(DateTime.Now, $"{m.GetDisplayText()}检测结果", $"{((m.Spec.MeasureResult ?? false) ? "OK" : "NG")}"); IShapeElement indicator = null; pMeasure.ElementList.Add(indicator); //输出图形基元到界面 todo OnElementUpdated?.BeginInvoke(indicator, null, null); SaveKeyImages(pMeasure.Barcode, m); m.IsUpdated = true; } } }); if (!pMeasure.Measurements.All(m => m.IsUpdated)) { return; } //MES输出 todo //Excel报表输出 todo //数据库保存 todo SaveWholeImage(pMeasure); productionList.RemoveAll(p => p.Barcode == pMeasure.Barcode); pMeasure.Dispose(); } } } #region 图像保存 private void SaveWholeImage(ProductionMeasurement pMeasure) { try { Bitmap backImage = (Bitmap)Bitmap.FromFile(Config.BackgroundImagePath); Bitmap map = new Bitmap(backImage.Width, backImage.Height); using (Graphics g = Graphics.FromImage(map)) { g.DrawImage(backImage, new PointF(0, 0)); pMeasure.ElementList.ForEach(e => { e.Draw(g); }); } string dir = Path.Combine(Config.ImageSaveFolder, "TopView", DateTime.Now.ToString("yyyyMMdd")); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } map.Save(Path.Combine(dir, $"{pMeasure.Barcode}_{DateTime.Now.ToString("HHmmss")}.bmp")); } catch (Exception ex) { LogAsync(DateTime.Now, "整体图片保存异常", ex.GetExceptionMessage()); } } private void SaveKeyImages(string barCode, MeasurementUint measureUnit) { string measureName = measureUnit.GetDisplayText(); if (Config.ImageSaveOption.IsSaveOriginImage) { measureUnit.KeyUnitCollection.ForEach(u => u.ImageSaveStatus++); string dir = Path.Combine(Config.ImageSaveFolder, "Origin", DateTime.Now.ToString("yyyyMMdd"), barCode, measureUnit.MeasureType); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } SaveKeyImages(measureUnit, measureName, dir); } string result = (measureUnit.Spec.MeasureResult ?? false) ? "OK" : "NG"; if (Config.ImageSaveOption.AddtionalSaveType.ToUpper().Contains(result)) { measureUnit.KeyUnitCollection.ForEach(u => u.ImageSaveStatus++); string dir = Path.Combine(Config.ImageSaveFolder, result, DateTime.Now.ToString("yyyyMMdd"), barCode, measureUnit.MeasureType); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } SaveKeyImages(measureUnit, measureName, dir); } } private async void SaveKeyImages(MeasurementUint measureUnit, string measureName, string dir) { await Task.Run(() => { measureUnit.KeyUnitCollection.ForEach(u => { int i = 0; u.KeyImages?.ForEach(image => { string fileName = Path.Combine(dir, $"{measureName}_{u.Key}{(i == 0 ? "" : $"-{i}")}_{DateTime.Now.ToString("HHmmss")}.tiff"); image.WriteImage("tiff", 0, fileName); i++; }); u.ImageSaveStatus--; }); }); } #endregion private async void RunImageHandle(CameraBase camera, IOperationConfig opConfig, HImage hImage, string snapshotId, string snapshotName, List measureList) { await Task.Run(() => { var keys = Config.KeyUnitCollection.Where(u => u.IsEnabled && u.SnapshotPointId == snapshotId); var keyBindCollection = measureList.SelectMany(u => u.KeyUnitCollection).Where(u => keys.Any(k => k.Key == u.Key)).ToList(); string toolKey = (opConfig as CameraOprerationConfigBase).AlgorithemPath; HObject images = hImage; if (!string.IsNullOrWhiteSpace(toolKey)) { toolKey = snapshotId + "|" + toolKey; if (!_halconToolDict.ContainsKey(toolKey)) { LogAsync(DateTime.Now, $"{snapshotName}未初始化取图算法配置", ""); keyBindCollection.ForEach(k => k.FillKeyValues(null)); return; } _halconToolDict[toolKey].InputImageDic["INPUT_Image"] = hImage; if (!_halconToolDict[toolKey].RunProcedure(out string error)) { LogAsync(DateTime.Now, $"{snapshotName}取图算法异常,{error}", ""); keyBindCollection.ForEach(k => k.FillKeyValues(null)); return; } images = _halconToolDict[toolKey].GetResultObject("OUTPUT_Images"); } HOperatorSet.CountObj(images, out HTuple count); if (count == 0) { LogAsync(DateTime.Now, $"{snapshotName}取图算法未输出图像", ""); keyBindCollection.ForEach(k => k.FillKeyValues(null)); return; } var excludeKeys = keys.Where(u => u.ImageSeq > count).ToList(); if (excludeKeys.Count > 0) { LogAsync(DateTime.Now, $"{string.Join(" ", excludeKeys.Select(u => u.AlignName))}未在图片获取序列中", ""); keyBindCollection.Where(k => excludeKeys.Any(u => u.Key == k.Key)).ToList().ForEach(k => { k.FillKeyValues(null); }); } Parallel.For(1, count.I, (i) => { HOperatorSet.SelectObj(images, out HObject image, i); keys.Where(u => u.ImageSeq == i).ToList().ForEach(k => { Dictionary resultDict = null; var keyBindList = keyBindCollection.Where(u => u.Key == k.Key).ToList(); string keyToolKey = k.AlignName + "|" + k.KeyAlgorithemPath; if (!_halconToolDict.ContainsKey(keyToolKey)) { LogAsync(DateTime.Now, $"{k.AlignName}检测算法未初始化", ""); } else { _halconToolDict[keyToolKey].InputImageDic["INPUT_Image"] = image; if (!_halconToolDict[keyToolKey].RunProcedure(out string error)) { LogAsync(DateTime.Now, $"{k.AlignName}检测算法异常,{error}", ""); } else { var results = _halconToolDict[keyToolKey].GetResultTuple("OUTPUT_Results").HTupleToDouble(); if (results.Count == 0 || results.Any(u => u < 0)) { LogAsync(DateTime.Now, $"{k.AlignName}检测结果异常", ""); } else { resultDict = k.KeyResultList.ToDictionary(u => u, u => { int index = k.KeyResultList.IndexOf(u); return results[index]; }); } } } keyBindList.ForEach(kb => { kb.KeyImages.Add(image.Clone() as HImage); kb.FillKeyValues(resultDict); }); }); image.Dispose(); }); if (count.I != 1) { hImage?.Dispose(); hImage = null; } }); } #endregion } }