VisionPro项目记录2 —— 不规则胶路检测

article/2025/7/23 1:05:40

简介

本文介绍了一种基于Cognex视觉工具的胶路检测方法,分为直线和弧形两部分检测。

直线部分采用卡尺工具检测胶路宽度,通过动态调整仿射矩形区域进行多位置测量;弧形部分使用blob工具沿圆周设置检测区域。

两种方法均通过脚本实现工具映射、参数绑定和结果分析功能,支持调试模式显示检测区域和结果标注。

通过try-catch异常处理机制确保检测过程稳定,直线部分可检测断胶情况,弧形部分通过径向补偿实现圆周检测。

此方法具有参数可调性,可根据实际需求灵活配置工具组合和检测参数,适用于不同形状胶路的自动化检测需求。

效果总览

工具

使用结果分析工具输出总结果

直线部分

工具及参数

只用了最基础的模板和定位,卡尺工具是主体。

自定义参数可根据项目需求灵活配置

脚本

映射所有工具并运行,初始化所需参数并与输入参数完成绑定。

创建仿射矩形对象并配置参数,注释的部分为调试用途

调试时取消代码注释,调整步距参数,检查矩形的尺寸、位置和角度是否符合预期效果。

使用try-catch语句能够有效避免因断胶导致卡尺搜索失败时程序报错中断,从而确保后续代码和工具的正常执行。

添加了文字显示功能,采用方法重载的方式实现。通过定义两个同名方法,可以根据需要灵活选择不同的显示效果。

脚本源码

