☰
C#与Halcon结合的PCB缺陷检测系统架构与算法解析
2026/10/17 11:18:35 网站建设 项目流程

1. PCB基板瑕疵检测:这个源码解决的是哪类问题

1.1 场景还原:一条产线每天要处理什么

很多刚入行的同学以为PCB检测很简单,无非是拍张照片、比对一下、输出结果。但真正到过产线的人都知道,一块基板从上线到出货,中间要经历刷锡膏、贴片、回流焊、AOI检测等多个环节,而每一个环节都可能引入不同类型的缺陷。缺件、极性反、桥连、少锡、偏移、划伤、氧化、脏污,甚至基板本身的板弯、板翘、字符漏印,都会导致产品不良。更麻烦的是,这些缺陷往往混在一起出现,有的肉眼可见,有的必须依赖特定光源角度才能显形。

我参与过的某电子制造项目(这里姑且称它为“项目X”),做的是PCB基板在贴片后、回流焊前的在线抽检与全检系统。当时产线要求是:单板检测节拍控制在2秒以内,覆盖至少6类缺陷,同时要把每一次检测结果记录下来,做到批次可追溯。最初团队也试过直接用开源视觉库做原型,但一接触到实际板材就发现,PCB板的纹理复杂度远超预期——线路、焊盘、丝印、过孔堆叠在一起,传统方法很难快速区分“真实缺陷”和“正常特征”。

后来项目落地的技术路线就是标题里说的这个组合:C#负责整体流程控制和界面交互,Halcon负责底层图像处理与缺陷识别。这套组合在工业视觉圈子里其实非常常见,算是比较“稳”的一种选型。C#有成熟的WinForms/WPF生态,做产线级上位机得心应手,数据库、日志、串口通信、TCP/IP和PLC通信都有现成库;Halcon则是在图像算子层面足够丰富,尤其在生产场景的鲁棒性上,比许多开源库要好不少,而且它提供专门的C#接口,两者嵌合度很高。

1.2 为什么选C# + Halcon这个组合

再往深一层说,为什么不是Python + OpenCV,也不是C++ + Halcon?这个问题在我接触过的大小项目里几乎都会被问到。

Python + OpenCV的优势是快速验证算法,原型阶段很爽,但到了产线就有几个绕不开的问题:一是界面和业务逻辑集成要额外框架,二是打包部署环境容易出现兼容性麻烦,三是实时性在复杂算子组合下不容易稳定控制。对于中小型制造企业来说,产线上的工控机配置往往并不高,Windows系统下C#写的WinForms程序启动快、内存占用可控,调试也直观,对维护人员的门槛相对友好。

C++ + Halcon性能上限更高,但开发周期会长很多,尤其UI部分要投入大量精力。对于项目X这种“一个月内必须上机试跑”的节奏,C#明显是更务实的选择。

Halcon方面的理由同样充分。它内部封装了大量工业场景验证过的算法:形态学、Blob分析、模板匹配、测量、分类器,还有针对表面检测的多种预处理和频域工具。更重要的是Halcon支持导出C#代码,也有HDevEngine这种可以动态加载视觉脚本的方式。这样视觉工程师可以用Halcon的交互环境快速调参,开发工程师在C#里写流程,两边可以并行推进。这类模式在项目排期紧张时非常有效。

2. 系统架构与核心模块设计

2.1 整体分层:UI、逻辑、算法、数据四层分离

拿到这个源码,不要一头扎进某个算子的参数里。先看整体架构。做得比较规范的系统,通常会分成四层:表现层、业务逻辑层、算法服务层、数据层。项目X源码里也是这么划分的。

表现层就是WinForms主窗体,承担操作员登录、参数配置、实时图像显示、检测结果列表、状态监控这些功能。业务逻辑层负责处理相机触发、流水线信号对接、检测流程状态机、报警逻辑。算法服务层是核心,它封装所有Halcon操作,对外只暴露类似InspectPCB(Bitmap image, string recipeName)这样的接口,返回缺陷列表和判定结果。数据层则负责把每次检测任务写入本地数据库(常用SQLite或SQL Server),记录良品数、不良品数、缺陷类型分布、图像路径。有些改造版还会对接MES,把结果上报到产线管理系统。

