using HalconDotNet; using LB_VisionProcesses.Cameras; using LB_VisionProcesses.Communicators; using LB_VisionFlowNode; using LB_VisionProcesses; using LB_VisionProcesses.Alogrithms; using LB_VisionProcesses.Processes; using LB_SmartVision.Forms.Pages.SettingPage; using OpenCvSharp; using System.Collections.Concurrent; namespace LB_SmartVision.ProcessRun { public class ProcessContext : IFlowContext { /// /// 通讯集合(Key:通讯名,Value:通讯句柄) /// public ObservableConcurrentDictionary dicCommunicators { get; set; } /// /// 相机集合(Key:相机SN,Value:相机句柄) /// public ObservableConcurrentDictionary dicCameras { get; set; } public ConcurrentDictionary>> dicInputsMapping { get; set; } public ConcurrentDictionary> dicOutputsMapping { get; set; } /// /// 运行流程 /// public ConcurrentDictionary dicContext = new ConcurrentDictionary(); /// /// 运行标记 /// public bool bRuning = false; /// /// 运行完成 /// public bool bCompleted = true; /// /// 运行结果 /// public bool Result = false; /// /// 运行消息 /// public string Msg = string.Empty; /// /// 运行时间 /// public double RunTime = 0; /// /// 开始时间 /// public DateTime StartTime = DateTime.Now; private HTuple ho_ImageWidth = new HTuple(); private HTuple ho_ImageHeight = new HTuple(); /// /// 用于绘制结果图的窗口控件 /// private HWindowControl hWindowControl = new HWindowControl(); public ProcessContext(ObservableConcurrentDictionary dicCameras, ObservableConcurrentDictionary dicCommunicators , ConcurrentDictionary>> dicInputsMapping, ConcurrentDictionary> dicOutputsMapping) { this.dicCameras = dicCameras; this.dicCommunicators = dicCommunicators; this.dicInputsMapping = dicInputsMapping; this.dicOutputsMapping = dicOutputsMapping; hWindowControl.Size = new System.Drawing.Size(1920, 1080); TAlgorithm.set_display_font(hWindowControl.HalconWindow, 1080 / 20, "mono", "true", "false"); HOperatorSet.SetLineWidth(hWindowControl.HalconWindow, 5); InitializeMethods(); InitializeDelegates(); mappingEngine = new ExpressionTreeMappingEngine(dicContext); } // 初始化 ExpressionTreeMappingEngine mappingEngine = null; /// /// 编译映射 /// public void CompileMappings() { mappingEngine = new ExpressionTreeMappingEngine(dicContext); mappingEngine.CompileMappings(dicInputsMapping); } /// /// 更新输入(高性能执行) /// /// public void UpdateInputs(IProcess process) { mappingEngine.UpdateInputs(process); } public bool GetValue(string map, out object obj) { obj = null; if (string.IsNullOrEmpty(map)) return false; try { string[] arrMap = map.Split("."); if (arrMap.Length <= 1) return false; string IndexProcessName = arrMap[0]; string IndexIsInputOrOutput = arrMap[1]; string IndexValueName = arrMap.Length == 3 ? arrMap[2] : ""; //这里的o是你所指向的输出流程 object o = dicContext[IndexProcessName]; if (o != null && o is IProcess i) { if (i.strProcessName != IndexProcessName) return false; if (IndexValueName == "Result") { switch (IndexIsInputOrOutput) { case "Inputs": //实际上不允许索引的值是输入 obj = i.Result; break; case "Outputs": obj = i.Result; break; default: return false; } } else { //赋值参数 switch (IndexIsInputOrOutput) { case "Inputs": obj = i.Params.Inputs[IndexValueName]; break; case "Outputs": obj = i.Params.Outputs[IndexValueName]; break; default: return false; } } return true; } else return false; } catch { obj = null; return false; } } public bool GetStringOutput(string map, out string str) { bool res = GetValue(map, out object obj); str = ProcessParams.ConvertToString(obj); return res; } public bool GetImage(Layout layout, out HObject InputImage, out HObject RecordImage) { InputImage = null; RecordImage = null; try { if (layout == null) return false; string ProcessName = layout.ProcessName; string InputImageMap = layout.InputImage; string RecordImageMap = layout.RecordImage; string[] arrOutputs = new string[] { }; string IndexProcessName = string.Empty; string IndexIsInputOrOutput = string.Empty; string IndexValueName = string.Empty; #region 获取输入图片 if (dicContext.ContainsKey(InputImageMap)) { object o_InputImage = ((IProcess)dicContext[InputImageMap]).OutputImage; if (o_InputImage is HObject ho_image && ho_image.IsInitialized()) InputImage = ho_image; else if (o_InputImage is Bitmap) { //将Mat转换为HObject TAlgorithm.Bitmap2HObject((Bitmap)o_InputImage, out HObject ho_RecordImage); InputImage = ho_RecordImage; } else if (o_InputImage is Mat) { //将Mat转换为HObject TAlgorithm.Mat2HObject((Mat)o_InputImage, out HObject ho_RecordImage); InputImage = ho_RecordImage; } if (InputImage != null && InputImage.IsInitialized()) { HOperatorSet.GetImageSize(InputImage, out ho_ImageWidth, out ho_ImageHeight); //图片尺寸变化才更新窗口尺寸[提高速度] if ((ho_ImageWidth.Length > 0 && ho_ImageWidth.TupleInt() != hWindowControl.Size.Width) || (ho_ImageHeight.Length > 0 && ho_ImageHeight.TupleInt() != hWindowControl.Size.Height)) { hWindowControl.Invoke(new Action(() => { hWindowControl.Size = new System.Drawing.Size(ho_ImageWidth, ho_ImageHeight); })); } } if (InputImage != null) TAlgorithm.DispImage(InputImage, hWindowControl.HalconWindow); } #endregion #region 绘制结果图 string[] RecordImageMaps = RecordImageMap.Split(';'); int FontSize = ho_ImageHeight.I / 80 > 0 ? ho_ImageHeight.I / 80 : 8; int MsgSize = ho_ImageHeight.I / 40 > 0 ? ho_ImageHeight.I / 80 : 20; TAlgorithm.set_display_font(hWindowControl.HalconWindow, FontSize, "mono", "true", "false"); foreach (var item in RecordImageMaps) { if (dicContext.ContainsKey(item)) { ObjectRecord objectRecord = ((IProcess)dicContext[item]).Record; if (objectRecord != null) { objectRecord.Display(hWindowControl.HalconWindow); objectRecord.Dispose(); } } } TAlgorithm.set_display_font(hWindowControl.HalconWindow, MsgSize, "mono", "true", "false"); if (Result) { Msg = "运行成功"; HOperatorSet.SetColor(hWindowControl.HalconWindow, "green"); } else HOperatorSet.SetColor(hWindowControl.HalconWindow, "red"); TAlgorithm.DispMsg(Msg, hWindowControl.HalconWindow, Result ? "green" : "red", 0, 0); HOperatorSet.DumpWindowImage(out RecordImage, hWindowControl.HalconWindow); #endregion return true; } catch { return false; } } public bool GetCsv(CsvSetting csv, out List DataTitle, out Dictionary ResultData) { // 数据标题 DataTitle = (new string[] { "名称", "时间", "耗时", "结果", "原因" }).ToList(); ResultData = new Dictionary(); try { ResultData.Add("名称", csv.ProcessName); ResultData.Add("时间", $"'{DateTime.Now.ToString("HH:mm:ss.ff")}"); ResultData.Add("耗时", $"{RunTime.ToString("F2")}"); ResultData.Add("结果", Result); ResultData.Add("原因", Msg); for (int i = 0; i < csv.Others.Count; i++) { string title = $"数据{i}"; string map = csv.Others[i]; GetValue(map, out object obj); if (obj == null) continue; Type type = obj.GetType(); switch (type) { case Type t when t == typeof(double): ResultData.Add(title, ((double)obj).ToString("F4")); DataTitle.Add(title); break; default: ResultData.Add(title, ProcessParams.ConvertToString(obj)); DataTitle.Add(title); break; } } return true; } catch { return false; } } /// /// 非分支节点的统一调用方式 /// private void RunNodeAsync(FlowNode node) { // 走默认分支 node.BranchIndex = "0"; string ProcessName = node.Text; try { if (dicContext.TryGetValue(ProcessName, out IProcess obj) && obj is IProcess process) { process.InputImage = null; UpdateInputs(process); // 不同节点跳过的方式不同 if (node.Break) { switch (node.Description) { case "T306通讯": node.BranchIndex = "0"; node.Result = true; process.Result = false; process.Msg = "T306通讯未启用"; return; default: node.BranchIndex = "0"; node.Result = true; process.Result = true; process.Msg = string.Empty; return; } } if (!process.Run()) { node.Result = false; Result &= false; if (!string.IsNullOrEmpty(process.Msg) && !Msg.Contains($"[{process.strProcessName}]{process.Msg}")) Msg += $"[{process.strProcessName}]{process.Msg}"; } else node.Result = true; } } catch (Exception ex) { node.Result = false; Result &= false; Msg += $"[{ProcessName}]运行发生意外,{ex.Message}"; } } #region 相机工具 [Node("相机取图", "相机", "Basic", "相机取图")] public void 相机取图(FlowNode node) { RunNodeAsync(node); } #endregion #region 通讯工具 [Node("通讯测试", "通讯", "Basic", "通讯测试")] public void 通讯测试(FlowNode node) { RunNodeAsync(node); } //[Node("西门子S7", "通讯", "Basic", "西门子S7")] //public void 西门子S7(FlowNode node) { RunNodeAsync(node); } [Node("T306通讯", "通讯", "Basic", "T306通讯")] public void T306通讯(FlowNode node) { RunNodeAsync(node); } [Node("ModbusRTU", "通讯", "Basic", "ModbusRTU")] public void ModbusRTU(FlowNode node) { RunNodeAsync(node); } [Node("ModbusTCP", "通讯", "Basic", "ModbusTCP")] public void ModbusTCP(FlowNode node) { RunNodeAsync(node); } #endregion #region Halcon2D算法 [Node("Halcon2D_模板匹配工具", "Halcon2D算法", "Basic", "Halcon2D_模板匹配工具")] public void Halcon2D_模板匹配工具(FlowNode node) { RunNodeAsync(node); } [Node("Halcon2D_多模板匹配工具", "Halcon2D算法", "Basic", "Halcon2D_多模板匹配工具")] public void Halcon2D_多模板匹配工具(FlowNode node) { RunNodeAsync(node); } [Node("Halcon2D_斑点工具", "Halcon2D算法", "Basic", "Halcon2D_斑点工具")] public void Halcon2D_斑点工具(FlowNode node) { RunNodeAsync(node); } [Node("Halcon2D_读码工具", "Halcon2D算法", "Basic", "Halcon2D_读码工具")] public void Halcon2D_读码工具(FlowNode node) { RunNodeAsync(node); } [Node("Halcon2D_找线工具", "Halcon2D算法", "Basic", "Halcon2D_找线工具")] public void Halcon2D_找线工具(FlowNode node) { RunNodeAsync(node); } [Node("Halcon2D_图像增强工具", "Halcon2D算法", "Basic", "Halcon2D_图像增强工具")] public void Halcon2D_图像增强工具(FlowNode node) { RunNodeAsync(node); } #endregion #region 分割模型 [Node("语义分割工具", "BigModel", "Basic", "语义分割工具")] public void 语义分割工具(FlowNode node) { RunNodeAsync(node); } #endregion #region OpenCvSharp算法 [Node("OpenCvSharp_模板匹配工具", "OpenCvSharp算法", "Basic", "OpenCvSharp_模板匹配工具")] public void OpenCvSharp_模板匹配工具(FlowNode node) { RunNodeAsync(node); } [Node("OpenCvSharp_斑点工具", "OpenCvSharp算法", "Basic", "OpenCvSharp_斑点工具")] public void OpenCvSharp_斑点工具(FlowNode node) { RunNodeAsync(node); } [Node("OpenCvSharp_找线工具", "OpenCvSharp算法", "Basic", "OpenCvSharp_找线工具")] public void OpenCvSharp_找线工具(FlowNode node) { RunNodeAsync(node); } #endregion #region 图像处理工具 [Node("单图像处理工具", "图像处理工具", "Basic", "单图像处理工具")] public void 单图像处理工具(FlowNode node) { RunNodeAsync(node); } [Node("点云转换工具", "图像处理工具", "Basic", "点云转换工具")] public void 点云转换工具(FlowNode node) { RunNodeAsync(node); } [Node("畸变矫正工具", "图像处理工具", "Basic", "畸变矫正工具")] public void 畸变矫正工具(FlowNode node) { RunNodeAsync(node); } #endregion #region 工具 [Node("脚本", "工具", "Basic", "脚本")] public void 脚本(FlowNode node) { RunNodeAsync(node); } [Node("轮胎计数", "工具", "Basic", "轮胎计数")] public void 轮胎计数(FlowNode node) { RunNodeAsync(node); } [Node("创建绘制工具", "工具", "Basic", "创建绘制工具")] public void 创建绘制工具(FlowNode node) { RunNodeAsync(node); } [Node("创建固定跟随", "工具", "Basic", "创建固定跟随")] public void 创建固定跟随(FlowNode node) { RunNodeAsync(node); } [Node("创建线段工具", "工具", "Basic", "创建线段工具")] public void 创建线段工具(FlowNode node) { RunNodeAsync(node); } [Node("创建垂线工具", "工具", "Basic", "创建垂线工具")] public void 创建垂线工具(FlowNode node) { RunNodeAsync(node); } [Node("线线交点工具", "工具", "Basic", "线线交点工具")] public void 线线交点工具(FlowNode node) { RunNodeAsync(node); } [Node("延时", "工具", "Basic", "延时")] public void 延时(FlowNode node) { RunNodeAsync(node); } #endregion [Node("开始", "控制", "Logic", "开始")] public override void 开始(FlowNode node) { StartTime = DateTime.Now; RunTime = 0; Result = true; bRuning = true; bCompleted = false; Msg = string.Empty; HOperatorSet.ClearWindow(hWindowControl.HalconWindow); HOperatorSet.SetColor(hWindowControl.HalconWindow, "green"); } [Node("结束", "控制", "Logic", "结束")] public override void 结束(FlowNode node) { bRuning = false; bCompleted = true; if (Result) Msg = "运行成功"; RunTime = (DateTime.Now - StartTime).TotalMilliseconds; } [Node("分支", "控制", "Logic", "分支")] public override void 分支(FlowNode node) { string ProcessName = node.Text; node.BranchIndex = "-1"; node.Result = true; try { if (dicContext.TryGetValue(ProcessName, out IProcess obj) && obj is ScriptTool script) { if (node.Break) { node.BranchIndex = "0"; node.Result = true; script.Result = true; script.Msg = string.Empty; return; } if (script.Params.Outputs.Count >= 2) { RunNodeAsync(node); if (!script.Result) { node.Result = false; Result &= false; Msg = $"[{ProcessName}]{script.Msg}"; } for (int i = 0; i < script.Params.Outputs.Count; i++) { if (script.Params.Outputs[$"Branch{i}"] != null && Convert.ToBoolean(script.Params.Outputs[$"Branch{i}"])) { node.BranchIndex = i.ToString(); return; } } node.Result = false; Result &= false; Msg = $"[{ProcessName}]无满足条件的分支"; } else { node.Result = false; Result &= false; Msg = $"[{ProcessName}]分支数量不为2"; } } else { node.Result = false; Result &= false; } } catch (Exception ex) { node.Result = false; Result &= false; Msg = $"[{ProcessName}]运行发生意外,{ex.Message}"; } } [Node("多分支", "控制", "Logic", "多分支")] public override void 多分支(FlowNode node) { if (node.Break) { node.BranchIndex = "0"; node.Result = true; return; } string ProcessName = node.Text; node.BranchIndex = "-1"; node.Result = true; try { if (dicContext.TryGetValue(ProcessName, out IProcess obj) && obj is ScriptTool script) { if (node.Break) { node.BranchIndex = "0"; node.Result = true; script.Result = true; script.Msg = string.Empty; return; } if (script.Params.Outputs.Count >= 1) { RunNodeAsync(node); if (!script.Result) { node.Result = false; Result &= false; Msg = $"[{ProcessName}]{script.Msg}"; } for (int i = 0; i < script.Params.Outputs.Count; i++) { if (script.Params.Outputs[$"Branch{i}"] != null && Convert.ToBoolean(script.Params.Outputs[$"Branch{i}"])) { node.BranchIndex = i.ToString(); return; } } node.Result = false; Result &= false; Msg = $"[{ProcessName}]无满足条件的分支"; } else { node.Result = false; Result &= false; Msg = $"[{ProcessName}]多分支数量小于1"; } } else { node.Result = false; Result &= false; } } catch (Exception ex) { node.Result = false; Result &= false; Msg = $"[{ProcessName}]运行发生意外,{ex.Message}"; } } } }