/* * ============================================================================== * * 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.DataStructClass; using System.Windows.Forms; using Logger; using System.Diagnostics; using System.IO; using ViewROI; using DataStruct; namespace PMAlignTool { [Serializable] public class PMAlign : IToolBase { /// /// 绑定job名称 /// public string bingdingJobName { get; set; } /// /// 工具名称 /// 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; } = 360; /// /// 角度步长 /// internal int angleStep { get; set; } = 1; /// /// 对比度 /// internal int contrast { get; set; } = 30; /// /// 超时处理 /// internal int timeOut { get; set; } = 500; /// /// 训练时所使用的模板图像,不点击获取图像时,不进行更新 /// [NonSerialized] public HObject oldTrainImage; public bool isCreateModel { get; set; } internal string pmaModelName { get; set; } = Guid.NewGuid().ToString(); /// /// 剪出的模板图像 /// [NonSerialized] public HObject modelPartImage = new HObject(); /// /// 模板位置和实际位置的姿态差异 /// internal HTuple posHomMat2D = new HTuple(); public override void DispMainWindow(HWindowTool_Smart 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 string trainImgPath, trainShmPath, trainModelPath, dataDirectory; [NonSerialized] public HObject SearchRegion; public void InitTool() { trainImgPath = ConfigData.ConfigPath + $"\\{bingdingJobName}\\{toolName}_{pmaModelName}_TrainImage.bmp"; trainShmPath = ConfigData.ConfigPath + $"\\{bingdingJobName}\\{toolName}_{pmaModelName}.Shm"; trainModelPath = ConfigData.ConfigPath + $"\\{bingdingJobName}\\{toolName}_{pmaModelName}_ModelImage.bmp"; dataDirectory = ConfigData.ConfigPath + $"\\{bingdingJobName}\\"; } public override void Run(SoftwareRunState softwareState) { Stopwatch sw = new Stopwatch(); sw.Restart(); softwareRunState = softwareState; if (inputImage == null) { toolRunStatu = ToolRunStatu.Lack_Of_Input_Image; runMessage = "工具输入图像为空"; FormPMAlignTool.Instance.SetToolStatus(runMessage, toolRunStatu); 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); //对预期线的找模板区域做放射变换 } HObject findModelImg = ProcessImage(inputImage); int ret = FindModelTemplate(findModelImg); UpdateResultDataGridview(); ToolRunStatu myState = ret == 0 ? ToolRunStatu.Succeed : ToolRunStatu.Model_UnFound; toolRunStatu = myState; string retMsg = ret == 0 ? $"{toolName}工具运行成功,已找到匹配项!" : $"{toolName}未找到匹配项"; runMessage = retMsg; sw.Stop(); runTime = $"运行时间: {sw.ElapsedMilliseconds} ms"; FormPMAlignTool.Instance.SetToolStatus(retMsg, myState); } catch (Exception ex) { FormPMAlignTool.Instance.SetToolStatus($"{toolName}工具运行异常,异常原因: {ex}", ToolRunStatu.Tool_Run_Error); } finally { } } public void UpdateResultDataGridview() { FormPMAlignTool.Instance.dgv_matchResult.Rows.Clear(); //FormPMAlignTool.Instance.dgv_matchResult.Columns.Clear(); //FormPMAlignTool.Instance.dgv_matchResult.Columns.Add("num", "序号"); //FormPMAlignTool.Instance.dgv_matchResult.Columns.Add("Socre", "分值"); //FormPMAlignTool.Instance.dgv_matchResult.Columns.Add("Row", "行"); //FormPMAlignTool.Instance.dgv_matchResult.Columns.Add("Col", "列"); //FormPMAlignTool.Instance.dgv_matchResult.Columns.Add("Angle", "角度"); int count = 0; foreach (var item in L_resultList) { FormPMAlignTool.Instance.dgv_matchResult.Rows.Add(++count, item.Socre, item.Row, item.Col, item.Angle); } } public void UpdateParamsFromUI() { 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; timeOut = Convert.ToInt16(FormPMAlignTool.Instance.nud_Timeout.Value); contrast = Convert.ToInt16(FormPMAlignTool.Instance.tkb_contrast.Value); } 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 void SetParamsFromUI() { 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; } public int CreateModelTemplate(bool setInputModelRegion, HObject inputModelRegion) { HObject template; oldTrainImage = inputImage; // 判断是否从外部输入模板 if(setInputModelRegion) { templateRegion = inputModelRegion; } else { if (FormPMAlignTool.Instance.templateModelListAdd.Count == 0) { LoggerClass.WriteLog($"{toolName}未划定模板建立区域", MsgLevel.Exception); isCreateModel = false; return -1; } CreateModelRegion(); } HObject createModelImg; HOperatorSet.GenEmptyObj(out createModelImg); createModelImg = ProcessImage(inputImage); HOperatorSet.ReduceDomain(createModelImg, templateRegion, out template); HOperatorSet.CropDomain(template, out modelPartImage); //SetParamsFromUI(); try { HTuple rows, cols, angles, scores, scale; if (matchMode == MatchMode.BasedShape) { HOperatorSet.CreateShapeModel(template, "auto", 0, 360, "auto", "auto", polarity, isAutoConstants ? (HTuple)"auto" : (HTuple)contrast, "auto", out modelID); HOperatorSet.FindShapeModel(createModelImg, (HTuple)modelID, ((HTuple)startAngle).TupleRad(), ((HTuple)angleRange - startAngle).TupleRad(), (HTuple)minScore, (HTuple)matchNum, (HTuple)0.5, (HTuple)"least_squares", (HTuple)0, (HTuple)0.9, out rows, out cols, out angles, out scores); } else { HOperatorSet.CreateNccModel(template, "auto", ((HTuple)startAngle).TupleRad(), ((HTuple)angleRange).TupleRad(), "auto", "use_polarity", out modelID); HOperatorSet.FindNccModel(createModelImg, (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; // 模板句柄信息 Directory.CreateDirectory(dataDirectory); HOperatorSet.WriteShapeModel(modelID, trainShmPath); HOperatorSet.WriteImage(inputImage, "bmp", 0, trainImgPath); HOperatorSet.WriteImage(modelPartImage, "bmp", 0, trainModelPath); 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($"{toolName}创建模板时出现异常", ex); isCreateModel = false; return -1; } finally { // FormPMAlignTool.Instance.templateModelListAdd.Clear(); // FormPMAlignTool.Instance.templateModelListSub.Clear(); } return 0; } public int FindModelTemplate(HObject findModelImage) { if (!File.Exists(trainShmPath)) { LoggerClass.WriteLog($"{toolName}未创建或加载模板", MsgLevel.Exception); return -1; } HOperatorSet.ReadShapeModel(trainShmPath, out modelID); 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 { image = ProcessImage(image); if (matchMode == MatchMode.BasedShape) { HTuple temp; HOperatorSet.FindShapeModel(image, (HTuple)modelID, ((HTuple)startAngle).TupleRad(), ((HTuple)angleRange - startAngle).TupleRad(), (HTuple)minScore, (HTuple)matchNum, (HTuple)0.5, (HTuple)"least_squares", (HTuple)0, (HTuple)0.7, out rows, out cols, out angles, out scores); /* 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); } 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; } } } HOperatorSet.VectorAngleToRigid(templatePose.X, templatePose.Y, templatePose.U, L_resultList[0].Row, L_resultList[0].Col, L_resultList[0].Angle, out posHomMat2D); } if (softwareRunState == SoftwareRunState.Debug) { FormPMAlignTool.Instance.myHwindow.DispHWindow.ClearWindow(); FormPMAlignTool.Instance.myHwindow.DispImage(inputImage); } if (L_resultList.Count > 0) { toolRunStatu = ToolRunStatu.Succeed; if (softwareRunState == SoftwareRunState.Debug) { ShowTemplate(FormPMAlignTool.Instance.myHwindow); } return 0; } } catch (Exception ex) { LoggerClass.WriteLog($"{toolName}寻找模板时出现异常!", ex); toolRunStatu = ToolRunStatu.Not_Succeed; } return -1; } public HObject contour; /// /// 显示模板 /// internal void ShowTemplate(HWindowTool_Smart dispHWindow, bool clearImg = false) { try { if (modelID == null) { return; } if(clearImg) { dispHWindow.DispHWindow.ClearWindow(); dispHWindow.DispImage(inputImage); } if(L_resultList.Count > 0) { foreach (var item in L_resultList) { HTuple homMat2D; HOperatorSet.GetShapeModelContours(out contour, modelID, new HTuple(1)); HOperatorSet.VectorAngleToRigid(0, 0, 0, item.Row, item.Col, item.Angle,out homMat2D); HOperatorSet.AffineTransContourXld(contour, out contour, homMat2D); dispHWindow.DispHWindow.SetColor("green"); dispHWindow.DispHWindow.DispObj(contour); } } } catch (Exception ex) { Logger.LoggerClass.WriteLog($"{toolName}显示模板时出现错误", 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; } }