这个分层的核心好处是:换相机、换光源、换检测算法时,不会牵一发动全身。举个例子,项目X最初用的是Basler相机,后来因为采购原因换成海康相机,只需要改业务逻辑层里的相机采集类,算法层和数据层完全不动。如果你拿到源码后发现所有东西都堆在一个窗体文件里,那可维护性就很差,改造成本也高。

2.2 多维度缺陷识别怎么落地到程序

“多维度”这三个字,是这个项目的精华,也是最容易被误解的地方。它不是指算法数量多,而是指对同一种缺陷,从多个特征维度去描述和判定,避免单一阈值导致误杀或漏杀。

比如缺件检测,常规做法是:先在标准板上记录每个元件位置和对应区域。检测时,用模板匹配找到当前板的位置偏移,然后把标准元件区域映射到检测图上,计算该区域内的灰度均值、纹理能量、边缘数量。只测灰度均值会出问题:有的元件本体颜色和PCB基材接近,灰度差异很小,但边缘信息很明显。所以项目X里把“灰度特征”“边缘密度”“区域面积占比”三个维度组合在一起,任何一个维度进入可疑区间就触发复判逻辑,复判时再由另一套更精细的算子确认。

这个思路可以延伸到其他缺陷类型。划伤检测,不能只看二值化后的面积,还要看长宽比和方向一致性;桥连检测,除了看相邻焊盘之间是否连通,还要看连通域的面积与骨架宽度;污渍检测,则要在特定颜色空间里看色差分布。源码里的DefectClassifier类就是干这件事的,每一种缺陷对应一个特征向量,特征向量进入分类器之前还会做归一化,避免某个量纲特别大的维度主导结果。

3. 核心算法与检测流程逐段拆解

3.1 图像采集与预处理:得到一张能用的图比想象中难

Halcon程序的第一步永远是图像采集。项目X源码中采集部分做得很细,不只是简单GrabImage。它包含:曝光时间设置、增益控制、触发模式配置、图像分辨率校验、坏点补偿、平场校正。其中平场校正许多人会忽略,但实际效果影响非常大。

PCB板反光特性复杂,同一块板上亮区和暗区亮度差异可能超过50%,如果不做平场校正,后续二值化阈值就不可能全局统一。Halcon里可以用calibrate_sheet_of_light或者通过采集标准白板/灰板生成校正系数。项目X里用的是多灰度均匀的标准陶瓷板标定,生成校正矩阵后在预处理阶段直接应用。

预处理流程一般是:转灰度 -> 中值滤波去噪 -> 平场校正 -> 增强对比度。这里有个关键细节:去噪不能用过大的高斯核,否则细小划伤会被抹掉。中值滤波窗口一般3x3就够了,目的是去除传感器噪点而不是做平滑。增强对比度也不能用全局直方图均衡,因为PCB板上有大量细密线路,全局均衡会把微弱划伤淹没在背景纹理里。项目X用的是局部对比度增强,具体算子是emphasize或者scale_image。

3.2 定位与配准:所有检测的前提

PCB板每次放置位置不可能完全一样,哪怕有定位治具也会有微米级偏差,所以必须先做定位与配准。Halcon里最常用的是基于形状的模板匹配,算子族是create_shape_model和find_shape_model。

项目X源码中,匹配模板不是直接用整块板,而是选几个特征明显的定位点。选定位点的原则有三条:一是必须在同一平面上,避免板弯导致位置偏移不一致;二是纹理足够独特,避免误匹配;三是尽量分布在对角位置,这样计算出的仿射变换更准确。我当时帮项目X选的是两个大焊盘加一个特殊丝印字符,效果非常稳定。

得到模板位置后,用hom_mat2d_identity、hom_mat2d_translate、hom_mat2d_rotate组合计算当前图到标准位置的变换矩阵,然后用affine_trans_image做校正。校正之后所有缺陷检测都在标准坐标系下进行,后续ROI映射直接可用。如果省略这一步,哪怕偏了2个像素,对细小线路的断短路检测都是灾难性的。

3.3 缺陷检测算子选型:分门别类才能稳准狠

