/* * ============================================================================== * * Filename: PMAlign * Description: * * Version: 1.0 * Created: 2021/3/30 14:07:10 * * Author: liu.wenjie * * ============================================================================== */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using CommonMethods; using HalconDotNet; using ToolBase; using static DataStruct.DataStruct; using System.Windows.Forms; using Logger; using System.Diagnostics; using System.IO; namespace PMAlignTool { [Serializable] public class PMAlign : IToolBase { public string toolName { get; set; } = string.Empty; /// /// 输入姿态 /// public PosXYU inputPose = new PosXYU(); /// /// 制作模板时的输入位姿 /// public PosXYU templatePose = new PosXYU(); /// /// 是否显示匹配到的模板 /// internal bool showTemplate { get; set; } = true; /// /// 是否显示中心十字架 /// internal bool showCross { get; set; } = true; /// /// 是否显示特征 /// internal bool showFeature { get; set; } = true; /// /// 显示结果序号 /// internal bool showIndex { get; set; } = true; /// /// 是否显示搜索区域 /// internal bool showSearchRegion { get; set; } = true; /// /// 模板句柄 /// internal HTuple modelID = -1; /// /// 行列间隔像素数 /// internal int spanPixelNum { get; set; } = 100; /// /// 排序模式 /// // internal SortMode sortMode = SortMode.从上至下且从左至右; /// /// 模板区域 /// internal HObject templateRegion; /// /// 在进行模板创建及匹配时进行的图像预处理 /// public ImagePreProcess imageProcess { get; set; } = new ImagePreProcess(); /// /// 搜索区域图像 /// internal HObject reducedImage; /// /// 最小匹配分数 /// internal double minScore { get; set; } = 0.5; /// /// 匹配个数 /// internal int matchNum { get; set; } = 1; /// /// 起始角度 /// internal int startAngle { get; set; } = -30; /// /// 角度范围 /// internal int angleRange { get; set; } = 30; /// /// 角度步长 /// internal int angleStep { get; set; } = 1; /// /// 对比度 /// internal int contrast { get; set; } = 30; /// /// 训练时所使用的模板图像,不点击获取图像时,不进行更新 /// public HObject oldTrainImage { get; set; } public bool isCreateModel { get; set; } public override void DispMainWindow(HWindow dispHWindow) { if (showFeature) { ShowTemplate(dispHWindow, false); } } /// /// 极性 /// internal string polarity { get; set; } = "use_polarity"; /// /// 工具锁 /// private object obj { get; set; } = new object(); /// /// 模板匹配结果 /// public List L_resultList { get; set; } = new List() { }; /// /// 匹配模式 /// public MatchMode matchMode { get; set; } = MatchMode.BasedShape; /// /// 缩放最小值 /// public HTuple minScale { get; internal set; } = 0.9; /// /// 缩放最大值 /// public HTuple maxScale { get; internal set; } = 1.1; public bool isAutoConstants { get; set; } public string modelFilePath { get; set; } public RegionType searchRegionType { get; set; } public HObject SearchRegion { get; private set; } public override void Run(SoftwareRunState softwareRunState) { Stopwatch sw = new Stopwatch(); sw.Restart(); if (inputImage == null) { FormPMAlignTool.Instance.SetToolStatus("工具输入图像为空", ToolRunStatu.Not_Input_Image); return; } try { if (softwareRunState == SoftwareRunState.Debug) { DispImage(); } if (inputPose != null) { HTuple Row = inputPose.X - templatePose.X; HTuple Col = inputPose.Y - templatePose.Y; HTuple angle = inputPose.U - templatePose.U; HTuple _homMat2D; HOperatorSet.HomMat2dIdentity(out _homMat2D); HOperatorSet.HomMat2dRotate(_homMat2D, (HTuple)(angle), (HTuple)templatePose.X, (HTuple)templatePose.Y, out _homMat2D); HOperatorSet.HomMat2dTranslate(_homMat2D, (HTuple)(Row), (HTuple)(Col), out _homMat2D); //对预期线的找模板区域做放射变换 } minScore = FormPMAlignTool.Instance.nud_minScore.Value; startAngle = Convert.ToInt16(FormPMAlignTool.Instance.nud_angleStart.Value); angleRange = Convert.ToInt16(FormPMAlignTool.Instance.nud_angleRange.Value); angleStep = Convert.ToInt16(FormPMAlignTool.Instance.nud_angleStep.Value); polarity = FormPMAlignTool.Instance.cbx_polarity.TextStr; isAutoConstants = FormPMAlignTool.Instance.ckb_autoContrast.Checked; minScale = FormPMAlignTool.Instance.nud_ScaleStart.Value; maxScale = FormPMAlignTool.Instance.nud_ScaleRange.Value; HObject findModelImg = ProcessImage(inputImage); int ret = FindModelTemplate(findModelImg); ToolRunStatu myState = ret == 0 ? ToolRunStatu.Succeed : ToolRunStatu.Model_UnFound; string retMsg = ret == 0 ? "工具运行成功,已找到匹配项!" : "未找到匹配项"; sw.Stop(); runTime = $"运行时间: {sw.ElapsedMilliseconds} ms"; FormPMAlignTool.Instance.SetToolStatus(retMsg, myState); } catch (Exception ex) { FormPMAlignTool.Instance.SetToolStatus($"工具运行异常,异常原因: {ex}", ToolRunStatu.Tool_Run_Error); } finally { } } public override void DispImage() { FormPMAlignTool.Instance.myHwindow.DispHWindow.ClearWindow(); if (inputImage != null) { FormPMAlignTool.Instance.myHwindow.DispHWindow.DispObj(inputImage); } } private void CreateModelRegion() { HOperatorSet.GenEmptyObj(out templateRegion); foreach (var item in FormPMAlignTool.Instance.templateModelListAdd) { HObject selectObj = item.GetDrawingObjectIconic(); HOperatorSet.Union2(selectObj, templateRegion, out templateRegion); } foreach (var item in FormPMAlignTool.Instance.templateModelListSub) { HObject selectObj = item.GetDrawingObjectIconic(); HOperatorSet.Difference(templateRegion, selectObj, out templateRegion); } } public int CreateModelTemplate() { HObject template; oldTrainImage = inputImage; if (FormPMAlignTool.Instance.templateModelListAdd.Count == 0) { LoggerClass.WriteLog("未划定模板建立区域", MsgLevel.Exception); isCreateModel = false; return -1; } CreateModelRegion(); HObject createModelImg; HOperatorSet.GenEmptyObj(out createModelImg); createModelImg = ProcessImage(inputImage); HOperatorSet.ReduceDomain(createModelImg, templateRegion, out template); try { HTuple rows, cols, angles, scores, scale; if (matchMode == MatchMode.BasedShape) { HOperatorSet.CreateScaledShapeModel(template, "auto", ((HTuple)startAngle).TupleRad(), ((HTuple)angleRange).TupleRad(), "auto", minScale, maxScale, "auto", "auto", polarity, isAutoConstants ? (HTuple)"auto" : (HTuple)contrast, "auto", out modelID); HOperatorSet.FindScaledShapeModel(inputImage, (HTuple)modelID, ((HTuple)startAngle).TupleRad(), ((HTuple)angleRange - startAngle).TupleRad(), minScale, maxScale, (HTuple)minScore, (HTuple)matchNum, (HTuple)0.5, (HTuple)"least_squares", (HTuple)0, (HTuple)0.9, out rows, out cols, out angles, out scale, out scores); } else { HOperatorSet.CreateNccModel(template, "auto", ((HTuple)startAngle).TupleRad(), ((HTuple)angleRange).TupleRad(), "auto", "use_polarity", out modelID); HOperatorSet.FindNccModel(inputImage, (HTuple)modelID, ((HTuple)startAngle).TupleRad(), ((HTuple)angleRange - startAngle).TupleRad(), (HTuple)minScore, (HTuple)matchNum, (HTuple)0.5, (HTuple)"true", (HTuple)0, out rows, out cols, out angles, out scores); } isCreateModel = true; HOperatorSet.WriteRegion(templateRegion, FormPMAlignTool.Instance.myToolInfo.FormToolName + ".hobj"); if (scores != null && scores.Type != HTupleType.EMPTY) { templatePose = new PosXYU { X = rows[0].D, Y = cols[0].D , U = angles[0].D }; } } catch (Exception ex) { Logger.LoggerClass.WriteLog("创建模板时出现异常", ex); isCreateModel = false; return -1; } finally { FormPMAlignTool.Instance.templateModelListAdd.Clear(); FormPMAlignTool.Instance.templateModelListSub.Clear(); } return 0; } public int FindModelTemplate(HObject findModelImage) { if (!isCreateModel) { LoggerClass.WriteLog("未创建或加载模板", MsgLevel.Exception); return -1; } if (File.Exists(toolName + ".hobj")) { HOperatorSet.ReadRegion(out templateRegion, toolName + ".hobj"); LoggerClass.WriteLog($"{FormPMAlignTool.Instance.myToolInfo.FormToolName} 已加载模板", MsgLevel.Info); } HObject image; if (searchRegionType == RegionType.AllImage) { image = findModelImage; } else { HOperatorSet.ReduceDomain(inputImage, SearchRegion, out reducedImage); image = reducedImage; } HTuple rows, cols, angles, scores; L_resultList.Clear(); try { if (matchMode == MatchMode.BasedShape) { HTuple temp; HOperatorSet.FindScaledShapeModel(image, (HTuple)modelID, ((HTuple)startAngle).TupleRad(), ((HTuple)angleRange - startAngle).TupleRad(), minScale, maxScale, (HTuple)minScore, (HTuple)matchNum, (HTuple)0.5, (HTuple)"least_squares", (HTuple)0, (HTuple)0.9, out rows, out cols, out angles, out temp, out scores); } else { HOperatorSet.FindNccModel(image, (HTuple)modelID, ((HTuple)startAngle).TupleRad(), ((HTuple)angleRange - startAngle).TupleRad(), (HTuple)minScore, (HTuple)matchNum, (HTuple)0.5, (HTuple)"true", (HTuple)0, out rows, out cols, out angles, out scores); } FormPMAlignTool.Instance.myHwindow.DispHWindow.ClearWindow(); FormPMAlignTool.Instance.myHwindow.DispImage(inputImage); if (rows.TupleLength() > 0) { for (int i = 0; i < rows.TupleLength(); i++) { MatchResult matchResult = new MatchResult(); matchResult.Row = Math.Round((double)rows[i], 3); matchResult.Col = Math.Round((double)cols[i], 3); matchResult.Angle = Math.Round((double)angles[i], 3); matchResult.Socre = Math.Round((double)scores[i], 3); L_resultList.Add(matchResult); } MatchResult temp; for (int i = 0; i < L_resultList.Count - 1; i++) { for (int j = i + 1; j < L_resultList.Count; j++) { if (L_resultList[i].Socre < L_resultList[j].Socre) { temp = L_resultList[i]; L_resultList[i] = L_resultList[j]; L_resultList[j] = temp; } } } } if(L_resultList.Count > 0) { toolRunStatu = ToolRunStatu.Succeed; ShowTemplate(FormPMAlignTool.Instance.myHwindow.DispHWindow); return 0; } } catch (Exception ex) { LoggerClass.WriteLog("寻找模板时出现异常!", ex); toolRunStatu = ToolRunStatu.Not_Succeed; } return -1; } public HObject contour; /// /// 显示模板 /// internal void ShowTemplate(HWindow dispHWindow, bool clearImg = false) { try { if (modelID == null) { return; } if(clearImg) { dispHWindow.ClearWindow(); dispHWindow.DispObj(inputImage); } if (matchMode == MatchMode.BasedShape) { HOperatorSet.GetShapeModelContours(out contour, modelID, new HTuple(1)); HTuple area, row, col; HOperatorSet.AreaCenter(templateRegion, out area, out row, out col); HTuple homMat2D; HOperatorSet.HomMat2dIdentity(out homMat2D); HOperatorSet.HomMat2dTranslate(homMat2D, row, col, out homMat2D); HOperatorSet.AffineTransContourXld(contour, out contour, homMat2D); dispHWindow.SetColor("green"); dispHWindow.DispObj(contour); } HObject outBoundary, inBoundary; HOperatorSet.Boundary(templateRegion, out outBoundary, "inner_filled"); HOperatorSet.Boundary(templateRegion, out inBoundary, "outer"); HOperatorSet.SetColor(FormPMAlignTool.Instance.myHwindow.DispHWindow, "green"); HOperatorSet.SetLineStyle(FormPMAlignTool.Instance.myHwindow.DispHWindow, new HTuple()); dispHWindow.DispObj(outBoundary); dispHWindow.DispObj(inBoundary); } catch (Exception ex) { Logger.LoggerClass.WriteLog("显示模板时出现错误", ex); } } private HObject ProcessImage(HObject inputImg) { if (inputImage == null) return inputImage; if (imageProcess.erosionValue1.isEnable) { HOperatorSet.GrayErosionShape(inputImg, out inputImg, imageProcess.erosionValue1.algValue, imageProcess.erosionValue1.algValue, imageProcess.erosionValue1.algName); } if (imageProcess.dilationValue.isEnable) { HOperatorSet.GrayDilationShape(inputImg, out inputImg, imageProcess.erosionValue1.algValue, imageProcess.erosionValue1.algValue, imageProcess.dilationValue.algName); } if (imageProcess.erosionValue2.isEnable) { HOperatorSet.GrayErosionShape(inputImg, out inputImg, imageProcess.erosionValue1.algValue, imageProcess.erosionValue1.algValue, imageProcess.erosionValue2.algName); } return inputImg; } } [Serializable] public class ImagePreProcess { public ProcessAlg erosionValue1 { get; set; } = new ProcessAlg(); public ProcessAlg dilationValue { get; set; } = new ProcessAlg(); public ProcessAlg erosionValue2 { get; set; } = new ProcessAlg(); } [Serializable] public class ProcessAlg { public double algValue { get; set; } = 0; public bool isEnable { get; set; } = false; public string algName { get; set; } = "rectangle"; } [Serializable] public enum MatchMode { BasedShape, BasedGray, } [Serializable] public enum RegionType { AllImage, Rectangle1, Rectangle2, Circle, Ellipse, MultPoint, Ring, Any, } /// /// 模板匹配结果 /// [Serializable] public struct MatchResult { internal double Row; internal double Col; internal double Angle; internal double Socre; } }