核心方案CogMath 静态几何函数无需拖拽额外几何测量工具适合动态循环、多目标批量测量模板定位跟随找线 ROI 场景 业务场景模板匹配多目标 → 动态移动找线 ROI → 逐个计算匹配点到直线垂直距离 OK/NG 判定 图形叠加一、命名空间脚本头部必须引用using System.Collections.Generic; using Cognex.VisionPro; using Cognex.VisionPro.ToolBlock; using Cognex.VisionPro.PMAlign;二、CogMath 静态几何库脚本距离测量核心CogMath是静态类不需要实例化工具直接调用适合循环遍历多目标、动态 ROI 跟随模板定位场景表格方法作用参数说明CogMath.DistancePointPoint点到点欧氏距离x1,y1,x2,y2, out angleCogMath.DistancePointLine点到无限直线垂直距离本次代码核心px,py, CogLine, image, out footX, out footYCogMath.DistancePointSegment点到线段最短距离不是无限延长px,py, CogLineSegment, out footX, footYCogMath.DistanceLineLine两直线距离平行lineA, lineBCogMath.DistancePointCircle点到圆距离px,py,circle⚠️重点区分CogLine数学无限长直线 →DistancePointLine垂直距离适合边基准CogLineSegment有限线段 →DistancePointSegment最短距离垂足落在线段外时取端点【核心代码片段】点到直线距离double footX, footY; double distance1 CogMath.DistancePointLine( pX, //模板匹配点X pY, //模板匹配点Y foundLine, //CogLine找线结果.GetLine()无限直线 image1, //图像对象 out footX, //垂足X输出 out footY //垂足Y输出 );三、高级业务逻辑案例完整流程预先在 ToolBlock 中放入CogPMAlignTool模板匹配、CogFindLineTool找线工具输入端子yy传入灰度图脚本遍历所有 PM 匹配结果pma.Results多目标核心高级点动态修改找线 ROI跟随每个匹配点坐标 姿态实时更新ExpectedLineSegment产品偏移、旋转自动跟随执行Line1.Run()提取直线判空校验lineResults ! null lineResults.Count0防止未找到特征直接崩溃工业脚本必备容错CogMath 计算距离获取垂足坐标公差判定绘制图形到gc图形集合线段标记检测边蓝色垂线匹配点→垂足调试看垂直基准文本打印距离数值找不到线黄色警告文本LineNotFound图形集合gc.Clear()每帧清空防止上一帧图形残留四、高级进阶要点面试 / 项目踩坑1. 像素距离 vs 物理毫米距离CogMath 默认返回像素如果做九点标定要把坐标转到标定空间距离自动转为物理 mm。标定后用CogTransform2D把点 / 线转到世界坐标系再计算距离。2. 【大坑】GetLine()vsGetLineSegment()CogLine foundLine lineResults.GetLine(); //无限数学直线 → DistancePointLine CogLineSegment foundSeg lineResults.GetLineSegment(); //有限线段 → 绘图用很多新手混用导致距离计算结果完全错误。3. 多目标循环的坑Line1是工具块里同一个工具实例循环每一轮都会覆盖RunParams必须在循环内每次重新设置 ROI 再 Run。4. 坐标系问题模板匹配自带 Pose位姿不能只用 TranslationX/Y产品存在旋转时ROI 需要利用 Pose 做坐标变换否则找线 ROI 会随产品旋转而偏移。ROI 随匹配角度旋转 核心代码CogTransform2DLinear pose p.GetPose(); CogPoint2D p1 pose.TransformPoint(new CogPoint2D(-18,0)); CogPoint2D p2 pose.TransformPoint(new CogPoint2D(18,0)); Line1.RunParams.ExpectedLineSegment.StartX p1.X; Line1.RunParams.ExpectedLineSegment.StartY p1.Y; Line1.RunParams.ExpectedLineSegment.EndX p2.X; Line1.RunParams.ExpectedLineSegment.EndY p2.Y;5. 结果输出到 ToolBlock 端子项目常用脚本可以定义数组把每一个匹配目标的距离、OK/NG 存入数组输出到 ToolBlock 输出端子供上位机读取。Listdouble distList new Listdouble(); distList.Add(distance1); mToolBlock.Outputs[DistList].Value distList;五、完整优化版代码修复旋转补偿 输出结果可直接替换你原来脚本using System.Collections.Generic; using Cognex.VisionPro; using Cognex.VisionPro.ToolBlock; using Cognex.VisionPro.PMAlign; using Cognex.VisionPro.LineFind; public override bool Run(CogToolBlock mToolBlock, CogGraphicCollection gc, ref string message, ref CogRecord result) { gc.Clear(); //运行工具块内全部工具 foreach(ICogTool tool in mToolBlock.Tools) { mToolBlock.RunTool(tool, ref message, ref result); } CogPMAlignTool pma mToolBlock.Tools[0] as CogPMAlignTool; CogFindLineTool Line1 mToolBlock.Tools[4] as CogFindLineTool; CogImage8Grey image1 mToolBlock.Inputs[yy].Value as CogImage8Grey; double tolerance 30; Listdouble distResultList new Listdouble(); Listbool okList new Listbool(); foreach(CogPMAlignResult p in pma.Results) { CogTransform2DLinear pose p.GetPose(); //ROI随模板角度自动旋转高级修正 CogPoint2D roiStart pose.TransformPoint(new CogPoint2D(-18,0)); CogPoint2D roiEnd pose.TransformPoint(new CogPoint2D(18,0)); Line1.RunParams.ExpectedLineSegment.StartX roiStart.X; Line1.RunParams.ExpectedLineSegment.StartY roiStart.Y; Line1.RunParams.ExpectedLineSegment.EndX roiEnd.X; Line1.RunParams.ExpectedLineSegment.EndY roiEnd.Y; Line1.RunParams.ExpectedLineSegment.SelectedColor CogColorConstants.Green; Line1.Run(); CogFindLineResults lineResults Line1.Results; if (lineResults ! null lineResults.Count 0) { CogLine foundLine lineResults.GetLine(); CogLineSegment foundSeg lineResults.GetLineSegment(); double pX pose.TranslationX; double pY pose.TranslationY; double footX, footY; double distance1 CogMath.DistancePointLine(pX,pY,foundLine,image1,out footX,out footY); distResultList.Add(distance1); bool isOK distance1 tolerance; okList.Add(isOK); CogLineSegment line2 new CogLineSegment(); line2.Color isOK ? CogColorConstants.Green : CogColorConstants.Red; line2.StartX foundSeg.MidpointX - 28; line2.StartY foundSeg.MidpointY; line2.EndX foundSeg.MidpointX 28; line2.EndY foundSeg.MidpointY; gc.Add(line2); //垂足蓝色线 CogLineSegment perpendicular new CogLineSegment(); perpendicular.Color CogColorConstants.Blue; perpendicular.StartX pX; perpendicular.StartY pY; perpendicular.EndX footX; perpendicular.EndY footY; gc.Add(perpendicular); //文本 CogGraphicLabel txt new CogGraphicLabel(); txt.Text $Dist:{distance1:F3}; txt.X foundSeg.MidpointX; txt.Y foundSeg.MidpointY - 10; txt.Color line2.Color; gc.Add(txt); } else { CogGraphicLabel txtFail new CogGraphicLabel(); txtFail.Text LineNotFound; txtFail.X p.GetPose().TranslationX; txtFail.Y p.GetPose().TranslationY; txtFail.Color CogColorConstants.Yellow; gc.Add(txtFail); distResultList.Add(-1); //-1代表检测失败 okList.Add(false); } } //输出结果到工具块端子 mToolBlock.Outputs[DistanceList].Value distResultList; mToolBlock.Outputs[OKList].Value okList; return true; }这里使用的液面检测的一个VsionPro高级案例比较适合在这样使用完整代码#region namespace imports using System; using System.Collections; using System.Drawing; using System.IO; using System.Windows.Forms; using Cognex.VisionPro; using Cognex.VisionPro.ToolBlock; using Cognex.VisionPro3D; using Cognex.VisionPro.PMAlign; using Cognex.VisionPro.ImageProcessing; using Cognex.VisionPro.Caliper; #endregion public class CogToolBlockAdvancedScript : CogToolBlockAdvancedScriptBase { #region Private Member Variables private Cognex.VisionPro.ToolBlock.CogToolBlock mToolBlock; CogGraphicCollection gc new CogGraphicCollection(); #endregion /// summary /// Called when the parent tool is run. /// Add code here to customize or replace the normal run behavior. /// /summary /// param namemessageSets the Message in the tools RunStatus./param /// param nameresultSets the Result in the tools RunStatus/param /// returnsTrue if the tool should run normally, /// False if GroupRun customizes run behavior/returns public override bool GroupRun(ref string message, ref CogToolResultConstants result) { // To let the execution stop in this script when a debugger is attached, uncomment the following lines. // #if DEBUG // if (System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Break(); // #endif // Run each tool using the RunTool function foreach(ICogTool tool in mToolBlock.Tools) mToolBlock.RunTool(tool, ref message, ref result); gc.Clear(); CogPMAlignTool pma mToolBlock.Tools[0] as CogPMAlignTool; CogFindLineTool Line1 mToolBlock.Tools[4] as CogFindLineTool; CogImage8Grey image1 mToolBlock.Inputs[yy].Value as CogImage8Grey; //CogDistancePointLineTool distance1 mToolBlock.Tools[3] as CogDistancePointLineTool; //CogMath math1 new CogMath(); /* foreach(CogPMAlignResult p in pma.Results) { //Line1.RunParams.ExpectedLineSegment.StartX Line1.RunParams.ExpectedLineSegment.StartX p.GetPose().TranslationX - 8; Line1.RunParams.ExpectedLineSegment.StartY p.GetPose().TranslationY; Line1.RunParams.ExpectedLineSegment.EndX p.GetPose().TranslationX 8; Line1.RunParams.ExpectedLineSegment.EndY p.GetPose().TranslationY; Line1.RunParams.ExpectedLineSegment.SelectedColor CogColorConstants.Green; Line1.Run(); CogFindLineResults lineResults Line1.Results; CogLine foundLine lineResults.GetLine(); //CogDistancePointLineTool distance1 new CogDistancePointLineTool(); double pX p.GetPose().TranslationX; double pY p.GetPose().TranslationY; double footX, footY; double distance1 CogMath.DistancePointLine( pX, pY, foundLine, image1, //传入工具块输入图像 out footX, out footY ); CogLineSegment line2 new CogLineSegment(); line2.Color CogColorConstants.Red; line2.StartX Line1.Results.GetLineSegment().MidpointX - 28; line2.StartY Line1.Results.GetLineSegment().MidpointY; line2.EndX Line1.Results.GetLineSegment().MidpointX 28; line2.EndY Line1.Results.GetLineSegment().MidpointY; gc.Add(line2); } */ // 设置距离公差按需修改 double tolerance 30; foreach(CogPMAlignResult p in pma.Results) { double pX p.GetPose().TranslationX; double pY p.GetPose().TranslationY; // 动态更新找线ROI Line1.RunParams.ExpectedLineSegment.StartX pX - 18; Line1.RunParams.ExpectedLineSegment.StartY pY; Line1.RunParams.ExpectedLineSegment.EndX pX 18; Line1.RunParams.ExpectedLineSegment.EndY pY; Line1.RunParams.ExpectedLineSegment.SelectedColor CogColorConstants.Green; Line1.Run(); CogFindLineResults lineResults Line1.Results; // ✅判空防止找不到线崩溃 if (lineResults ! null lineResults.Count 0) { //CogFindLineResult lineResult lineResults; CogLine foundLine lineResults.GetLine(); CogLineSegment foundSeg lineResults.GetLineSegment(); double footX, footY; double distance1 CogMath.DistancePointLine( pX, pY, foundLine, image1, out footX, out footY ); CogLineSegment line2 new CogLineSegment(); // 根据距离设置颜色 if (distance1 tolerance) { line2.Color CogColorConstants.Red; // NG 红色 } else { line2.Color CogColorConstants.Green; // OK 绿色 } line2.StartX foundSeg.MidpointX - 28; line2.StartY foundSeg.MidpointY; line2.EndX foundSeg.MidpointX 28; line2.EndY foundSeg.MidpointY; gc.Add(line2); //【可选】绘制蓝色垂线PM点→垂足方便调试 CogLineSegment perpendicular new CogLineSegment(); perpendicular.Color CogColorConstants.Blue; perpendicular.StartX pX; perpendicular.StartY pY; perpendicular.EndX footX; perpendicular.EndY footY; gc.Add(perpendicular); //【可选】绘制距离文本 CogGraphicLabel txt new CogGraphicLabel(); txt.Text Dist: distance1.ToString(F3); txt.X foundSeg.MidpointX; txt.Y foundSeg.MidpointY - 10; txt.Color line2.Color; gc.Add(txt); } else { // 本次找线失败可以画黄色提示标记 CogGraphicLabel txtFail new CogGraphicLabel(); txtFail.Text LineNotFound; txtFail.X pX; txtFail.Y pY; txtFail.Color CogColorConstants.Yellow; gc.Add(txtFail); } } return false; } #region When the Current Run Record is Created /// summary /// Called when the current record may have changed and is being reconstructed /// /summary /// param namecurrentRecord /// The new currentRecord is available to be initialized or customized./param public override void ModifyCurrentRunRecord(Cognex.VisionPro.ICogRecord currentRecord) { } #endregion #region When the Last Run Record is Created /// summary /// Called when the last run record may have changed and is being reconstructed /// /summary /// param namelastRecord /// The new last run record is available to be initialized or customized./param public override void ModifyLastRunRecord(Cognex.VisionPro.ICogRecord lastRecord) { foreach(ICogGraphic g in gc) { mToolBlock.AddGraphicToRunRecord(g,lastRecord,CogIPOneImageTool2.OutputImage,); } } #endregion #region When the Script is Initialized /// summary /// Perform any initialization required by your script here /// /summary /// param namehostThe host tool/param public override void Initialize(Cognex.VisionPro.ToolGroup.CogToolGroup host) { // DO NOT REMOVE - Call the base class implementation first - DO NOT REMOVE base.Initialize(host); // Store a local copy of the script host this.mToolBlock ((Cognex.VisionPro.ToolBlock.CogToolBlock)(host)); } #endregion }
阅读完成 · 觉得有帮助?