下面把项目X里实际用到的缺陷检测思路按类展开。这里不堆算子名,尽量讲清楚每种缺陷的核心判别逻辑。

第一类是缺件与漏贴。流程是:映射标准元件ROI到当前图 -> 计算ROI内的边缘密度和灰度均值 -> 与标准模板值做差异比对。如果在ROI内测得的边缘密度骤降、平均灰度趋近基材值,基本可以判定缺件。源码中对应函数是CheckMissingComponent。

第二类是桥连与短路。这个必须用连通域分析。先对焊盘区域做阈值分割,得到二值图,然后connection得到连通域,再用select_shape筛选面积异常大的连通域。但单纯看面积不够,项目X里还有一步关键操作:对每个焊盘做凸包计算,如果凸包面积与原始面积之差超过阈值,说明该焊盘区域有异常延伸,很可能就是桥连。

第三类是划伤与基材损伤。这里用的是灰度梯度加形态学方法。先计算图像的sobel梯度幅值,划伤区域通常表现为一条方向性明显的高梯度线条。再用一个长条形的结构元素做开运算,把点状噪点滤掉,留下的就是候选划伤。最后看候选区域的长宽比和连续性,长宽比大于某个阈值、且能拟合成直线或弧线的,判为划伤。

第四类是焊点虚焊与少锡。这个项目X用的是频域方案。焊点区域做FFT变换后,标准焊点的频谱会有一个典型模式,虚焊或少锡会导致频谱中低频成分的比例变化。用rft_generic加一个预先训练好的分类器(Halcon里可以用MLP或GMM)来判断。这块对初学者来说门槛稍高,但在源码里给了训练好的分类器数据文件,用户可以直接调用。

3.4 判定规则与参数配置化:不要写死阈值

市面上很多半成品源码最大的问题是阈值直接写在程序里,换一块板材就得改代码重新编译。项目X源码这点做得比较好,它把判定规则抽出来做成JSON配置文件,每条规则对应一个缺陷类型,包含算子参数、阈值、权重和启停开关。

例如缺件规则的配置片段大致如下:

{ "DefectType": "MissingComponent", "Enabled": true, "RoiName": "R01", "GrayDiffThreshold": 25.0, "EdgeDensityThreshold": 0.15, "AreaRatioThreshold": 0.30, "Weight": 1.0 }

用户想调整灵敏度,不需要打开Visual Studio改代码,直接在界面上的“规则配置”页修改,保存后实时生效。做这个设计的原因很简单:产线上调机时,常常同一个型号板卡的良率波动需要用不同参数去适配,配置化可以大幅缩短调机时间。整个过程不需要停产太久,几分钟就能完成参数切换。

另外,源码里的规则引擎还支持“按产品型号加载配方(Recipe)”。今天测板卡A,明天切板卡B,只需要选不同配方,所有模型和参数自动切换过来。这个功能在项目验收时是非常加分的亮点,因为很多制造企业同一产线会轮流生产多款产品,没有配方管理就意味着每次换型都要工程师介入,完全不现实。

4. 流程化管控:从检测结果到生产闭环

4.1 数据记录与追溯:结果可不是绿灯就完事

很多检测系统能告诉你“这块板OK/NG”,但问它“NG的板从哪批来、第几道工序、当时用的什么配方、检测图像存在哪”,就答不上来了。项目X源码花了不少功夫在流程化管控上。

每次检测任务开始前,系统会生成一个唯一任务号,一般由PCBA序列号或自动生成的批次号组成。检测完成后,以下信息都会写入数据库:任务号、产品型号、配方版本、检测时间、操作员账号、相机温度、光照强度(如果接入传感器)、检测总耗时。如果结果是NG,还会把缺陷类型、缺陷位置坐标、缺陷面积、缺陷图像裁剪图路径一并保存。这样一来,后续质量分析时可以直接在数据库里按缺陷类型统计趋势,也可以单独调取某块板的检测图像做人工复核。

数据库表设计上,至少要有三张表:InspectionTask(任务主表)、DefectRecord(缺陷明细表)、RecipeInfo(配方表)。任务主表和缺陷明细表通过TaskID关联。做趋势统计时常用的SQL大概长这样:

