翻出这几年攒下的工作笔记VisionPro相关的条目是最厚的一摞。最开始接触它的时候我走的是一段很典型的弯路把帮助文档里每个工具的说明都读了一遍模板匹配会训练了斑点工具会调阈值了卡尺会找边了可一到真正搭一个能交给产线跑的检测作业还是手忙脚乱——工具之间怎么接、坐标怎么统一、结果怎么给出去文档里几乎不讲能搜到的帖子又大多只贴半张截图。这篇笔记就是把这些靠现场试错攒下来的东西理成一条线作业骨架怎么搭、坐标系怎么钉死、测量类工具怎么选、逻辑怎么封装、现场跑不稳的时候从哪儿开始查。它不是什么功能大全而是一份“能落地”的操作记录。适合已经能打开软件、但做出来的作业还不敢交给产线的新手也适合做了两三年、想把零散经验理一理的同行——里面提到的参数和方法基本都能直接照着复现。1. 作业骨架怎么搭决定了后面省多少事1.1 作业、工具组与工具树的三层关系VisionPro里所有东西都挂在一棵树上最上层是作业Job往下是工具组ToolGroup再往下才是具体的工具。这棵树最终被序列化成一个工程文件连同里面的图像、训练好的模板、脚本一起打包。我见过不少人把这个文件当成“一张图配一堆参数”随手扔在桌面改个名就发给现场结果现场一打开就报错——因为工程文件里可能记录了绝对路径的图片源、绑定了本机的相机配置换台机器就散架。理解这棵树的关键在于工具组本身也是一个工具。它有自己的运行入口、自己的输入输出、自己的结果状态。这意味着你可以把一个完整的检测流程封成一个工具组再把这个工具组装进另一个更大的工具组里像搭积木一样层层嵌套。产线上常见的做法是外层一个总控工具组负责取像和分流内层按工位或按检测项拆成若干子组哪个工位出问题一眼就能定位到对应的分支不用在几十个工具里翻。另一个容易忽略的点是运行记录RunRecord。每个工具跑完都会往自己的记录里塞图形和文本界面上看到的那些绿框、红线、尺寸标注全是运行记录渲染出来的。它的价值不只是“看着直观”——现场出现偶发不良时能不能把出问题那一帧的运行记录连同原图一起存下来直接决定了你后面是花十分钟定位还是花两天猜。我的习惯是在总控组里加一段逻辑只要最终判定不通过就把当前图像和整棵树的运行记录一起落盘文件名带上时间戳和工位号。这个习惯救过我很多次。1.2 取像端的选择先用图片文件夹再换真相机新手最容易犯的错是一上手就接相机。相机牵扯触发方式、曝光时间、增益、白平衡、网络配置任何一个没弄对你看到的图像都不是你以后要处理的那张后面所有参数全部白调。我的一般顺序是先用图片文件夹把算法流程跑通再替换成相机。工程里的取像工具支持两种典型模式一种是接相机按软触发或硬触发抓一帧另一种是直接读文件夹里的图片序列跑完一张自动下一张。做算法验证阶段用文件夹模式配合几十张覆盖了各种边界情况的样本图反复跑、反复看结果分布效率比接相机高得多。等到流程稳定了把取像工具的来源切换到相机其余工具的接线一根都不用动——这也是把取像单独放成第一个工具的好处。真正上相机时有几个参数值得先在纸上算清楚再动手。曝光时间决定了运动中的工件会不会拖影假设工件在视野内的移动速度是每秒50毫米像素当量是每毫米10个像素那么1毫秒的曝光对应0.5个像素的位移基本可以接受如果曝光拉到10毫秒位移就是5个像素边缘测量类的工具立刻就不准了。增益能提亮画面但同时抬噪声能不调就不调。触发方式上硬触发比软触发稳因为硬触发的时刻由传感器决定不受上位机调度抖动影响软触发方便调试但不适合高速产线。提示换相机之后像素当量一定变了。之前按像素设的所有阈值、搜索范围、卡尺长度都要按新旧分辨率的比例重新算一遍别指望它们自己适配。1.3 一个最小可跑通流程的搭建顺序我把搭建顺序固定成六步几乎每个新项目都按这个来很少出岔子取像单独的取像工具输出一张图。格式统一如果相机出的是彩色图先转成8位灰度。视觉算法里绝大多数工具对灰度图最友好彩色图留着做颜色判别别让它一路往下传。定位一个模板匹配工具找出工件再用坐标对齐工具建立工件坐标系。测量/检测所有尺寸、缺陷、字符工具都接在对齐后的图像和坐标系上。判定把各工具的结果汇总算出最终的合格/不合格状态。输出把状态和关键数值写成字符串或数值交给外部。这个顺序看起来平平无奇但它隐含了一个重要约束后面所有工具都依赖第3步的坐标系。所以第3步必须做得足够稳稳到“工件在视野里随便怎么放都能找到”。如果第3步本身就在飘那第4步再怎么调参数都是徒劳——这一点我在第2节会展开。至于分支逻辑比如“找到工件才测量找不到直接判不合格”不要靠工具的启用开关去硬关那样在结果汇总时很容易读到上一次运行的残留值。正确做法是在工具组里加判断把没跑的工具结果显式置为无效值再往下传。2. 坐标系不钉死后面所有测量都是浮的2.1 模板训练的四个参数决定定位稳不稳模板匹配工具是整个作业的地基它的输出不只是“找到了”更重要的是“找到的位置和角度”。训练一个模板我通常只盯四个东西模板区域。框选范围要包含足够多的稳定特征——边、角、孔位而不是大片没有纹理的平面。框得太大计算量上去了稳定性反而下降框得太小特征不足工件轻微脏污就匹配不上。我的经验是让模板里至少有两组方向不同的边缘。原点位置。模板原点就是后续坐标系的参考点选在工件的功能基准上比如定位孔中心、两条基准边的交点。这一点必须和机械、工艺的人对过——你选的基准和人家检测报告里的基准不是同一个量出来的数值永远对不上账。角度范围。搜索角度范围要覆盖工件实际可能出现的旋转同时不要无脑开到正负180度。范围每扩大一倍匹配耗时基本按比例增长而且误匹配的概率也上升。产线上工件由治具定位实际角度偏差往往只有几度那就给正负10度留点余量够用。接受阈值。这个分数不是越高越好。设成0.9遇上一点油污就漏检设成0.5画面里随便一个相似纹理都能匹配上。正确做法是拿一批真实样本跑一遍看合格品得分的分布下限把阈值压在分布下限下面一点留出余量再看不良品的得分上限确认两者之间有明显间隔。如果两个分布是重叠的说明模板选得不好回去重新框区域而不是硬调阈值。参数常见错误设法我的建议后果模板区域框整个工件只框稳定特征区域过大导致耗时高、易受干扰原点默认图像中心选工艺基准点数值与检测报告对不上角度范围正负180度按治具实际偏差留余量耗时翻倍、误匹配增多接受阈值凭感觉设0.8按样本得分分布定漏检或误判训练算法上一般有两种取向一种追求极限精度和抗干扰耗时略高另一种速度快适合节拍紧张、图像质量好的场合。产品表面有反光、脏污、丝印干扰时我倾向用前者纯粹做有无判断、位置粗定位时后者完全够用。2.2 坐标对齐工具把像素坐标“钉”在工件上模板匹配给出的是工件在图像里的位置和角度但后面那些测量工具如果还工作在原始图像坐标系里工件一转动它们的测量区域就全部错位了。这时候需要坐标对齐工具把匹配结果的位置和角度作为输入它输出一张变换后的图像和一个新的坐标空间名。接线有三个地方必须接对缺一个就白干坐标对齐工具的输入图像接模板匹配的输出图像它的位置和角度输入接匹配结果的平移量和旋转量后面每一个测量工具的输入图像接坐标对齐工具的输出图像坐标空间选它输出的那个空间名。最后这一条是最容易漏的。图像接对了但坐标空间没选对工具会在原始坐标系里算结果就是图像看起来在正确位置数值却是错的而且错得不明显——工件摆放角度小的时候误差可能就在公差边缘晃你根本发现不了。我排查这类问题的方法很笨但很有效故意把工件转一个明显的角度如果测量值跟着变化说明坐标空间没接对。2.3 坐标系失效后的连锁反应怎么快速定位现场最典型的故障是“昨天好好的今天就全NG了”。这类问题八成出在定位环节而不是测量环节。我一般的排查顺序是先看模板匹配的得分。得分低往上游查——光源是不是衰减了、镜头是不是脏了、工件换了批次表面状态变了。得分正常但角度或位置跳变查治具是不是松动、相机是不是被碰过。再看坐标对齐工具的输出图像。把它的输出单独显示出来正常情况应该是工件被摆正、居中。如果图像是花的、黑的、或者还是原图没变说明接线断了或者变换参数没进对。最后才去看测量工具。如果前两步都正常测量工具还在飘那就是它自己的参数问题比如卡尺的对比度门限压得太死工件表面亮度稍微一变就找不准边。这个顺序的价值在于它把“一大片工具都可能有问题”压缩成“先确认一个工具”。定位稳了后面九成的疑点自动排除。3. 测量类工具怎么选比怎么调更重要3.1 卡尺的对比度与极性为什么总在变卡尺类工具干的事情很朴素沿着一条搜索方向找亮度发生突变的位置也就是边缘。它有三个参数必须配合着看。极性。从暗到亮、从亮到暗是两种不同的边缘。工件的轮廓在背光下是暗背景亮工件在正光下可能是亮背景暗工件极性设反了工具会去找另一侧的边量出来的宽度直接差一个工件厚度。这个问题在新项目里极其常见尤其是换光源方案之后忘了改。对比度门限。它决定“多大幅度的亮度变化才算一条边”。设得太高边缘模糊或者对比度低的地方比如倒角、圆角就找不到设得太低工件表面的纹理、刀纹、油膜都会被当成边找出来的位置随机跳。我的习惯是先把它设成一个明显偏低的保守值跑一批样本看找到的边位置是否稳定再逐步往上提提到刚好还有余量为止。滤波半宽。它在找边之前对像素做一次平滑宽度越大抗噪越好但边缘定位的精度会下降。精度要求高的场合比如亚像素级的尺寸这个值要小图像噪声大、表面粗糙的场合适当加大反而更稳。还有一个容易被忽略的参数是投影长度。卡尺不是只看一个像素列而是把一段长度内的像素沿垂直于搜索方向做投影平均再找边。投影越长抗噪越好但对工件的直线度要求越高——工件边缘本身是弯的投得太长反而把边“抹平”了。3.2 找线与找圆单点结果和拟合结果的区别用卡尺找一条边得到的是一个点要量一条直线的角度或者两个特征之间的距离得先“找线”。找线工具内部通常是一排卡尺每个卡尺各找一个点然后对这些点做直线拟合。这里有个关键认知找线的结果不是某一个卡尺的结果而是所有卡尺点的拟合结果。所以当一条线找得不准时问题可能只出在其中一两个卡尺上——比如线上有个缺口、有个反光点那个卡尺就找偏了拟合出来的直线整体被带歪。处理办法有两个。一是把卡尺数量增加、均匀铺开让个别异常点的影响被稀释二是启用剔除机制让偏离拟合结果太远的点不参与最终计算。我一般先用前者还不够再加后者。但要注意剔除比例设得太激进可能把真实的形状偏差也剔掉了量出来的反而是“理想值”掩盖了工件本身的问题。找圆同理它是多个卡尺点拟合圆。圆弧缺一段、或者工件边缘有毛刺都会让拟合结果偏移。这时候与其死调参数不如换思路把搜索区域避开缺陷段只取干净的圆弧部分来拟合。3.3 标定把像素换成毫米时最容易漏的一步所有测量工具默认输出的都是像素值。要输出毫米得做标定也就是建立像素与实际尺寸的映射关系。常用的是棋盘格标定板或者用已知间距的标准件做多点标定。标定这件事坑基本集中在这几处标定板要和工件在同一高度。镜头的视野是有景深的标定板放高了两毫米算出来的像素当量就是错的而且这个错误是系统性的——所有尺寸会按同一个比例偏看起来“很一致”特别容易蒙混过关。标定板要覆盖足够大的视野范围。只用视野正中心一小块做标定边缘的畸变校正不到越靠边测出来的值偏差越大。标定完成后要验证。拿一个已知尺寸的标准件去量量出来的值和真值的差就是你这套系统的实际误差。这个误差必须写进检测报告的说明里——公差是0.05毫米系统误差就有0.03毫米那这个方案本身就不成立得换镜头或者换方案不是靠调参数能救的。单位换算别在脚本里硬编码。有人图省事在脚本里写死一个0.02毫米每像素的系数后来换了镜头忘了改这一行量出来的数据全错还查了很久。正确做法是把标定结果作为工具的输出往下传脚本只负责计算不负责存常数。4. 把一堆工具封成一块积木ToolBlock与脚本4.1 输入输出终端的命名规范当流程复杂到十几个工具时直接在工具树里横冲直撞地接线很快就会变成一团乱麻。ToolBlock的价值就在于它对外只暴露有限的几个输入输出端口内部怎么接线是它自己的事。我用过的命名规范大概是这样输入以In_开头输出以Out_开头中间用下划线分节全部用英文和数字不用中文、不用空格。比如In_Image、In_Trigger、Out_Result、Out_Width_mm、Out_Score。看起来啰嗦但好处在脚本里立刻体现——你敲一个In_就能列出所有输入不用回头翻工具树确认名字。另一条规范是输出只给必要的东西。有人喜欢把内部每个工具的中间结果都暴露成输出二十几个端口外部调用的人根本不知道该看哪个。我一般只暴露三类最终判定、关键测量值、以及一个用于追溯的分数或状态码。中间量留给自己调试用要暴露就临时加一个调完删掉。4.2 脚本里怎么取结果、怎么判合格ToolBlock支持挂脚本最常用的是在整组运行完成后做一次汇总判定。下面这段是我常用的骨架语言是C#public override bool GroupRun(ref string message, ref CogToolResultConstants result) { // 先跑组内所有工具 RunWorkspace(); double width 0, tolerance 0.05; double score 0; bool ok true; // 取子工具的结果先判工具本身是否有效 CogPMAlignTool align mToolBlock.Tools[CogPMAlignTool1] as CogPMAlignTool; if (align null || align.Results null || align.Results.Count 0) { message 定位失败; result CogToolResultConstants.Reject; return false; } score align.Results[0].Score; // 取测量工具的数值输出 width (double)mToolBlock.Inputs[In_Width].Value; tolerance (double)mToolBlock.Inputs[In_Tol].Value; // 判定并写回输出 if (Math.Abs(width - 10.0) tolerance) ok false; if (score 0.7) ok false; mToolBlock.Outputs[Out_Width_mm].Value width; mToolBlock.Outputs[Out_Score].Value score; mToolBlock.Outputs[Out_Result].Value ok ? 1 : 0; message ok ? OK : NG; result ok ? CogToolResultConstants.Accept : CogToolResultConstants.Reject; return true; }这段代码里有几个细节值得说。先判空再取值是所有脚本的第一原则工具没跑、结果为空、集合长度为0这些情况在现场都会真实发生比如相机丢帧不判空就是等着程序崩。结果状态的写法是三个值合格、不合格、需要警告外部拿到的就是这个状态不是靠解析字符串。信息字段用来带一句话描述界面和日志里都能看到排查的时候比看状态码快得多。4.3 脚本调试的实用手法脚本出错最烦的地方是它不像普通程序那样能随便打断点。我积累的几个手法用信息字段当打印。每跑到一个关键节点就往信息字段里追加一句当前变量的值最后一起显示出来。虽然土但不用装任何调试工具。分步验证。先把脚本简化成只读一个输入、写一个输出确认通了再一点点往上加逻辑。一次写完几十行再跑出错时根本不知道是哪一行。把中间结果写进输出端口。临时加几个输出把怀疑的变量挂上去在界面上直接看值比猜快得多。调完记得删不然端口越堆越多。注意脚本运行时机。脚本是在组内工具跑完之后执行的所以脚本里能拿到所有工具的结果但如果你在脚本里改了某个工具的输入那个工具不会因为你的改动再跑一遍。要形成“改参数再重跑”的循环得在脚本里显式调用运行方法这一点很多人第一次都栽过。5. 现场跑不稳从哪儿开始查5.1 偶发NG靠图像记录反推别靠猜偶发不良是最消耗人的问题。一天出三五件去现场盯半天一件不出回来又出。对付这类问题唯一可靠的办法是把出问题那一刻的证据留住。我的做法是在作业里加一段落盘逻辑最终判定不通过时把当前原图、变换后的图、整棵树的运行记录全部存下来路径按日期分文件夹文件名带工位号、时间戳、关键测量值。跑一周之后把攒下来的不良图片按测量值排序看规律往往自己就浮出来了——可能是某个角度区间特别容易出问题可能是某一批工件表面状态不同也可能是某个时间点之后开始出问题那就去查光源衰减或者镜头污染。有了这批数据再看参数才有依据。没有数据的调参本质上是拿产线当试验田。5.2 节拍超标哪些设置在悄悄吃时间节拍不够的时候第一反应往往是“换个更快的相机”或者“换台更快的电脑”。先别急把耗时拆开看通常在软件层面就能省出不少。耗时项典型影响优化手段图像显示刷新每帧都在重绘界面占用的时间比算法还多关掉不需要的显示只在异常时刷新运行记录存储每个工具都存完整图形记录内存和IO双杀只对关键工具开启记录模板匹配搜索范围角度和尺度范围开太大耗时线性增长按实际偏差收窄范围图像分辨率像素翻倍计算量翻四倍能裁剪就先裁剪别全图处理工具数量与串行一个个顺序跑累加起来就超了无依赖的分支考虑并行我遇到过最夸张的一次算法本身跑完只要三十几毫秒但界面刷新加运行记录存储占了将近两百毫秒整条线卡在显示上。把显示改成“只在NG时刷新”之后节拍直接达标。5.3 换型多型号共用的组织方式一条线要跑七八种型号每种型号的模板、阈值、公差都不一样。最差的做法是复制七八份工程文件换型时手工打开对应的那份——这种方案迟早会出事故因为人总会开错。更稳妥的做法是一份工程、多套参数。把型号相关的部分模板、搜索范围、公差、判定阈值全部提升成工具组的输入端口外面用一个配方文件或者参数表来喂。换型时只切换参数源不动工程文件。再进一步如果不同型号的检测流程本身就不一样有的要测三个尺寸有的要读码那就按型号拆成多个子工具组用一个总控根据型号选择跑哪一组。总控里维护一张映射表型号代码对应子组名加新型号只是加一行配置不用改逻辑。6. 从调试界面到产线软件中间还差什么6.1 界面挂载与运行环境的几个坑调试阶段用的是软件自带的编辑界面交付时通常要把它嵌进自己的上位机程序里。做法是把工具编辑控件拖进窗体把工程对象赋给它界面上就有了完整的工具树和图像显示。这里有几个坑值得提前知道。运行库和授权现场机器上要装对应的运行环境授权方式可能是加密狗也可能是软授权交付前一定要确认现场那台机器的授权是通的别等到验收当天才发现跑不起来。分辨率与缩放产线工控机的屏幕分辨率往往不高界面上工具树、图像、参数面板挤在一起交付前要在目标分辨率下实际看一遍别在自己两K的显示器上调好了就发货。操作权限产线操作工只需要看结果和按按钮不需要也不应该能改参数。工具编辑控件默认什么都能改得加一层权限控制普通账号进去只看只读视图。6.2 结果怎么交给外部设备结果输出一般两条路一条是数字量合格一根线、不合格一根线简单可靠但只能传状态传不了数值另一条是以太网通信把结果拼成字符串或键值对发出去能传完整数据但要处理粘包、超时、重连。不管走哪条我都坚持三个原则。结果要带序号每件工件一个流水号外部拿到结果能对上号出问题时能追溯。要有心跳通信断了外部设备得知道不能傻等。要有超时保护视觉这边算超时了必须主动回一个“本件无效”而不是不回让外部一直等。字符串拼接的格式我一般用固定分隔符加固定字段顺序比如流水号、判定、几个关键尺寸、时间戳用竖线隔开。别用逗号某些地区的数字格式里逗号是小数点解析会出乱子。6.3 版本管理与变更记录比想象中重要工程文件是二进制打包的没法像代码那样做差异对比。所以变更管理只能靠人。我的习惯是每次改动都做三件事改之前把当前文件复制一份文件名带上日期和改动摘要改完之后在同一个目录的文本日志里追加一行写清楚改了什么、为什么改、谁改的交付给现场的版本单独放一个目录只读不允许在现场直接改。这套流程听起来繁琐但真的省事。现场反馈“上周还好好的”你翻一下日志就知道上周改了什么直接锁定嫌疑范围。没有日志就只能靠回忆而回忆在现场压力下通常是不准的。我个人在实际操作中的体会是VisionPro这类工具的入门门槛其实不高真正拉开差距的是“作业层”的功夫——坐标系钉得稳不稳、参数有没有数据支撑、异常时能不能留住证据、交付的版本管没管住。工具会点只是起点把这些琐碎的事情做扎实作业才敢交给产线连着跑三个月。