using HalconDotNet; using LB_VisionControl; using LB_VisionProcesses.Alogrithms.Halcon; using System; using System.Collections.Generic; using System.Drawing.Imaging; using System.Linq; using System.Text; using System.Threading.Tasks; using static LB_VisionProcesses.Alogrithms.Halcon.HFindCode2dTool; namespace LB_VisionProcesses.Alogrithms.Halcon { public enum Transition { Positive, Negative, Ignore } public enum Selector { First, Last, Best } [Process("Halcon2D找线工具", Category = "Halcon2D工具", Description = "创建找线工具")] public class HFindLineTool : TAlgorithm { public HFindLineTool() { strProcessClass = "LB_VisionProcesses.Alogrithms.Halcon.HFindLineTool"; strProcessName = "Halcon2D找线工具"; Params.Inputs.Add("卡尺数量", 6); Params.Inputs.Add("卡尺长度", 30); Params.Inputs.Add("卡尺宽度", 10); Params.Inputs.Add("过滤一半像素", 2); Params.Inputs.Add("对比度阈值", 5); Params.Inputs.Add("极性", "Ignore"); Params.Inputs.Add("边缘位置", "Best"); Params.Inputs.Add("忽略点数", 0); Params.Outputs.Add("X", new List()); Params.Outputs.Add("Y", new List()); Params.Outputs.Add("CenterX", 0.0); Params.Outputs.Add("CenterY", 0.0); Params.Outputs.Add("Phi", 0.0); Params.Outputs.Add("Angle", 0.0); Params.Outputs.Add("Count", 0); Params.Outputs.Add("Segment", new HSegment()); Params.ROI = new HSegment(0, 0, 250, 250); } /// /// 算子逻辑 /// public override void TAlgorithmMain() { #region 初始化变量 HObject ho_Regions, ho_LineXld; HOperatorSet.GenEmptyObj(out ho_Regions); HOperatorSet.GenEmptyObj(out ho_LineXld); #endregion try { if (InputImage == null) { Msg = "输入图片为空"; Result = false; return; } if (InputImage is Bitmap) { try { using (HImage hImage = new HImage()) { Rectangle rect = new Rectangle(0, 0, ((Bitmap)InputImage).Width, ((Bitmap)InputImage).Height); BitmapData srcBmpData = ((Bitmap)InputImage).LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb); hImage.GenImageInterleaved(srcBmpData.Scan0, "rgbx", ((Bitmap)InputImage).Width, ((Bitmap)InputImage).Height, 0, "byte", ((Bitmap)InputImage).Width, ((Bitmap)InputImage).Height, 0, 0, -1, 0); ((Bitmap)InputImage).UnlockBits(srcBmpData); ((Bitmap)InputImage).Dispose(); InputImage = hImage.Clone(); } } catch (Exception ex) { Msg = "转图出错:" + ex.Message; Result = false; return; } } if (!(InputImage is HObject)) { Msg = "输入图片格式不为Mat"; Result = false; return; } #region 裁剪区域 if (!(Params.ROI is HSegment)) { Msg = "ROI类型错误,必须为HSegment类型"; Result = false; return; } if (!(InputImage is HObject)) { Msg = "输入图片类型错误,必须为HObject类型"; Result = false; return; } HObject DomainImage = ((HObject)InputImage)?.CopyObj(1, -1); #endregion #region 算子逻辑 Record = new ObjectRecord(); HObject hoDomainImage = DomainImage as HObject; HTuple hv_Channels = new HTuple(); //判断是否为灰度图 using (HDevDisposeHelper dh = new HDevDisposeHelper()) { try { HOperatorSet.CountChannels(hoDomainImage, out hv_Channels); if (hv_Channels.TupleInt() != 1) HOperatorSet.Rgb1ToGray(hoDomainImage, out hoDomainImage); //转换后再次检查是否为灰度图 HOperatorSet.CountChannels(hoDomainImage, out hv_Channels); if (hv_Channels.TupleInt() != 1) { HOperatorSet.Rgb1ToGray(hoDomainImage, out hoDomainImage); Msg = "输入图片不为灰度图"; Result = false; return; } } catch { Msg = "输入图片不为灰度图且转换失败"; Result = false; return; } } int hv_Elements = Convert.ToInt16(Params.Inputs["卡尺数量"]); double hv_DetectHeight = Convert.ToDouble(Params.Inputs["卡尺长度"]); double hv_DetectWidth = Convert.ToDouble(Params.Inputs["卡尺宽度"]); int hv_Sigma = Convert.ToInt16(Params.Inputs["过滤一半像素"]); int hv_Threshold = Convert.ToInt16(Params.Inputs["对比度阈值"]); int hv_IgnoreNum = Convert.ToInt16(Params.Inputs["忽略点数"]); Enum.TryParse(Params.Inputs["极性"]?.ToString(), out Transition transition); string hv_Transition = "ignore"; switch (transition) { case Transition.Positive: hv_Transition = "positive"; break; case Transition.Negative: hv_Transition = "negative"; break; case Transition.Ignore: default: hv_Transition = "ignore"; break; } Enum.TryParse(Params.Inputs["边缘位置"]?.ToString(), out Selector selector); string hv_Select = "best"; switch (selector) { case Selector.First: hv_Select = "first"; break; case Selector.Last: hv_Select = "last"; break; case Selector.Best: default: hv_Select = "best"; break; } double hv_Row1 = Convert.ToDouble(((HSegment)Params.ROI).BeginRow + Params.Fixture.Row); double hv_Column1 = Convert.ToDouble(((HSegment)Params.ROI).BeginColumn + Params.Fixture.Column); double hv_Row2 = Convert.ToDouble(((HSegment)Params.ROI).EndRow + Params.Fixture.Row); double hv_Column2 = Convert.ToDouble(((HSegment)Params.ROI).EndColumn + Params.Fixture.Column); Rake(hoDomainImage, out ho_Regions, hv_Elements, hv_DetectHeight, hv_DetectWidth , hv_Sigma, hv_Threshold, hv_Transition, hv_Select , hv_Row1, hv_Column1, hv_Row2, hv_Column2 , out HTuple hv_ResultRow, out HTuple hv_ResultColumn); #endregion #region 结果处理 List X = new List(); List Y = new List(); double CenterX = 0; double CenterY = 0; double Phi = 0; HSegment HSegment = new HSegment(); if (hv_ResultRow.Type != HTupleType.EMPTY && hv_ResultRow.Length > 0) { for (int k = 0; k < hv_ResultRow.Length; k++) { Y.Add(hv_ResultRow[k].D); X.Add(hv_ResultColumn[k].D); } if (X.Count >= 3) { pts_to_best_line(out ho_LineXld, hv_ResultRow, hv_ResultColumn, hv_IgnoreNum , out HTuple hv_Row11, out HTuple hv_Column11, out HTuple hv_Row21, out HTuple hv_Column21); ((ObjectRecord)Record).AddXld(ho_LineXld); CenterX = (hv_Column11.D + hv_Column21.D) / 2; CenterY = (hv_Row11.D + hv_Row21.D) / 2; //计算直线与x轴的夹角,逆时针方向为正向 HOperatorSet.AngleLx(hv_Row11, hv_Column11, hv_Row21, hv_Column21, out HTuple hv_ATan); Phi = hv_ATan; HSegment = new HSegment(hv_Column11.D, hv_Row11.D, hv_Column21.D, hv_Row21.D); } else { Msg = "找线失败"; Result = false; return; } } else { Msg = "找线失败"; Result = false; return; } Params.Outputs["X"] = X; Params.Outputs["Y"] = Y; Params.Outputs["CenterX"] = CenterX; Params.Outputs["CenterY"] = CenterY; Params.Outputs["Phi"] = Phi; Params.Outputs["Angle"] = Phi * 180.0 / Math.PI; Params.Outputs["Count"] = X.Count; Params.Outputs["Segment"] = HSegment; #endregion #region 生成OutputImage给后续处理 try { OutputImage = hoDomainImage; } catch (Exception ex) { Msg = "生成OutputImage失败,原因是:" + ex.ToString(); Result = false; return; } #endregion if (Msg == "运行超时") { Result = false; return; } Msg = "运行成功"; Result = true; return; } catch (Exception ex) { Msg = "运行失败,原因是:" + ex.ToString().TrimEnd(); OutputImage = null; Result = false; return; } finally { if (!Result) { Params.Outputs.Add("X", new List()); Params.Outputs.Add("Y", new List()); Params.Outputs.Add("CenterX", 0.0); Params.Outputs.Add("CenterY", 0.0); Params.Outputs.Add("Phi", 0.0); Params.Outputs.Add("Angle", 0.0); Params.Outputs.Add("Count", 0); Params.Outputs.Add("Segment", new HSegment()); } bCompleted = true; #region 内存释放 ho_Regions.Dispose(); #endregion } } } }