SELECT DefectType, COUNT(*) AS Cnt FROM DefectRecord WHERE TaskID IN ( SELECT TaskID FROM InspectionTask WHERE ProductModel = 'PCB-X' AND TestDate >= '2025-01-01' ) GROUP BY DefectType ORDER BY Cnt DESC;

这些报表大多在C#里用DataGridView直接呈现,也有部分客户要求导出Excel,源码里封装了ExportHelper,支持把当前列表导出成xlsx。

4.2 与产线流程的衔接:PLC信号、报警与自动分拣

检测系统不能孤立运行。项目X现场是这样衔接的:基板由传送带进入检测工位,到位传感器触发相机采集,检测完成后C#程序通过TCP/IP或Modbus把结果发给PLC,PLC根据结果控制后续机械动作——OK板放行进入下一工位,NG板则推入待复判区域。如果连续三块板NG,程序会弹报警并可通过IO模块控制三色灯报警,同时暂停产线,等待操作员确认。

这套逻辑里有个细节容易被忽略:信号握手必须做超时处理。产线运行过程中偶尔会出现传感器没触发或者通信中断的情况,如果程序不做超时判断,就会一直卡在等待状态,导致产线堵塞。项目X源码中做的是:采集触发等待时间超过5秒自动报警提示,PLC信号超过3秒无响应就重新发送。这种“异常兜底”在产线级软件里不是加分项,而是必选项。

权限控制也是流程化管控的一部分。操作员只能进行开始检测、查看结果这类基础操作;参数修改需要工程师权限;配方删除需要管理员权限。项目X里用的是简单的登录角色控制,用户名密码存在数据库里。权限等级过低时修改按钮置灰,防止现场操作员误改参数导致批量不良。这实际上是为“可追溯”服务:出了问题能定位到是谁、在什么时间、改了什么东西。

5. 实测中常见问题与排查技巧

5.1 高频问题速查表

这个表是按项目X从开发到试产再到稳定运行三个阶段里遇到的高频问题整理的,基本覆盖大多数PCB视觉检测系统的典型故障。

现象可能原因排查方法
图像整体偏暗或过曝曝光时间、增益配置不合理打开相机参数面板,观察直方图,使灰度均值落在140-180区间
模板匹配偶发失败定位点纹理不够独特或光照波动换更明显的特征点,必要时做多模板匹配,取最高分
细小划伤检测不到预处理过度平滑或分辨率不足检查中值滤波窗口,确认相机像素精度满足最小缺陷尺寸要求
OK板误报NG判定阈值过于敏感查看缺陷特征值是否接近阈值边界,适当放宽或调整权重
连续检测速度变慢内存泄漏或图像缓存未释放检查是否及时释放Halcon对象,用Dispose方法清空临时变量
与PLC通信偶尔超时串口/TCP缓冲区堆积增加通信层的心跳检测,异常后自动重连
光源亮度衰减导致误检光源老化软件中增加亮度监测模块,低于设定值就预警

5.2 光路与程序联调的心得

最后聊一点个人经验。做PCB检测项目,我越来越认可一句话:“光源和光路决定了算法的上限。”算法再强,如果光源没有打好,图片信息本身就缺失,后面任何高级算子都是在补先天不足。

以项目X为例,最初用环形低角度光拍基板,划伤能看到一部分,但部分斜向划伤对比度很低。后来改成四条独立可控的条形光源分区打光,在同一位置分别采集两种光照条件下的图像,再在Halcon里做图像融合。仅仅这个改动,划伤检出率就提升了不少。这个经验建议大家如果做同类项目时直接借鉴。另外,在相机固定支架设计上建议增加微调机构,产线调试时调节角度会非常频繁,没有微调螺丝只能靠垫片,极其痛苦。

还有一个小提醒:Halcon运行授权的License文件,部署到产线工控机上时一定要确认是对应版本和硬件锁。曾经遇到过开发环境一切正常,发布到产线后提示授权错误,最后发现是License绑定网卡地址,而那台工控机换了网卡导致重新授权。这种事虽然不大,但处理起来让人头疼,提前规避能省很多时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询