using HalconDotNet; using LB_SmartVision.Forms.Pages.SettingPage; using LB_SmartVision.Tool; using LB_VisionFlowNode; using LB_VisionProcesses; using LB_VisionProcesses.Alogrithms; using LB_VisionProcesses.Cameras; using LB_VisionProcesses.Communicators; using LB_VisionProcesses.Processes.ScriptTool; using OpenCvSharp; using System.Collections.Concurrent; using System.Windows.Media.Media3D; 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); } //void UpdateInputs(IProcess process) //{ // string ProcessName = process.strProcessName; // List> listTuples = dicInputsMapping[ProcessName]; // foreach (var tuple in listTuples) // { // if (string.IsNullOrEmpty(tuple.Item2) || tuple.Item2.Trim() == "") // continue; // string[] arrInputs = tuple.Item1.Split("."); // if (arrInputs.Length < 3) // continue; // string InputProcessName = arrInputs[0]; // string strInput = arrInputs[1]; // string InputValueName = arrInputs[2]; // string[] arrOutputs = tuple.Item2.Split("."); // if (arrOutputs.Length < 2) // continue; // string IndexProcessName = arrOutputs[0]; // string IndexIsInputOrOutput = arrOutputs[1]; // string IndexValueName = arrOutputs.Length == 3 ? arrOutputs[2] : ""; // //这里的o是你所指向的输出流程 // object o = dicContext[IndexProcessName]; // if (o == null) // continue; // else if (o is IProcess) // { // IProcess i = (IProcess)o; // if (i.strProcessName != IndexProcessName) // continue; // if (InputValueName == "Image") // { // switch (IndexIsInputOrOutput) // { // case "Inputs": // //实际上不允许索引的值是输入 // if (IndexValueName == "Image") // process.InputImage = i.InputImage; // else // process.InputImage = i.Params.Inputs[IndexValueName]; // break; // case "Outputs": // if (IndexValueName == "Image") // process.InputImage = i.OutputImage; // else // process.InputImage = i.Params.Outputs[IndexValueName]; // break; // default: // process.InputImage = null; // break; // } // if (IndexValueName == "") // process.InputImage = null; // } // else if (InputValueName == "Fixture") // { // //赋值参数 // switch (IndexIsInputOrOutput) // { // case "Inputs": // //实际上不允许索引的值是输入 // process.Params.Fixture = i.Params.Fixture; // break; // case "Outputs": // process.Params.Fixture = i.Params.Fixture; // break; // default: // //process.Params.Fixture = new Fixture(); // break; // } // if (IndexValueName == "") // process.Params.Fixture = new Fixture(); // } // else if (IndexValueName == "Result") // { // //赋值参数 // switch (IndexIsInputOrOutput) // { // case "Inputs": // //实际上不允许索引的值是输入 // process.Params.Inputs[InputValueName] = i.Result; // break; // case "Outputs": // process.Params.Inputs[InputValueName] = i.Result; // break; // default: // process.Params.Inputs[InputValueName] = null; // break; // } // } // else if (process.Params.Inputs.Contains(InputValueName)) // { // //赋值参数 // switch (IndexIsInputOrOutput) // { // case "Inputs": // //实际上不允许索引的值是输入 // process.Params.Inputs[InputValueName] = i.Params.Inputs[IndexValueName]; // break; // case "Outputs": // process.Params.Inputs[InputValueName] = i.Params.Outputs[IndexValueName]; // break; // default: // process.Params.Inputs[InputValueName] = null; // break; // } // } // } // } //} 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 RecordImageMap1 = layout.RecordImage1; string RecordImageMap2 = layout.RecordImage2; string RecordImageMap3 = layout.RecordImage3; string[] arrOutputs = new string[] { }; string IndexProcessName = string.Empty; string IndexIsInputOrOutput = string.Empty; string IndexValueName = string.Empty; #region 获取输入图片 arrOutputs = InputImageMap.Split("."); if (arrOutputs.Length > 2) { IndexProcessName = arrOutputs[0]; IndexIsInputOrOutput = arrOutputs[1]; IndexValueName = arrOutputs[2]; object o_InputImage = ((IProcess)dicContext[IndexProcessName]).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); TAlgorithm.set_display_font(hWindowControl.HalconWindow, ho_ImageWidth.I / 20, "mono", "true", "false"); })); } } TAlgorithm.DispImage(InputImage, hWindowControl.HalconWindow); } #endregion #region 绘制结果图 arrOutputs = RecordImageMap1.Split("."); if (arrOutputs.Length > 2) { IndexProcessName = arrOutputs[0]; IndexIsInputOrOutput = arrOutputs[1]; IndexValueName = arrOutputs[2]; if (dicContext.ContainsKey(IndexProcessName)) { ObjectRecord objectRecord1 = ((IProcess)dicContext[IndexProcessName]).Record; if (objectRecord1 != null) { objectRecord1.Display(hWindowControl.HalconWindow); objectRecord1.Dispose(); } } } arrOutputs = RecordImageMap2.Split("."); if (arrOutputs.Length > 2) { IndexProcessName = arrOutputs[0]; IndexIsInputOrOutput = arrOutputs[1]; IndexValueName = arrOutputs[2]; if (dicContext.ContainsKey(IndexProcessName)) { ObjectRecord objectRecord2 = ((IProcess)dicContext[IndexProcessName]).Record; if (objectRecord2 != null) { objectRecord2.Display(hWindowControl.HalconWindow); objectRecord2.Dispose(); } } } arrOutputs = RecordImageMap3.Split("."); if (arrOutputs.Length > 2) { IndexProcessName = arrOutputs[0]; IndexIsInputOrOutput = arrOutputs[1]; IndexValueName = arrOutputs[2]; if (dicContext.ContainsKey(IndexProcessName)) { ObjectRecord objectRecord3 = ((IProcess)dicContext[IndexProcessName]).Record; if (objectRecord3 != null) { objectRecord3.Display(hWindowControl.HalconWindow); objectRecord3.Dispose(); } } } 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; if (process.InputImage != null) { if (process.InputImage is HObject) ((HObject)process.InputImage).Dispose(); else if (process.InputImage is Mat) ((Mat)process.InputImage).Dispose(); else if (process.InputImage is Bitmap) ((Bitmap)process.InputImage).Dispose(); process.InputImage = null; } if (process.OutputImage != null) { if (process.OutputImage is HObject) ((HObject)process.OutputImage).Dispose(); else if (process.OutputImage is Mat) ((Mat)process.OutputImage).Dispose(); else if (process.OutputImage is Bitmap) ((Bitmap)process.OutputImage).Dispose(); process.OutputImage = null; } if (process.Record != null) { process.Record.Dispose(); process.Record = 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); } [Node("Halcon2D斑点工具", "Halcon2D工具", "Basic", "Halcon2D斑点工具")] public void Halcon2D斑点工具(FlowNode node) { RunNodeAsync(node); } [Node("通讯模块", "通讯工具", "Basic", "通讯模块")] public void 通讯模块(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 [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) { UpdateInputs(script); if (node.Break) { node.BranchIndex = "0"; node.Result = true; script.Result = true; script.Msg = string.Empty; return; } if (script.Params.Outputs.Count >= 2) { if (!script.Run()) { 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) { UpdateInputs(script); if (node.Break) { node.BranchIndex = "0"; node.Result = true; script.Result = true; script.Msg = string.Empty; return; } if (script.Params.Outputs.Count >= 1) { if (!script.Run()) { 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}"; } } } }