using HalconDotNet; using System.Data.Common; using LB_VisionProcesses.Alogrithms; using System.Windows.Forms; using Newtonsoft.Json; using static LB_VisionProcesses.Alogrithms.Halcon.BlobAfterProcess; using LB_VisionControl; namespace LB_VisionProcesses.Alogrithms.Halcon { public partial class HBlobToolEdit : TAlgorithmEdit { public HBlobToolEdit(HBlobTool subject = null) { if (subject != null && subject is HBlobTool) Subject = subject; else Subject = new HBlobTool(); this.Dock = DockStyle.Fill; InitializeComponent(); // 遍历可以选择的类型枚举 foreach (var value in Enum.GetValues(typeof(ProcessType))) cmbProcessType.Items.Add(value.ToString()); cmbProcessType.Text = ProcessType.Close.ToString(); // 遍历可以选择的类型枚举 foreach (var value in Enum.GetValues(typeof(ShapeType))) cmbShapeType.Items.Add(value.ToString()); cmbShapeType.Text = ShapeType.Rectangle.ToString(); cmbShapeType.SelectedIndexChanged += (sender, e) => { if (cmbShapeType.SelectedItem.ToString() == ShapeType.Circle.ToString()) txtAfterProcessHeight.Enabled = false; else txtAfterProcessHeight.Enabled = true; }; btnAdd.Click += (sender, e) => { if (txtAfterProcessWidth.Value > 0 && txtAfterProcessHeight.Value > 0 && Enum.TryParse(cmbProcessType.Text, out ProcessType type) && Enum.TryParse(cmbShapeType.Text, out ShapeType shape)) { if (shape == ShapeType.Circle) ckbListAfter.Items.Add($"{type}_{shape}_{txtAfterProcessWidth.Value}*{txtAfterProcessWidth.Value}", true); else ckbListAfter.Items.Add($"{type}_{shape}_{txtAfterProcessWidth.Value}*{txtAfterProcessHeight.Value}", true); } }; btnDel.Click += (sender, e) => { ckbListAfter.Items.RemoveAt(ckbListAfter.Items.Count - 1); }; lblTips.Text = "闭运算(先膨胀再腐蚀) Close 填充孔洞、填补不规则缺陷" + "\n开运算(先腐蚀再膨胀) Open 去除噪声、去除细小杂质、优化形状" + "\n膨胀 Dilation 扩大区域、裂缝填补、目标区域扩展" + "\n腐蚀 Erosion 消除噪声、目标分离、形态边界缩小"; } /// /// 控件加载事件 /// /// /// private void HBlobToolEdit_Load(object sender, EventArgs e) { pnlInputImage.Controls.Add(inputImageHSmartWindowControl); inputImageHSmartWindowControl.Dock = DockStyle.Fill; pnlRecordImage.Controls.Add(recordImageHSmartWindowControl); recordImageHSmartWindowControl.Dock = DockStyle.Fill; //遍历可以选择的Roi类型枚举 foreach (var value in Enum.GetValues(typeof(RoiType))) cmbTypeRoi.Items.Add(value.ToString()); //遍历可以选择的Fixture枚举 cmbFixture.Items.Add(""); foreach (string value in IProcess.dicFixtures.Keys) cmbFixture.Items.Add(value.ToString()); cmbTypeRoi.Text = RoiType.None.ToString(); LoadParas(); if (Subject.Result) { lblResult.BackColor = Color.Green; lblResult.Text = "True"; } else { lblResult.BackColor = Color.Red; lblResult.Text = "False"; } lblMsg.Text = Msg.Length > 50 ? Msg.Substring(0, 50) : Msg; lblMsgToolTip.SetToolTip(BtmStatusStrip, Msg); lblRunTime.Text = $"{Subject.RunTime}ms"; } /// /// 更新运行参数 /// public override void UpdataInputs() { //设置运行参数 double dResult = 0; int iResult = 0; Subject.Params.Inputs["MinThreshold"] = int.TryParse(dtxtMinThreshold.Text, out iResult) ? iResult : Subject.Params.Inputs["MinThreshold"]; Subject.Params.Inputs["MaxThreshold"] = int.TryParse(dtxtMaxThreshold.Text, out iResult) ? iResult : Subject.Params.Inputs["MaxThreshold"]; Subject.Params.Inputs["MinArea"] = double.TryParse(dtxtMinArea.Text, out dResult) ? dResult : Subject.Params.Inputs["MinArea"]; Subject.Params.Inputs["MaxArea"] = double.TryParse(dtxtMaxArea.Text, out dResult) ? dResult : Subject.Params.Inputs["MaxArea"]; Subject.Params.Inputs["MinRow"] = double.TryParse(dtxtMinRow.Text, out dResult) ? dResult : Subject.Params.Inputs["MinRow"]; Subject.Params.Inputs["MaxRow"] = double.TryParse(dtxtMaxRow.Text, out dResult) ? dResult : Subject.Params.Inputs["MaxRow"]; Subject.Params.Inputs["MinColumn"] = double.TryParse(dtxtMinColumn.Text, out dResult) ? dResult : Subject.Params.Inputs["MinColumn"]; Subject.Params.Inputs["MaxColumn"] = double.TryParse(dtxtMaxColumn.Text, out dResult) ? dResult : Subject.Params.Inputs["MaxColumn"]; Subject.Params.Inputs["MinCircularity"] = double.TryParse(dtxtMinCircularity.Text, out dResult) ? dResult : Subject.Params.Inputs["MinCircularity"]; Subject.Params.Inputs["MaxCircularity"] = double.TryParse(dtxtMaxCircularity.Text, out dResult) ? dResult : Subject.Params.Inputs["MaxCircularity"]; Subject.Params.Inputs["MinRectangularity"] = double.TryParse(dtxtMinRectangularity.Text, out dResult) ? dResult : Subject.Params.Inputs["MinRectangularity"]; Subject.Params.Inputs["MaxRectangularity"] = double.TryParse(dtxtMaxRectangularity.Text, out dResult) ? dResult : Subject.Params.Inputs["MaxRectangularity"]; Subject.Params.Inputs["MinCount"] = int.TryParse(dtxtMinCount.Text, out iResult) ? iResult : Subject.Params.Inputs["MinCount"]; Subject.Params.Inputs["MaxCount"] = int.TryParse(dtxtMaxCount.Text, out iResult) ? iResult : Subject.Params.Inputs["MaxCount"]; Subject.Params.Inputs["MinContlength"] = double.TryParse(dtxtMinContlength.Text, out dResult) ? dResult : Subject.Params.Inputs["MinContlength"]; Subject.Params.Inputs["MaxContlength"] = double.TryParse(dtxtMaxContlength.Text, out dResult) ? dResult : Subject.Params.Inputs["MaxContlength"]; Subject.Params.Inputs["MinAnisometry"] = double.TryParse(dtxtMinAnisometry.Text, out dResult) ? dResult : Subject.Params.Inputs["MinAnisometry"]; Subject.Params.Inputs["MaxAnisometry"] = double.TryParse(dtxtMaxAnisometry.Text, out dResult) ? dResult : Subject.Params.Inputs["MaxAnisometry"]; Subject.Params.Inputs["MinDistMean"] = double.TryParse(dtxtMinDistMean.Text, out dResult) ? dResult : Subject.Params.Inputs["MinDistMean"]; Subject.Params.Inputs["MaxDistMean"] = double.TryParse(dtxtMaxDistMean.Text, out dResult) ? dResult : Subject.Params.Inputs["MaxDistMean"]; Subject.Params.Inputs["MinDistDeviation"] = double.TryParse(dtxtMinDistDeviation.Text, out dResult) ? dResult : Subject.Params.Inputs["MinDistDeviation"]; Subject.Params.Inputs["MaxDistDeviation"] = double.TryParse(dtxtMaxDistDeviation.Text, out dResult) ? dResult : Subject.Params.Inputs["MaxDistDeviation"]; try { List BlobAfterProcesses = new List(); for (int i = 0; i < ckbListAfter.Items.Count; i++) { string[] arrStr = ckbListAfter.Items[i].ToString().Split('_'); if (arrStr.Length >= 3 && Enum.TryParse(arrStr[0], out ProcessType type) && Enum.TryParse(arrStr[1], out ShapeType shape)) { string[] arrSize = arrStr[2].ToString().Split('*'); BlobAfterProcesses.Add(new BlobAfterProcess( type, shape, Convert.ToInt32(arrSize[0]), Convert.ToInt32(arrSize[1]), ckbListAfter.GetItemChecked(i))); } } Subject.Params.Inputs["BlobAfterProcesses"] = JsonConvert.SerializeObject(BlobAfterProcesses); } catch { } if (cmbFixture.Text == "") Subject.Params.Fixture = new Fixture(); else if (IProcess.dicFixtures.ContainsKey(cmbFixture.Text)) Subject.Params.Fixture = IProcess.dicFixtures[cmbFixture.Text]; base.UpdataInputs(); } /// /// 加载运行参数 /// public override void LoadParas() { this.BeginInvoke(new Action(() => { dtxtMinThreshold.Text = Subject.Params.Inputs["MinThreshold"]?.ToString(); dtxtMaxThreshold.Text = Subject.Params.Inputs["MaxThreshold"]?.ToString(); dtxtMinArea.Text = Subject.Params.Inputs["MinArea"]?.ToString(); dtxtMaxArea.Text = Subject.Params.Inputs["MaxArea"]?.ToString(); dtxtMinRow.Text = Subject.Params.Inputs["MinRow"]?.ToString(); dtxtMaxRow.Text = Subject.Params.Inputs["MaxRow"]?.ToString(); dtxtMinColumn.Text = Subject.Params.Inputs["MinColumn"]?.ToString(); dtxtMaxColumn.Text = Subject.Params.Inputs["MaxColumn"]?.ToString(); dtxtMinCircularity.Text = Subject.Params.Inputs["MinCircularity"]?.ToString(); dtxtMaxCircularity.Text = Subject.Params.Inputs["MaxCircularity"]?.ToString(); dtxtMinRectangularity.Text = Subject.Params.Inputs["MinRectangularity"]?.ToString(); dtxtMaxRectangularity.Text = Subject.Params.Inputs["MaxRectangularity"]?.ToString(); dtxtMinContlength.Text = Subject.Params.Inputs["MinContlength"]?.ToString(); dtxtMaxContlength.Text = Subject.Params.Inputs["MaxContlength"]?.ToString(); dtxtMinAnisometry.Text = Subject.Params.Inputs["MinAnisometry"]?.ToString(); dtxtMaxAnisometry.Text = Subject.Params.Inputs["MaxAnisometry"]?.ToString(); dtxtMinDistMean.Text = Subject.Params.Inputs["MinDistMean"]?.ToString(); dtxtMaxDistMean.Text = Subject.Params.Inputs["MaxDistMean"]?.ToString(); dtxtMinDistDeviation.Text = Subject.Params.Inputs["MinDistDeviation"]?.ToString(); dtxtMaxDistDeviation.Text = Subject.Params.Inputs["MaxDistDeviation"]?.ToString(); dtxtMinCount.Text = Subject.Params.Inputs["MinCount"]?.ToString(); dtxtMaxCount.Text = Subject.Params.Inputs["MaxCount"]?.ToString(); try { List BlobAfterProcesses = JsonConvert.DeserializeObject>(Subject.Params.Inputs["BlobAfterProcesses"].ToString()); foreach (var BlobAfterProcess in BlobAfterProcesses) ckbListAfter.Items.Add($"{BlobAfterProcess.Type}_{BlobAfterProcess.Shape}_{BlobAfterProcess.Width}*{BlobAfterProcess.Height}", BlobAfterProcess.Enable); } catch { } if (Subject.InputImage != null && Subject.InputImage is HImage) inputImageHSmartWindowControl.ShowHoImage((HImage)Subject.InputImage); Type type = Subject.Params.ROI?.GetType(); if (Subject.Params.ROI != null) { switch (type) { case Type t when t == typeof(HRectangle2): cmbTypeRoi.Text = RoiType.Rectangle2.ToString(); break; case Type t when t == typeof(HCircle): cmbTypeRoi.Text = RoiType.Circle.ToString(); break; case Type t when t == typeof(HSegment): cmbTypeRoi.Text = RoiType.Segment.ToString(); break; default: cmbTypeRoi.Text = RoiType.None.ToString(); break; } if (cmbTypeRoi.Text.ToString() != "None") ckbDrawRoi.Checked = true; else ckbDrawRoi.Checked = false; inputImageHSmartWindowControl.oRoi = Subject.Params.ROI; } if (Subject.Params.Fixture != null) cmbFixture.Text = Subject.Params.Fixture.strName; else cmbFixture.Text = ""; base.LoadParas(); })); } /// /// 更新输出结果 /// public override void UpdataOutputs() { this.BeginInvoke(new Action(() => { //存在反序列化错乱的情况需要使用自定义的转换器 dtxtCenterX.Text = ProcessParams.ConvertToString(Subject.Params.Outputs["CenterX"]); dtxtCenterY.Text = ProcessParams.ConvertToString(Subject.Params.Outputs["CenterY"]); dtxtPhi.Text = ProcessParams.ConvertToString(Subject.Params.Outputs["Phi"]); dtxtWidth.Text = ProcessParams.ConvertToString(Subject.Params.Outputs["Width"]); dtxtHeight.Text = ProcessParams.ConvertToString(Subject.Params.Outputs["Height"]); dtxtArea.Text = ProcessParams.ConvertToString(Subject.Params.Outputs["Area"]); dtxtCount.Text = ProcessParams.ConvertToString(Subject.Params.Outputs["Count"]); })); } /// /// 点击运行 /// /// /// public override void btnRun_Click(object sender, EventArgs e) { if (Subject.InputImage != null) InputImage = Subject.InputImage; DateTime StartTime = DateTime.Now; Run(); //更新日志与结果 this.BeginInvoke(new Action(() => { if (Subject.Result) { lblResult.BackColor = Color.Green; lblResult.Text = "True"; recordImageHSmartWindowControl.SetColor("green"); } else { lblResult.BackColor = Color.Red; lblResult.Text = "False"; recordImageHSmartWindowControl.SetColor("red"); } lblMsg.Text = Msg.Length > 50 ? Msg.Substring(0, 50) : Msg; lblMsgToolTip.SetToolTip(BtmStatusStrip, Msg); lblRunTime.Text = $"{(DateTime.Now - StartTime).TotalMilliseconds}ms"; UpdataOutputs(); imgTabControl.SelectedTab = tabPageRecordImage; if (Subject.InputImage != null && Subject.InputImage is HImage) { using (HImage hImage = (HImage)Subject.InputImage) { hImage.GetImageSize(out HTuple ho_ImageWidth, out HTuple ho_ImageHeight); recordImageHSmartWindowControl.ShowHoImage(hImage); } } //先判断子类再判断父类 if (Subject.Record != null && Subject.Record is MsgRecord msgRecord) { recordImageHSmartWindowControl.DispObj(msgRecord.RecordObject_OK, true); recordImageHSmartWindowControl.DispObj(msgRecord.RecordObject_NG, false); for (int i = 0; i < msgRecord.Msg.Length; i++) recordImageHSmartWindowControl.ShowMsg(msgRecord.Msg[i] , 1 == msgRecord.Result[i] ? true : false, msgRecord.Column[i], msgRecord.Row[i]); } else if (Subject.Record != null && Subject.Record is ObjectRecord objRecord) { recordImageHSmartWindowControl.DispObj(objRecord.RecordObject_OK, true); recordImageHSmartWindowControl.DispObj(objRecord.RecordObject_NG, false); } GC.Collect(); })); } public override void btnLoadImage_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog = new OpenFileDialog(); // 设置文件对话框的属性 openFileDialog.Multiselect = false; // 不允许多选 // 设置文件过滤器,支持多种文件类型 openFileDialog.Filter = "Image Files (*.png;*.jpg;*.jpeg;*.bmp)|*.png;*.jpg;*.jpeg;*.bmp|All Files (*.*)|*.*"; // 显示文件对话框 DialogResult result = openFileDialog.ShowDialog(); // 处理对话框返回结果 if (result == DialogResult.OK) { // 获取用户选择的文件名 string[] selectedFiles = openFileDialog.FileNames; if (selectedFiles.Length > 0) { HOperatorSet.ReadImage(out HObject ho_Image, selectedFiles[0]); //判断是否为灰度图 using (HDevDisposeHelper dh = new HDevDisposeHelper()) { HOperatorSet.CountChannels(ho_Image, out HTuple hv_Channels); if (hv_Channels.TupleInt() != 1) { HOperatorSet.Rgb1ToGray(ho_Image, out ho_Image); //更新日志与结果 this.BeginInvoke(new Action(() => { lblMsg.Text = "导入图片非灰度图,自动转换为灰度图"; })); } InputImage = ho_Image; imgTabControl.SelectedTab = tabPageInputImage; inputImageHSmartWindowControl.oRoi = inputImageHSmartWindowControl.oRoi; } } } } public override void btnSaveParas_Click(object sender, EventArgs e) { base.btnSaveParas_Click(sender, e); } public override void ckbDrawRoi_CheckedChanged(object sender, EventArgs e) { if (ckbDrawRoi.Checked) { inputImageHSmartWindowControl.bAollowDraw = true; imgTabControl.SelectedTab = tabPageInputImage; } else { inputImageHSmartWindowControl.bAollowDraw = false; Subject.Params.ROI = new ROI(); } } public override void cmbTypeRoi_SelectedIndexChanged(object sender, EventArgs e) { try { if (Enum.TryParse(cmbTypeRoi.Text.ToString(), out RoiType type)) { HTuple hv_imageWidth = 0; HTuple hv_imageHeight = 0; if (InputImage != null && InputImage is HObject) HOperatorSet.GetImageSize((HObject)InputImage, out hv_imageWidth, out hv_imageHeight); switch (type) { case RoiType.Rectangle2: inputImageHSmartWindowControl.oRoi = new HRectangle2(hv_imageWidth.TupleReal() / 2, hv_imageHeight.TupleReal() / 2, 0 , hv_imageWidth.TupleReal() / 4, hv_imageHeight.TupleReal() / 4); break; case RoiType.Circle: inputImageHSmartWindowControl.oRoi = new HCircle(hv_imageWidth.TupleReal() / 2, hv_imageHeight.TupleReal() / 2, hv_imageWidth.TupleReal() / 4); break; //case RoiType.Ellipse: // inputImageHSmartWindowControl.oRoi // = new HEllipse(hv_imageWidth.TupleReal() / 2, hv_imageHeight.TupleReal() / 2,0, hv_imageHeight.TupleReal() / 4, hv_imageWidth.TupleReal() / 4); // break; //case RoiType.Segment: // inputImageHSmartWindowControl.oRoi // = new HSegment(0, 0, hv_imageWidth.TupleReal() / 4, hv_imageHeight.TupleReal() / 4); // break; case RoiType.None: default: inputImageHSmartWindowControl.oRoi = null; break; } } } catch { } } public override void cmbFixture_SelectedIndexChanged(object sender, EventArgs e) { try { if (IProcess.dicFixtures.ContainsKey(cmbFixture.Text)) Subject.Params.Fixture = IProcess.dicFixtures[cmbFixture.Text]; else Subject.Params.Fixture = new Fixture(); } catch { } } } }