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("读码工具", "取像工具", "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}";
}
}
}
}