| | |
| | | using Bro.Common.Helper; |
| | | 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 |
| | |
| | | get => IConfig as M071Config; |
| | | } |
| | | #endregion |
| | | |
| | | #region 事件 |
| | | public event Action OnMeasureStart; |
| | | public event Action OnClearBarcode; |
| | | public event Action<IShapeElement> OnElementUpdated; |
| | | #endregion |
| | | |
| | | public override void Open() |
| | | { |
| | | InitialSetting(); |
| | | |
| | | base.Open(); |
| | | |
| | | CheckMachineState(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 检查设备状态 |
| | | /// </summary> |
| | | private void CheckMachineState() |
| | | { |
| | | //throw new NotImplementedException(); |
| | | } |
| | | |
| | | 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<string>(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.KeyResultId == "All") |
| | | { |
| | | keyRespone.SelectMany(kr => kr.KeyResultList).ToList().ForEach(r => |
| | | { |
| | | b.MeasureValueDict[r] = null; |
| | | }); |
| | | } |
| | | else |
| | | { |
| | | b.MeasureValueDict[b.KeyResultId] = 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 |
| | | |
| | | public string BarCode { get; set; } |
| | | |
| | | List<ProductionMeasurement> productionList = new List<ProductionMeasurement>(); |
| | | |
| | | [ProcessMethod("", "StartJob", "开始扫描", InvokeType.TestInvoke)] |
| | | public ProcessResponse StartJob(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) |
| | | { |
| | | if (string.IsNullOrWhiteSpace(BarCode)) |
| | | { |
| | | OnClearBarcode?.Invoke(); |
| | | throw new ProcessException("未输入产品条码,请勿开始测量"); |
| | | } |
| | | |
| | | 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.MotionOp.Device); |
| | | if (device == null) |
| | | throw new ProcessException($"{s.Name}拍照点位未设置运动设备"); |
| | | |
| | | IMotionCard motionDevice = device as IMotionCard; |
| | | |
| | | if (motionDevice == null) |
| | | throw new ProcessException($"{s.Name}拍照点位设置{device.Name}不是运动设备"); |
| | | |
| | | var response = motionDevice.Run(s.MotionOp.OpConfig); |
| | | if (!response.Result) |
| | | { |
| | | throw new ProcessException($"{device.Name}异常,{response.Message}", 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); |
| | | } |
| | | |
| | | #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<MeasurementUint> 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<string, double> 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 |
| | | } |
| | | } |