#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.CalibFix;
using Cognex.VisionPro.Caliper;
#endregionpublic class CogToolBlockAdvancedScript : CogToolBlockAdvancedScriptBase
{#region Private Member Variablesprivate Cognex.VisionPro.ToolBlock.CogToolBlock mToolBlock;private 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 name="message">Sets the Message in the tool's RunStatus.</param>/// <param name="result">Sets the Result in the tool's RunStatus</param>/// <returns>True 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 运行所有工具那行代码删了CogPMAlignTool pma = mToolBlock.Tools["CogPMAlignTool1"]as CogPMAlignTool;CogFixtureTool fix = mToolBlock.Tools["CogFixtureTool1"]as CogFixtureTool;CogCaliperTool cal = mToolBlock.Tools["CogCaliperTool1"]as CogCaliperTool;gc.Clear();pma.Run();fix.Run();cal.Run();// 给输出的结果初始化为falsemToolBlock.Outputs["FlowResult"].Value = false;bool FlowResult = true;// 初始化参数并与输入参数绑定double max = 0,min = 100,Pitch = (double) mToolBlock.Inputs["Pitch"].Value,StartX = (double) mToolBlock.Inputs["StartX"].Value,StartY = (double) mToolBlock.Inputs["StartY"].Value,SearchLength = (double) mToolBlock.Inputs["SearchLength"].Value,CaliperLengthX = (double) mToolBlock.Inputs["CaliperLengthX"].Value,CaliperLengthY = (double) mToolBlock.Inputs["CaliperLengthY"].Value,CaliperRotation = (double) mToolBlock.Inputs["CaliperRotation"].Value,SearchAngle = (double) mToolBlock.Inputs["SearchAngle"].Value,scale = (double) mToolBlock.Inputs["scale"].Value;int TestCount = (int) mToolBlock.Inputs["TestCount"].Value;bool breakLine = true;if (pma.RunStatus.Result == CogToolResultConstants.Accept){for (int i = 0; i < (SearchLength / Pitch) && i < TestCount; i++){ double CaliperDegrees = CaliperRotation * Math.PI / 180;double SearchDegrees = SearchAngle * Math.PI / 180;CogRectangleAffine rect = new CogRectangleAffine();rect.Rotation = CaliperDegrees;rect.CenterX = StartX - i * Pitch * Math.Sin(SearchDegrees);rect.CenterY = StartY + i * Pitch * Math.Cos(SearchDegrees);rect.SideXLength = Convert.ToInt32(mToolBlock.Inputs["CaliperLengthX"].Value);rect.SideYLength = Convert.ToInt32(mToolBlock.Inputs["CaliperLengthY"].Value);// 测试用显示矩形位置//rect.CenterX = pma.Results[0].GetPose().TranslationX + StartX - i * Pitch * Math.Sin(SearchDegrees);//rect.CenterY = pma.Results[0].GetPose().TranslationY + StartY + i * Pitch * Math.Cos(SearchDegrees);//gc.Add(rect);//MessageBox.Show("X坐标:" + rect.CenterX.ToString() + "Y坐标:" + rect.CenterY.ToString());// 把矩形给到卡尺的搜索范围并运行卡尺工具cal.Region = rect;cal.Run();max = max < (cal.Results[0].Width * scale) ? (cal.Results[0].Width * scale) : max;min = min > (cal.Results[0].Width * scale) ? (cal.Results[0].Width * scale) : min;//MessageBox.Show(max.ToString());try {	  if(cal.RunStatus.Result == CogToolResultConstants.Accept){if(((double) (cal.Results[0].Width * scale) > (double) mToolBlock.Inputs["WidthMax"].Value)|| ((double) (cal.Results[0].Width * scale) < (double) mToolBlock.Inputs["WidthMin"].Value)){AddLabel(pma.Results[0].GetPose().TranslationX + cal.Region.CenterX, pma.Results[0].GetPose().TranslationY + cal.Region.CenterY, "" + (cal.Results[0].Width * scale).ToString("f1"), CogColorConstants.Red);FlowResult = false;}else{AddLabel(pma.Results[0].GetPose().TranslationX + cal.Region.CenterX, pma.Results[0].GetPose().TranslationY + cal.Region.CenterY, "" + (cal.Results[0].Width * scale).ToString("f1"), CogColorConstants.Green);}}}catch (Exception){breakLine = false;AddLabel(pma.Results[0].GetPose().TranslationX + cal.Region.CenterX, pma.Results[0].GetPose().TranslationY + cal.Region.CenterY, "NG", CogColorConstants.Red);// MessageBox.Show("卡尺g了");// 继续执行或终止循环, 如果需要终止检测,可添加: return false;}}}AddLabel(520, 50, breakLine ? " " : "直线部分断胶", breakLine);AddLabel(520, 100, "直线部分最小值" + min.ToString("f1"), true);AddLabel(520, 150, "直线部分最大值" + max.ToString("f1"), true);mToolBlock.Outputs["FlowResult"].Value = FlowResult;return false;}// 添加文本方法private void AddLabel (double x, double y, string text, bool b){CogGraphicLabel label = new CogGraphicLabel();label.BackgroundColor = CogColorConstants.None;label.Color = b ? CogColorConstants.Green : CogColorConstants.Red;label.Font = new Font("楷体", 20);label.SetXYText(x, y, text);gc.Add(label);}private void AddLabel (double x, double y, string text, CogColorConstants color){CogGraphicLabel label = new CogGraphicLabel();label.BackgroundColor = CogColorConstants.None;label.Color = color;label.Font = new Font("楷体", 6);label.SetXYText(x, y, text);gc.Add(label);}#region When the Current Run Record is Created/// <summary>/// Called when the current record may have changed and is being reconstructed/// </summary>/// <param name="currentRecord">/// 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 Createdpublic override void ModifyLastRunRecord(Cognex.VisionPro.ICogRecord lastRecord){foreach (ICogGraphic item in gc){mToolBlock.AddGraphicToRunRecord(item, lastRecord, "CogPMAlignTool1.InputImage", "");}}#endregion#region When the Script is Initialized/// <summary>/// Perform any initialization required by your script here/// </summary>/// <param name="host">The host tool</param>public override void Initialize(Cognex.VisionPro.ToolGroup.CogToolGroup host){// DO NOT REMOVE - Call the base class implementation first - DO NOT REMOVEbase.Initialize(host);// Store a local copy of the script hostthis.mToolBlock = ((Cognex.VisionPro.ToolBlock.CogToolBlock)(host));}#endregion}

圆形部分

工具及参数

同直线部分一样,blob工具是核心

同上

调试的时候同样把相应的代码打开并调小步距。

脚本

同上

脚本源码

#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.CalibFix;
using Cognex.VisionPro.Caliper;
using Cognex.VisionPro.Blob;
#endregionpublic class CogToolBlockAdvancedScript : CogToolBlockAdvancedScriptBase
{#region Private Member Variablesprivate Cognex.VisionPro.ToolBlock.CogToolBlock mToolBlock;private 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 name="message">Sets the Message in the tool's RunStatus.</param>/// <param name="result">Sets the Result in the tool's RunStatus</param>/// <returns>True 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 运行所有工具那行代码删了CogPMAlignTool pma1 = mToolBlock.Tools["CogPMAlignTool1"]as CogPMAlignTool;CogFixtureTool fix1 = mToolBlock.Tools["CogFixtureTool1"]as CogFixtureTool;CogFindCircleTool cir1 = mToolBlock.Tools["CogFindCircleTool1"]as CogFindCircleTool;CogBlobTool blob1 = mToolBlock.Tools["CogBlobTool1"]as CogBlobTool;gc.Clear();pma1.Run();fix1.Run();cir1.Run();blob1.Run();// 给输出的结果初始化为falsemToolBlock.Outputs["FlowResult"].Value = false;bool FlowResult = true;// 初始化参数并与输入参数绑定double Pitch = (double) mToolBlock.Inputs["Pitch"].Value,             // 步长StartArc = (double) mToolBlock.Inputs["StartArc"].Value,       // 开始角度SearchAngle = (double) mToolBlock.Inputs["SearchAngle"].Value, // 搜索范围BlobLengthX = (double) mToolBlock.Inputs["BlobLengthX"].Value, // 矩形长BlobLengthY = (double) mToolBlock.Inputs["BlobLengthY"].Value, // 矩形宽scale = (double) mToolBlock.Inputs["scale"].Value;             // 缩放系数int TestCount = (int) mToolBlock.Inputs["TestCount"].Value,      // 循环次数限制RadiusCompensate = (int) mToolBlock.Inputs["RadiusCompensate"].Value; // 半径补偿// 主循环:生成仿射矩形并检测for (int i = 0; i < SearchAngle/Pitch && i < TestCount; i++){// 计算当前角度(度转弧度)double currentAngleDegrees = StartArc + i * Pitch;double currentAngleRadians = currentAngleDegrees * Math.PI / 180;// 创建仿射矩形(短边垂直于切线使矩形指向圆心)CogRectangleAffine rect = new CogRectangleAffine();rect.SideXLength = BlobLengthX;rect.SideYLength = BlobLengthY;rect.Rotation = currentAngleRadians;  // 短边与半径方向一致// 计算矩形中心位置rect.CenterX = cir1.Results.GetCircle().CenterX + (cir1.Results.GetCircle().Radius + RadiusCompensate) * Math.Cos(currentAngleRadians);rect.CenterY = cir1.Results.GetCircle().CenterY + (cir1.Results.GetCircle().Radius + RadiusCompensate) * Math.Sin(currentAngleRadians);blob1.Region = rect;blob1.Run();// 调试显示矩形位置//rect.CenterX = pma1.Results[0].GetPose().TranslationX + cir1.Results.GetCircle().CenterX +    //  (cir1.Results.GetCircle().Radius + RadiusCompensate) * Math.Cos(currentAngleRadians);//rect.CenterY = pma1.Results[0].GetPose().TranslationY + cir1.Results.GetCircle().CenterY +     //  (cir1.Results.GetCircle().Radius + RadiusCompensate) * Math.Sin(currentAngleRadians);//gc.Add(rect);try{if(blob1.Results.GetBlobs().Count > 0){AddLabel(pma1.Results[0].GetPose().TranslationX + rect.CenterX, pma1.Results[0].GetPose().TranslationY + rect.CenterY, "OK", true);}else{AddLabel(pma1.Results[0].GetPose().TranslationX + rect.CenterX, pma1.Results[0].GetPose().TranslationY + rect.CenterY, "NG", false);FlowResult = false;}}catch{AddLabel(pma1.Results[0].GetPose().TranslationX + cir1.Results.GetCircle().CenterX + rect.CenterX, pma1.Results[0].GetPose().TranslationY + cir1.Results.GetCircle().CenterY + rect.CenterY, "None", false);continue;}}//MessageBox.Show(angleRadians.ToString());AddLabel(520, 200, FlowResult ? " " : "圆形部分断胶", FlowResult ? CogColorConstants.Green : CogColorConstants.Red);mToolBlock.Outputs["FlowResult"].Value = FlowResult;return false;}// 添加文本方法private void AddLabel (double x, double y, string text, bool b){CogGraphicLabel label = new CogGraphicLabel();label.BackgroundColor = CogColorConstants.None;label.Color = b ? CogColorConstants.Green : CogColorConstants.Red;label.Font = new Font("楷体", 10);label.SetXYText(x, y, text);gc.Add(label);}private void AddLabel (double x, double y, string text, CogColorConstants color){CogGraphicLabel label = new CogGraphicLabel();label.BackgroundColor = CogColorConstants.None;label.Color = color;label.Font = new Font("楷体", 20);label.SetXYText(x, y, text);gc.Add(label);}#region When the Current Run Record is Created/// <summary>/// Called when the current record may have changed and is being reconstructed/// </summary>/// <param name="currentRecord">/// 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 name="lastRecord">/// The new last run record is available to be initialized or customized.</param>public override void ModifyLastRunRecord(Cognex.VisionPro.ICogRecord lastRecord){foreach (ICogGraphic item in gc){mToolBlock.AddGraphicToRunRecord(item, lastRecord, "CogPMAlignTool1.InputImage", "");}}#endregion#region When the Script is Initialized/// <summary>/// Perform any initialization required by your script here/// </summary>/// <param name="host">The host tool</param>public override void Initialize(Cognex.VisionPro.ToolGroup.CogToolGroup host){// DO NOT REMOVE - Call the base class implementation first - DO NOT REMOVEbase.Initialize(host);// Store a local copy of the script hostthis.mToolBlock = ((Cognex.VisionPro.ToolBlock.CogToolBlock)(host));}#endregion}


http://www.hkcw.cn/article/DcIExwnKaW.shtml

相关文章

STM32F407寄存器操作(多通道单ADC+DMA)

1.前言 又是半年没更新了&#xff0c;趁着端午放假有点时间&#xff0c;并且最近项目要用这块知识&#xff0c;我就顺带研究一下ADC吧。 一般来说ADC主要用法包含了1.单通道软件触发&#xff08;这是最简单和最常用的用法&#xff09;2.单通道多次采集&#xff08;需要快速采…

RuoYi前后端分离框架实现前后端数据传输加密(二)之前端篇

一、背景 本文是RuoYi前后端分离框架实现前后端数据传输加密(一)之后端篇文章配套的,主要介绍前端对自定义字段传输加密的实现,两篇文章结合可以完整的完成RuoYi前后端分离框架对API通信过程中实现自定义字段加密传输。前端的加解密实现,不涉及到界面的修改,仅仅是方法的…

马斯克称不想为美政府所做一切担责 “政府效率部”成替罪羊

美国企业家埃隆马斯克在接受哥伦比亚广播公司采访时表达了对政府的看法。他表示自己并不想公开反对美国政府,但也不愿意为政府所做的一切承担责任。马斯克提到,他领导的“政府效率部”成了所有问题的替罪羊,所有的裁员无论真假都被归咎于这个部门。马斯克还表示,他对国会共…

苏超第三轮全部战罢 南通队强势领跑

6月1日晚9时28分,江苏省城市足球联赛第三轮结束。本轮赛事分为两个比赛日进行。5月31日,镇江队0∶2不敌宿迁队,常州队0∶1负于扬州队,徐州队2∶1战胜连云港队。6月1日,盐城队1∶0击败淮安队,泰州队0∶4输给南通队,南京队与无锡队的比赛以1∶0结束。本轮联赛中,南通队和…

节后粽子有买三送一还有6折出售 促销力度大吸引顾客

作为传统节令食品,粽子在今年端午节期间再次成为餐桌主角。与往年不同的是,除了经典的“咸甜之争”外,“低卡”、“低脂”等健康概念成为今年粽子市场的新亮点。据《2025中国粽子行业白皮书》,从规模上来看,2025年中国粽子行业市场规模将达到110亿元,增长率在7%左右,产量…

泽连斯基再提乌俄领导人会晤 需达成具体协议

据法新社报道,俄罗斯总统新闻秘书佩斯科夫周三对乌克兰总统泽连斯基呼吁举行美俄乌三国领导人会谈一事作出回应。佩斯科夫表示,只有在俄乌双方达成具体协议后,才有可能举行此类会谈。他强调,这样的会谈应是乌克兰和俄罗斯代表团之间达成具体协议的结果。此前,乌克兰总统泽…

3、禁止树莓派屏幕休眠,设置树莓派屏幕常亮

树莓派是微型电脑&#xff0c;系统自带休眠保护功能&#xff0c;但是有人可能会处理一些事务&#xff0c;想树莓派屏幕常亮&#xff0c;保证树莓派一直都处于活动状态&#xff0c;今天分享如何让树莓派屏幕常亮&#xff0c;禁止休眠的解决方案。 1、 系统&#xff1a;raspbia…

巴黎欧冠夺冠狂欢夜559人被捕 暴力事件引发谴责

法甲球队巴黎圣日耳曼在5月31日晚赢得欧冠联赛冠军奖杯,法国多地的球迷彻夜庆祝。然而,据法国内政部消息,在狂欢夜有559人因滋事被捕,并发生了两起命案。6月1日,法国总统马克龙在爱丽舍宫接见巴黎圣日耳曼球队时,严厉谴责了庆祝活动中发生的暴力事件,称这些行为“不可接…

英国耗资百亿英镑新建核潜艇 备战状态升级

英国首相斯塔默表示,他将“恢复英国的战备状态”,并将提高英国的武器生产能力。6月2日,英国政府发布了《战略国防评估》,这份报告评估了英国面临的威胁,包括俄乌冲突及美国总统特朗普向北约盟国施压,要求提高国防开支及加强防御等情况。该报告呼吁英国武装部队进入“备战…

飞牛fnNAS装机之迷你小主机的利旧

前几天找Console线的时候,翻出一台迷你小主机,想起来以前是做“软路由”用的,现在用不上了。本想放回箱子,但突然想起最近正在做飞牛NAS的专题,不如将其改造成NAS得了。 这个东东有HDMI、VGA接口,2个USB(其中一个支持3.0),还有4个网口。 打开机盖,看看内部情况。发现…

2025年渗透测试面试题总结-奇安信[校招]奇安信观星实验室(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 奇安信[校招]奇安信观星实验室 1. 跟过的大型应用软件CVE漏洞 2. 容器虚拟化漏洞研究 3. 系统审计案例与漏…

郑钦文法网对阵萨巴伦卡 山海皆可平

6月1日,在法国网球公开赛女单第四轮比赛中,中国选手郑钦文以2比1战胜俄罗斯选手萨姆索诺娃,首次闯入法网女单8强。赛后,郑钦文发文:“人都应该有梦,有梦就别怕痛,是一颗宝石就该闪烁”,并鼓励大家勇敢追梦。在另一场1/8决赛中,头号种子萨巴伦卡把握住第八个赛点,以7-…

英首相称将恢复英国战备状态 提升武器生产能力至战时水平

英国首相基尔斯塔默表示,将恢复英国的“战备状态”,以此作为武装部队的核心目标。他表示,英国将把武器生产能力提升至战时水平。斯塔默在《太阳报》刊文称,英国正面临一个更加危险的世界,现在是时候改变保卫这些岛屿的方式了。斯塔默强调,英国将直面这一时刻,采取大多数…

动态规划第二弹:路径类问题(不同路径,珠宝的最高价值,地下城游戏)

目录 前言 1. 不同路径 &#xff08;1&#xff09;题目及示例 &#xff08;2&#xff09;解题思路 &#xff08;3&#xff09;代码 2. 珠宝的最高价值 &#xff08;1&#xff09;题目及示例 &#xff08;2&#xff09;解题思路 &#xff08;3&#xff09;代码 3. 地下…

LabVIEW双光子显微镜开发

基于LabVIEW 开发高性能双光子显微镜系统&#xff0c;聚焦于生物样本深层成像与纳米材料三维表征。实现了超快激光控制、多维数据采集与实时图像重建。系统采用飞秒激光光源与高精度振镜扫描模块&#xff0c;结合 LabVIEW 的 FPGA 实时控制能力&#xff0c;可对活体组织、荧光纳…

C++校园植树节活动 全国信息素养大赛复赛决赛 C++小学/初中组 算法创意实践挑战赛 内部集训模拟题详细解析

C++校园植树节活动 全国信息素养大赛 C++复赛/决赛模拟训练题 博主推荐 所有考级比赛学习相关资料合集【推荐收藏】1、C++专栏 电子学会C++一级历年真题解析电子学会C&#

题海拾贝:压缩字符串

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》 欢迎点赞&#xff0c;关注&am…

Golang——3、流程控制语句

流程控制语句 1、if-else(分支语句)2、for(循环语句)3、for range(键值循环)4、switch-case(分支语句)5、break跳出循环6、continue(跳过本次循环)7、goto(跳转到指定标签) Go语言中最常用的流程控制有if和for&#xff0c;而switch和goto主要是为了简化代码、降低重复代码而生的…

第14讲、Odoo 18 实现一个Markdown Widget模块

目录 模块概述安装与配置前端实现详解依赖库分析使用示例与最佳实践技术架构与设计模式分析总结 模块概述 模块地址https://apps.odoo.com/apps/modules/18.0/web_widget_markdown Odoo 18 Markdown Widget 是一个为 Odoo 18.0 社区版开发的全局通用模块&#xff0c;它允许…

乌方袭击俄机场画面曝光 乌克兰最大胆军事行动

乌克兰官员周日宣布,乌克兰军队对俄罗斯境内深处的多个军用机场发动了大规模无人机袭击。这些机场是用于进行空袭的战略轰炸机基地,这次行动被认为是自俄乌冲突爆发以来乌克兰军队最大胆的军事行动之一。乌克兰安全局官员透露,此次代号为“蛛网”的袭击行动历时一年半准备。…