简介:焊点质量直接影响电子产品可靠性与寿命,传统人工检测效率低,难以满足现代制造业对速度和精度的要求。这份PDF论文《基于计算机视觉的焊点缺陷检测系统的设计》面向机器视觉、图像处理及工业质检方向的研究生与工程师,系统阐述利用图像处理技术自动识别虚焊、漏焊、焊穿等缺陷的方法。全文从图像预处理入手,依次介绍平滑去噪、Otsu阈值分割、倒三角距离变换与分水岭算法的组合流程,并给出基于焊点面积、形状等特征的分类方案;同时说明机器视觉系统融合光学、传感器与图像处理软件,可实现非接触在线检测,实验证明该方法能高效识别多种排列焊点。压缩包共1个PDF文件,大小约308KB,便于离线阅读与打印;内含中英文摘要、关键词、算法步骤及实验数据,尤其适合作为课程设计、毕业设计或课题预研的参考文献。目前已有207人学习下载,是掌握机器视觉在工业质检中落地应用的实用资料。
1. 从人工目检到像素级判别:焊点检测为什么要换一条技术路线
在点焊机生产线上,焊点质量检测长期依赖人工目检。工人拿着放大镜,在强光下逐个判断焊点是否虚焊、漏焊或焊穿。这种方式的瓶颈很明显:连续工作半小时后注意力下降,误判率就会上升;而且人工记录只能给出“好/坏”的结论,无法量化焊点面积、灰度分布这类过程数据。我拆过不少类似的视觉项目,深有体会——检测环节的自动化程度往往决定了整条产线的良率上限,焊接本身再快,质检跟不上一样得停线。
这篇论文提供了一套完整的机器视觉检测方案:先把焊点图像做平滑去噪,再用 Otsu 方法自动确定阈值做二值化,接着用倒三角距离变换把二值图像转成灰度信息,最后通过分水岭算法把粘连在一起的焊点逐个切开,并利用面积、内部灰度变化等特征区分正常焊点、虚焊和焊穿。整套流程覆盖了从成像、分割到分类的完整链路。对正在做计算机视觉大作业、或者刚接触机器视觉入门、需要设计一套电子系统检测方案的读者来说,这篇论文的算法选型和参数推导逻辑都很值得参考。
2. 系统架构与成像选型:0.1 mm 检测精度是怎么凑出来的
2.1 硬件构成与选型逻辑
论文中的检测对象是一块 100 mm × 40 mm 的不锈钢薄板,点焊机焊接后表面会留下排列不规则的圆形焊点。系统的硬件层由工业数字摄像机、光学镜头、光源三部分组成,辅以控制单元和上位机软件。这里最关键的一个指标是 0.1 mm 的检测精度要求。论文选用的是 500 万像素工业面阵 CCD,通过 1394 接口(FireWire)与上位机通信。
为什么选 500 万像素?你可以用视场除以分辨率来估算单像素对应的物理尺寸。假设视场覆盖整个 100 mm × 40 mm 的工件,500 万像素面阵 CCD 的典型分辨率是 2448 × 2048 左右,那么在 X 方向上单像素约为 100 mm / 2448 ≈ 0.04 mm,论文里给出的数值与此吻合。也就是说,0.1 mm 的检测精度对应约 2.5 个像素,在视觉检测里属于合理的裕量范围。
光源用的是 LED 颗粒的同轴白色光源,采用正面打光方式。这个选择很关键。同轴光的特点是光线经过半反半透镜后垂直照射到被测物体表面,反射光再沿原路返回进入镜头。对于不锈钢这类高反光材质,同轴光能有效避免环境光的漫反射干扰,让背景灰度尽量均匀。在实际项目中,我一般会在光源控制器上加一个 PWM 调光模块,因为 LED 在低电流下会有色温和亮度的漂移,恒定电流驱动比脉冲调光更稳定。
2.2 上位机软件流程与模块划分
上位机软件是整个检测系统的神经中枢。从论文给出的流程图来看,采集到原始图像后,依次经过平滑处理、Otsu 阈值分割、倒三角距离变换、分水岭算法、圆拟合,最后做缺陷判别并输出信号给控制工作台。这个流水线设计有一个好处:每个模块都是独立的图像处理操作,便于单独调参和替换算法。比如平滑核的大小、Otsu 的直方图区间、距离变换的模板尺寸,都可以作为参数暴露在配置文件中,而不是硬编码在程序里。
一个容易忽略的细节是光机结构的固定方式。论文提到,不锈钢表面容易受环境光变化和位置偏移影响,因此相机、镜头和光源必须由支架固定在产品上方,并与产品水平面保持平行。这个在实验室里很容易被忽视——手持相机拍一张和固定机位拍一张,后续分割算法跑出来的结果差异非常大。光照角度变化几度,焊点边缘的灰度梯度就会改变,Otsu 自动计算的阈值也会跟着偏移,最终导致分割结果不稳定。
3. 从像素到焊点:平滑、Otsu 与倒三角距离变换的完整链路
3.1 图像平滑:为什么卷积核必须是奇数
图像在采集和传输过程中不可避免会引入噪声点,同时焊点背景区域可能存在细微的焊渣颗粒。论文使用卷积核与图像做卷积来实现平滑。设原始图像为 f(x, y),卷积核为 G(s, t),核大小为 m × n,则处理后的图像 g(x, y) 为:
g(x, y) = ΣΣ G(s, t) · f(x + s, y + t)
其中 s 和 t 的取值围绕核中心对称,m 和 n 为奇数。这是因为卷积核需要一个明确的中心锚点。如果核尺寸是偶数,锚点会落在两个像素之间的位置,导致输出的卷积结果在空间上偏移半个像素。对后续需要精确计算焊点中心和半径的圆拟合来说,这种亚像素偏移会影响最终判定结果。
在实际工程中,我一般用高斯核作为平滑核。普通均值卷积在去除噪声的同时会让边缘变得模糊,而高斯核的中心权重更大,能在去噪和保留边缘之间取得更好的平衡。OpenCV 里的实现非常直接:
import cv2 import numpy as np src = cv2.imread("solder_joint.bmp", cv2.IMREAD_GRAYSCALE) # 高斯平滑,核大小选用 5x5,标准差设为 1.5 blurred = cv2.GaussianBlur(src, (5, 5), 1.5) # 对比:均值模糊 box_blurred = cv2.blur(src, (5, 5))高斯核的两个关键参数是核尺寸和标准差 sigma。核尺寸决定了参与卷积的邻域范围,sigma 控制了权重在空间上的衰减速度。sigma 太小则平滑效果有限,噪声仍然存在;sigma 太大则会把焊点边缘的灰度梯度磨平,后续 Otsu 分割时边缘会变得模糊。从工程角度来说,sigma 一般取核尺寸的 1/6 左右,这样高斯核在边缘处接近自然衰减到零,不会出现截断突变。
3.2 Otsu 阈值分割:自适应的最大类间方差逻辑
平滑处理之后是阈值分割。论文采用 Otsu 方法,即最大类间方差法。它的核心思想是:给定一个灰度阈值 T,把图像像素分为前景和背景两类,计算两类的类间方差。当类间方差最大时,说明前景和背景的区分度最高,此时 T 即为最佳分割阈值。Otsu 的好处是不需要人工干预,算法会遍历所有可能的灰度级,自动找到最优阈值。
在焊点检测场景下,为什么不能用一个固定阈值?因为产线上的光照环境不可能完全恒定,LED 光源老化、产品表面氧化程度不同,都会导致焊点的绝对灰度值发生漂移。固定阈值需要人工不断调整,效率太低。论文在综述部分也提到,文献 [3] 的模式匹配方法检测速度快但阈值参数依赖人工设定,这恰恰是 Otsu 要解决的核心痛点。
OpenCV 里调用 Otsu 只需要在 threshold 函数里加上 THRESH_OTSU 标志,返回值里的 ret 就是算法自动找出的最优阈值:
# 大津法二值化,自动计算阈值 ret, binary = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) print(f"Otsu 自动阈值: {ret:.1f}") # 如果焊点是亮目标,但背景偏亮,可以取反 # binary_inv = cv2.bitwise_not(binary)这里有个实际工程中很容易踩的坑:Otsu 假设图像灰度直方图是双峰分布。如果光照不均导致背景灰度范围过大,直方图可能出现多峰,Otsu 计算的阈值就会偏向面积更大的那一类。常见的解决方案是先对图像做归一化或同态滤波,把光照不均的影响压下去,再去跑 Otsu。另一个方案是在中值滤波之后再进 Otsu,中值滤波在去除椒盐噪声方面比高斯滤波更有效。
3.3 倒三角距离变换:把像素关系变成灰度信息
二值化之后,焊点区域已经是白色前景、黑色背景的纯像素集合。但对于相互粘连的焊点,直接做连通域分析没法把它们分开。距离变换是解决这个问题的第一步。它的数学定义是:对每个前景像素,计算它到最近背景像素的距离,把这个距离值作为该像素的新灰度值。距离越长的像素,灰度值越高。
论文特别强调使用倒三角算法来计算距离变换,原因是标准的全局距离变换需要每个前景像素都去扫描全图中的背景像素,计算量随图像尺寸呈指数级增长,在 500 万像素的大图上是不可接受的。倒三角法类似于卷积操作,用 3 × 3 的模板做两次扫描:第一遍从左到右、自顶向下;第二遍从右到左、自底向上。每次扫描时,模板中心像素的值更新为模板覆盖区域内所有像素值与模板系数之和的最小值。
这个算法的本质是动态规划,通过两次单向传播来近似全局距离,计算复杂度从 O(N²) 降到了 O(N),其中 N 是图像像素数量。论文在 2.2 节明确指出“全局操作的计算量是非常大的”,这也是选型倒三角算法的直接动机。
OpenCV 内建了距离变换函数,支持多种距离度量和掩码类型:
# 距离变换:使用欧氏距离度量,3x3 掩码 dist = cv2.distanceTransform(binary, cv2.DIST_L2, 3) # 归一化到 0~255 方便可视化 dist_norm = cv2.normalize(dist, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)DIST_L2 对应欧氏距离,DIST_L1 对应曼哈顿距离,DIST_C 对应切比雪夫距离。在焊点这类近似圆形的目标上,欧氏距离最合适,因为它计算的是真实的几何距离,能最准确地反映从焊点中心到边缘的像素距离。距离变换之后,焊点中心区域灰度值高(离背景远),边缘区域灰度值低(离背景近),每个粘连的焊点内部会形成一个局部的灰度峰值。这个峰值就是后续分水岭分割的种子起点。
3.4 分水岭算法:处理粘连焊点的关键步骤
距离变换之后的图像,每个焊点中心像一个山丘的顶点,相连焊点之间的凹陷区域则形成山谷。分水岭算法模拟水从局部最低点开始上涨的过程,水面上涨到山脊时,山脊线就构成了分割边界。
论文中提到先对灰度图像做梯度变换,梯度图像中边缘提取趋近于零,二值化后分成大于阈值和小于阈值的两部分,分别对应“陆地”和“水域”,两者的分界就是分水岭。在 OpenCV 中实现分水岭的标准流程是:先找到每个焊点的中心标记(marker),再传入梯度图像让分水岭算法自动扩展标记区域:
# 分水岭标准流程 dist_thresh = cv2.threshold(dist_norm, 0.2 * np.max(dist_norm), 255, cv2.THRESH_BINARY)[1] dist_thresh = np.uint8(dist_thresh) # 形态学操作去除噪声和填洞 kernel = np.ones((3, 3), np.uint8) opened = cv2.morphologyEx(dist_thresh, cv2.MORPH_OPEN, kernel, iterations=2) # 找到确定的背景区域 sure_bg = cv2.dilate(opened, kernel, iterations=3) # 标记连通域 num_labels, labels = cv2.connectedComponents(opened) # 给标记加 1,使背景为 0 labels = labels + 1 # 未知区域置 0 unknown = cv2.subtract(sure_bg, opened) labels[unknown == 255] = 0 # 执行分水岭 markers = cv2.watershed(cv2.cvtColor(blurred, cv2.COLOR_GRAY2BGR), labels)分水岭算法对噪声敏感,过分割(oversegmentation)是最大的坑。论文的处理顺序值得一提:先做距离变换再进分水岭,而不是直接在梯度图上跑分水岭。距离变换本身就带有一点“滤波”的性质,能把焊点内部的灰度波动抹平,让每个焊点形成一个干净的单峰区域,大幅降低过分割的概率。如果分割结果还是碎了,可以检查一下 opened 的形态学开操作次数,或者调低 0.2 这个距离阈值系数——阈值越低,被标记为前景的区域越少,分割粒度越粗。
4. 缺陷分类的几何基础:圆拟合、面积计算与灰度判别
4.1 最小二乘圆拟合:从离散点到标准圆
分割完成后,每个焊点区域是一组像素点集合。论文采用最小二乘法拟合圆,用标准圆来近似表示样本点集的坐标关系。距离公式定义如下:
di² = (xi - A)² + (yi - B)²
拟合的目标是找到圆心坐标 (A, B) 和半径 R,使得所有样本点到圆心的距离与半径之差的平方和最小。论文给出的代价函数展开为:
Q(a, b, c) = Σ(xi² + yi² + a·xi + b·yi + c)²
把问题化为线性最小二乘,其中 a = -2A,b = -2B,c = A² + B² - R²,所以求解 a、b、c 之后即可反向推出圆心和半径。直接求解这个线性方程组,耗时远小于传统的非线性迭代优化方法。
在 OpenCV 里,直接用 minEnclosingCircle 可以求最小外接圆,但对有缺陷的焊点,最小外接圆的半径容易被边缘噪声拉大,更适合的做法是先用 findContours 拿到轮廓点集,再对轮廓点做代数圆拟合:
# 在分水岭分割后的图上提取每个焊点轮廓 contours, hierarchy = cv2.findContours( np.uint8(markers == region_id), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE ) for cnt in contours: area = cv2.contourArea(cnt) if area < 50: # 过滤过小噪声区域 continue # 方式一:最小外接圆 (x, y), r_min = cv2.minEnclosingCircle(cnt) # 方式二:轮廓矩求质心,再基于质心作代数圆拟合 M = cv2.moments(cnt) if M["m00"] == 0: continue cx = int(M["m10"] / M["m00"]) cy = int(M["m01"] / M["m00"]) # 拟合圆半径可用等效半径:sqrt(面积 / pi) r_equiv = np.sqrt(area / np.pi)从算法鲁棒性角度,我用 minEnclosingCircle 时会注意焊点边缘是否平滑。如果焊点边缘有少量毛刺,最小外接圆半径会比实际偏大,此时用面积反推等效半径更可靠。等效半径的定义是 r_equiv = sqrt(area / π),在焊点形状接近规则圆时,这个值与最小外接圆的差别很小。
从最小二乘拟合圆到缺陷分类,存在一个容易忽视的问题:拟合结果对轮廓点集的纯度高度敏感。分割时如果把焊渣、背景中的亮点也划进了焊点前景,面积会偏大,圆拟合的圆心也会偏移。所以在工程实现中,我会在拟合前先对轮廓做多边形逼近,把轮廓点数量降到可控范围,并结合每个点与初始圆心的距离做离群点剔除。
4.2 面积与灰度特征:虚焊和焊穿怎么区分
论文检测的缺陷主要针对虚焊和焊穿两类。通过比较发现:虚焊产生的焊点面积比正常焊点小;焊穿产生的焊点内部灰度均匀,没有明显的亮色区域。因此第一个判别维度是面积。按照论文的思路,焊点拟合圆之后求出面积,直接和正常焊点的面积基准做对比。正常焊点的基准值需要在实际产线上采样统计——采集几百个由合格焊件得到的拟合圆面积,计算均值和标准差,作为判别阈值的依据。
第二个判别维度是焊点内部灰度值的变化。焊穿的特征是内部灰度均匀,这与正常焊点的外观有明显不同。正常焊点由于焊接时金属熔融后再凝固,表面常形成不规则的亮斑,灰度方差较大;而焊穿区域因为材料被高温熔穿,表面失去原有的纹理特征,灰度分布趋于平坦。用方差来量化这个差异:
# 用掩膜统计焊点区域内部的灰度分布 mask = np.zeros_like(gray) cv2.drawContours(mask, [cnt], -1, 255, thickness=cv2.FILLED) # 提取焊点区域的灰度值 pixels = gray[mask == 255] # 计算灰度均值和标准差 mean_gray = np.mean(pixels) std_gray = np.std(pixels) # 判别规则 if area < area_normal_mean - 2 * area_normal_std: label = "虚焊" elif std_gray < std_gray_normal_threshold: label = "焊穿" else: label = "正常"这里有三个参数需要标定:面积下限阈值、面积上限阈值、灰度标准差阈值。灰度标准差阈值本质上刻画的是“内部灰度均匀”的程度——该值设得越小,判定为焊穿的条件越严格。设得太大则会误把正常焊点的反光区域也判成焊穿。论文原文描述的是“内部灰度均匀,无明显亮色区域”,这句话对应到代码上就是像素灰度值的高斯分布方差比较小。
在这个步骤里,一个常见的错误是直接在原始灰度图上统计方差,而不是基于分割后的掩膜来统计。如果掩膜不准,把背景或相邻焊点也划进来了,灰度方差的可靠性就会大打折扣。所以,面积判别的第一个闸门很重要,它先把面积离群区域筛掉,再针对面积正常的焊点做灰度分析,通过级联的方式降低误判率。
5. 产线落地的边界条件与实践技巧
5.1 系统标定与基准阈值确定
论文在系统功能测试一节提到,配备视觉系统前后各生产 200 块产品进行对比,结果表明视觉检测能有效识别有缺陷的焊点。但这里有一个隐含的前提:判别阈值是从哪一份样本集里学出来的?在实际落地时,我会建议分两步走。第一步是采集 100~200 个由工艺工程师确认过的合格焊点样本,统计面积和灰度方差的均值和标准差;第二步是采集虚焊、焊穿样本各 50 个左右,验证阈值分界是否清晰。如果虚焊样本的面积分布和正常焊点有重叠,单纯靠面积做单维判别是不够的,需要增加圆度特征(4π·area / perimeter²)作为补充维度。
阈值系数也有讲究。论文没有给出具体的系数值,但按常见的做法,推荐用均值加减 2~3 倍标准差。2 倍标准差意味着假设正态分布下约 95% 的正常样本落在区间内,那约 5% 的正常焊点会被误判为缺陷;3 倍标准差则更保守,但可能放过一部分虚焊焊点。到底是偏严还是偏松,取决于后段工序还能不能做人工复检。如果后段能复检,可以偏严,宁可把疑似缺陷挑出来;如果后端直接出货,就要偏松,避免误杀合格品。
5.2 光照漂移与分水岭过分割的工程处理
LED 同轴光源在连续工作若干小时后会出现光衰,光谱特性也会发生变化,导致采集到的焊点图像整体变暗。这时 Otsu 自动计算的阈值会随之调整,但分水岭算法对距离阈值系数的敏感度较高,可能需要定期校正。一个工程处理方案是监控 Otsu 返回的阈值,如果连续 N 个工件的结果都偏移超过预先记录的基准阈值的某个百分比(比如 15%),给出报警提示,让人去检查光源状态。
分水岭过分割的另一个容易被忽视的来源是焊点边缘的反光。正面打光下,不锈钢焊点的边缘可能出现一圈高亮的月牙形区域,这个区域在距离变换后会形成一个独立的局部峰值,导致分水岭算法把同一个焊点切成了两半。解决这个问题的通用做法是,分水岭分割后过滤面积过小的碎片,并把碎片归属到相邻最大的分割区域。这个后处理逻辑用 Python 实现很容易:统计每个标记区域的面积后,将面积小于阈值的区域合并到与之相邻的最近区域。
5.3 论文之外的现实接口问题
论文中用的是 1394 接口(FireWire)相机。这个接口在当年的工业相机场合很常见,但放到今天,新产线上的视觉项目更多采用 USB3.0 或 GigE Vision 接口。USB3.0 的理论带宽是 5 Gbps,传输 500 万像素灰度图(约 5 MB/帧)可以做到 60 fps 以上;GigE 则更利于多相机组网和中长距离传输。从传输协议上看,论文中的图像处理链路并不依赖 1394 接口的特殊性,换成 USB3.0 的工业相机,只需要把图像采集的 API 层替换掉,后续的 OpenCV 处理链路完全不需要改动。这一点在做复现实验时值得注意——直接拿论文的流程用现代相机重跑一遍,整体逻辑依然成立。
如果你需要验证这套算法的效果,我建议先用手机或普通工业相机拍几张正对焊点的图像,按论文流程跑一遍,观察二值化的结果是否把焊点完整地提出来,以及两个相邻焊点之间的距离变换灰度剖面是否有明显的山峰结构。如果焊点太密,山峰之间的山谷不明显,分水岭很难切干净,就要考虑提高相机的物距或者在光源上做文章来加大焊点边缘的对比度。这些细节论文不一定写到,但它们是把这个系统从论文带进产线的必经之路。
另外,距离变换的模板尺寸可以从 3 × 3 扩到 5 × 5。更大的模板意味着距离传播速度更快,但精度会有所下降。在焊点直径只有几个像素的小目标场景,3 × 3 模板的精度才够用;在焊点直径几十像素以上的常规场景,5 × 5 模板的计算效率优势更明显。具体选哪个,可以统计所有焊点前景像素的最小直径后做个简单的除法来判断。
本文还有配套的精品资源,点击获取