☰
机器视觉焊点缺陷检测:Otsu分割与分水岭分离粘连焊点
2026/9/30 10:16:21 网站建设 项目流程

简介:基于计算机视觉的焊点缺陷检测系统设计论文PDF,面向图像处理、机器视觉及工业质检方向的研究生和工程师,适用于课题研究、算法选型与论文写作参考。资源围绕点焊生产线中常见的虚焊、漏焊、焊穿等缺陷,提出了一套完整的视觉检测方案:先对焊点图像进行平滑去噪预处理,再采用Otsu方法自动选取阈值完成图像分割,随后进行倒三角距离变换以增强焊点与背景的对比度,最后利用分水岭算法精确分割焊点,并结合面积、形状等特征计算实现缺陷自动分类。文中给出了与传统检测方法的对比与实验验证,能够帮助读者理解机器视觉在焊接质量检测中的落地思路。资源共1个文件,为PDF格式,压缩包大小308KB,轻量易用;目前已有209人学习下载,适合作为相关课题的专业指导资料。

1. 焊点检测的机器视觉改造:这套方案先解决最扎手的粘连分割

生产线点焊出来的焊点不是教科书里的标准圆,多数时候是几个焊点叠在一起、边缘被焊渣包围、光照一变化灰度就飘。基于计算机视觉的焊点缺陷检测系统要处理的第一个难题不是分类,而是先把粘连的焊点一个个干净地切出来。这篇来自《测控技术》2015年的设计论文,给的是一条完整的落地路径:500万像素工业CCD采集、Otsu自动阈值分割、倒三角距离变换、分水岭算法分离粘连焊点、最小二乘圆拟合、再按面积和内部灰度判虚焊与焊穿。它适合两类人:一是产线上想给点焊机配视觉检测的工程师,二是正要写机器视觉课程设计或毕业论文、需要一套能讲清楚原理的检测方案的学生。这套方法不依赖深度学习,特征可解释,参数可调,拿到就能照着搭。

2. 系统方案与硬件选型:500万CCD配同轴光源,精度和像素是怎么算出来的

2.1 系统构成与工作流:相机、上位机、控制台的职责划分

论文把整个检测系统拆成四块:视频采集设备、控制单元、上位机(PC)以及上位机检测软件。视频采集设备再往下分是工业数字摄像机、光学镜头和光源,这三样决定了图像质量的上限;上位机是核心控制部分,负责摄像机采集控制,检测软件负责图像处理和信号输出;控制工作台接收上位机指令,做后续的剔料或报警动作。硬件通过1394接口与上位机相连,采集的图像数据直接传给上位机处理。

在实际产线里,这道流程可以整理成一条单向链路:产品到位触发 → 相机采集 → 图像经1394传输 → 上位机跑分割与分类算法 → 输出判别信号 → 控制台执行剔除。注意这里没有PLC做中间转译,上位机直接输出结果信号,好处是延迟低,坏处是上位机死机时整条检测线会停,所以论文里才强调要保证相机、镜头和光源由支架固定,减少外部环境变量对图像的影响。

2.2 把0.1mm检测精度换算成相机参数

论文给的关键指标是0.1mm检测精度、500万像素工业面阵CCD、单像素尺寸0.04mm。这三个数放在一起是能互相印证的:检测对象是100mm长、40mm宽的不锈钢材料,横向100mm如果对应约2500个像素,算下来每个像素就是0.04mm左右。0.1mm精度意味着缺陷区域在图像上至少占2到3个像素,既没过采样导致数据冗余和算法变慢,也没欠采样导致小缺陷根本显现不出来。

这个换算逻辑在选相机时很实用。500万像素听起来唬人,但真正决定检测能力的是“视野范围÷像素数”得到的单像素物理尺寸。同样500万像素,拍100mm视野和拍500mm视野,精度差5倍。论文选工业面阵CCD而不是CMOS或线阵相机,也是因为它要在固定视野内同时兼顾分辨率和帧率,面阵结构对静态工件的单次成像最直接。配1394接口而非USB,主要是工业现场传输稳定性考虑,1394连接在长距离和持续采集场景下丢帧率更低,2015年前后工业相机的主流接口就是它。

硬件模块选型参数作用
工业相机500万像素面阵CCD,单像素约0.04mm覆盖100mm×40mm视野,满足0.1mm精度
镜头定焦光学镜头保证成像清晰度,与CCD靶面匹配
光源LED同轴白光,正面打光均匀背景灰度,突出焊点轮廓
接口1394稳定传输图像数据至上位机
上位机工业PC完成图像处理、缺陷判别、信号输出

2.3 光源为什么选同轴白光正面打光

焊点检测的光源方案里,环形光、条形光、同轴光各有适用场景。论文最终选的是LED颗粒的同轴白色光源、正面打光方式,理由是“使得背景亮度均匀,即像素灰度值保持一致”。这句话在工程上非常关键:不锈钢表面反光厉害,如果用环形光,焊点边缘会出现一圈角度不同的高光带,同一个焊点内部灰度差能拉到几十甚至上百灰度级;Otsu阈值分割的假设是图像上有清晰的双峰灰度分布,背景灰度飘得越厉害,类间方差越难取到稳定极值。

同轴光的本质是让光线沿镜头光轴方向垂直照射被测面,反射光中只有平行于光轴的分量能原路返回进入镜头,镜面反射方向不匹配的部分被滤掉,所以背景会呈现均匀的暗场或均匀的亮场,具象到像素上就是灰度值在小范围内波动。这样后面做全局阈值分割时,焊点和背景的灰度差才是稳定的。我一般还会在光源支架上加一圈遮光罩,防止车间顶灯和日光直射造成灰度漂移,论文里用支架固定相机和光源已经考虑了这一点,但产线环境光变化往往比实验室大得多。

3. 焊点图像提取与Otsu分割:平滑卷积核与大津法阈值怎么落地

3.1 为什么不能直接对原图做二值化

焊点图像入手后的第一个坑就是直接二值化。二值化是一个逐像素的灰度映射,它不关心像素之间的空间关系。实际焊点图里存在三类干扰:一是图像获取和传输过程中产生的噪声点,类似椒盐噪声;二是背景里的焊渣,灰度和焊点边缘接近,直接二值化会一起被划成前景;三是多个焊点粘连在一起,二值化后连成一个连通域,根本数不清个数。论文明确说“传统的分割算法不能较好地适应此种情形”,指的就是这三个问题。

所以处理流程必须是串行的:先平滑去噪,再做全局阈值分割得到二值图,后续通过距离变换和分水岭把粘连焊点拆开。少了第一步,第三步分水岭会把噪声点也当成一个局部区域,产生大量碎片;少了第三步,粘连焊点会被合并成一个区域,面积特征直接失真,后面圆拟合和缺陷分类全错。

3.2 平滑处理:卷积核尺寸与计算逻辑

图像平滑在论文里给的是一个标准卷积公式,原始图像为f(x,y),卷积核为C(s,t),核大小为m×n,处理后图像为g(x,y),a=(m−1)/2,b=(n−1)/2,m和n取奇数。这里核的中心对应输出像素,卷积核滑动覆盖邻域后求和赋值。核尺寸是奇数这个细节不是随意写的,是为了保证核有唯一的中心像素,否则卷积结果会有半个像素的偏移。

卷积核取多大直接影响后续分割。核太小,比如3×3,对高斯噪声有轻微抑制,但对付不了焊渣这种成片的杂质;核太大,比如15×15以上,焊点边缘会被抹掉一层,边缘变圆钝,距离变换算出的中心位置和半径都会偏。论文的检测对象是焊点,直径在几十到上百像素之间,我一般先用5×5高斯核做平滑,再用3×3中值滤波扫掉孤立噪点,高斯负责整体去噪,中值负责去冲击噪声,两者配合比单用高斯稳得多。这段是参考论文平滑思路的常见做法,具体核尺寸要靠标定图试出来。

3.3 Otsu大津法原理与选型理由

大津法解决的问题是“阈值取多少”。固定阈值在实验室里看起来很美——打开一张图拉一下灰度直方图,取波谷当阈值就行;但产线连续工作后,光源衰减、工件批次差异、环境光微变都会让整张图的灰度分布整体平移,固定阈值立刻失效。Otsu不需要人工干预,它遍历0到255所有候选阈值,对每个阈值把像素分成前景背景两类,计算类间方差,取类间方差最大的那个阈值。

类间方差的核心公式是σ²=ω₀ω₁(μ₀−μ₁)²,其中ω₀、ω₁是两类像素占全图的比例,μ₀、μ₁是两类的平均灰度。两类灰度均值差越大且比例越均衡,类间方差越大,说明这个阈值把两类像素分得越开。Otsu的隐含假设是图像灰度分布接近双峰,焊点和背景灰度差明显,正好符合前面同轴光源制造出来的均匀背景条件。要注意Otsu不是万能的,如果背景灰度不均匀、出现第三个灰度峰,阈值会偏向占比大的那一类,造成前景区域膨胀或收缩——所以平滑和光源稳定必须在它之前做好。

3.4 OpenCV复现这一步的代码与参数

import cv2 import numpy as np # 读入灰度图,焊点检测全程用单通道图像处理即可 img = cv2.imread("solder_joint.bmp", cv2.IMREAD_GRAYSCALE) # 第一步:高斯平滑,核5x5,sigma=1.0 # sigma控制权重衰减速度,sigma越大模糊越强 blur = cv2.GaussianBlur(img, (5, 5), 1.0) # 第二步:中值滤波去孤立噪点,核3x3 # 中值滤波对椒盐噪声特别有效,且不引入新灰度值 blur = cv2.medianBlur(blur, 3) # 第三步:Otsu自动阈值分割 # threshold参数传0,配合THRESH_OTSU标志时会被忽略 _, binary = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

这段代码里,GaussianBlur的核尺寸决定去噪力度,5×5在焊点尺寸约40像素时不会明显侵蚀边缘;sigma取1.0~1.5之间,太大边缘模糊,太小高斯核退化成均值滤波。中值滤波的核只能取奇数,3×3够用。Otsu在OpenCV里的写法是threshold函数传0作为阈值参数,函数自己算最佳阈值并返回,所以返回值里第一个量是算出来的阈值,可以打印出来观察它随批次的变化。还有一个必须确认的细节:二值化后焊点应该是白色(255)还是黑色(0),取决于焊点相对背景的明暗。论文的焊点经距离变换后中心灰度小、边缘灰度大,说明焊点原始区域大概率比背景暗。如果跑出来前景背景反了,把THRESH_BINARY换成THRESH_BINARY_INV即可,我在产线上第一次跑就栽在这个极性问题上。

4. 倒三角距离变换与分水岭:粘连焊点分割的两板斧

4.1 距离变换到底在变换什么

二值图里只有0和255两类值,它包含的信息是“哪里是焊点、哪里是背景”,但完全不知道“焊点内部是什么结构”。粘连焊点半成品图里,两个焊点交叠后,二值层面上就是一个连通的白色区域,找不到分界线。距离变换做的事,是把这个白色区域里每个像素到最近背景像素的实际距离算出来,替换掉原来的二值灰度,让图像从“黑白二分”变成“从中心到边缘渐变的灰度图”。

对近似圆形的焊点来说,从中心沿径向到边缘,距离值依次递减;中心点离背景最远,边缘点距离接近1。论文里说的“中心灰度值小、边缘灰度值大”,是它们把距离值做了方向映射后的显示效果,本质上表达的是同一个空间关系。有了这个渐变的灰度信息,分水岭才有地形起伏可以划分,否则一张平地白图上无山可爬。两者是配套的:距离变换造地形,分水岭切割地形。

4.2 倒三角算法:两次扫描替代全局计算

理论上距离变换要算每个像素到所有背景像素的最小距离,是全局操作,图稍微大一点计算量就爆炸。论文采用倒三角法,把这个全局问题近似成局部传播问题。做法是准备两个3×3模板,一个前向模板、一个后向模板。前向模板按从左到右、自上而下的顺序扫描图像,模板中心下方的像素值由模板覆盖区域内计算出的最小值替换;后向模板按从右到左、自底向上的顺序再扫一遍。

倒三角的关键在于,中心像素到最近背景的距离,可以由它左、上、左上、右上这些已更新过的邻居距离加1推导出来,前向扫描装了半边信息,后向扫描补上另外半边,两趟下来距离场就收敛了。计算量从O(W×H×N)降成O(W×H),这里的N是背景像素数,实际场景里N可能占一半图像,这个优化直接决定了系统能不能跟上产线节拍。论文强调“倒三角”而不直接用OpenCV的cv2.distanceTransform,就是在讲这个效率问题。

4.3 分水岭分割:把灰度地形切开

分水岭算法理解起来有个很直观的画面:把距离变换后的灰度图假想成地形图,灰度值高的地方是山脊,灰度值低的地方是盆地。往每个盆地注水,水面上升,相邻盆地里的水快要汇合的地方就是分水岭——也就是粘连区域的切割线。论文的处理路径是先把灰度图像空间转化为梯度空间,再对梯度图做二值化,分成灰度高于和低于阈值的两部分,一部分叫陆地、一部分叫水域,中间的边界就是分水岭。

实际工程中用OpenCV实现分水岭,几乎不会做论文描述的“梯度图+二值化”那一步,而是直接用标记分水岭替代,核心是一句cv2.watershed。它接收一个三通道图像和一个标记矩阵,标记矩阵里提前标好哪些区域确定是焊点,分水岭只负责从这些标记出发划分边界。这么做的原因是原始分水岭对噪声太敏感,轻微的灰度扰动就会多出一堆假盆地,产生过度分割;标记分水岭相当于人为限定盆地数量,贴合焊点数。每个焊点中心在距离图上是一个局部极大值(或者论文映射后的局部极小值),把这些极值点提取出来做连通域标记,就是分水岭的种子。

4.4 OpenCV复现:distanceTransform与watershed配合

# binary是上一章Otsu输出的二值图,前景应为白色 # DIST_L2计算欧氏距离,maskSize=5是精度较高的近似核 dist = cv2.distanceTransform(binary, cv2.DIST_L2, 5) # 归一化到0~255方便显示和定阈值 dist_norm = cv2.normalize(dist, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8) # 标记阈值:大于0.4倍最大距离视为焊点中心区域 # 这个系数是整条流水线最需要标定的参数,密集焊点取低,稀疏焊点取高 _, markers_bin = cv2.threshold(dist_norm, 0.4 * 255, 255, cv2.THRESH_BINARY) # 先形态学开运算消除标记区域内的细小空洞和毛刺 markers_bin = cv2.morphologyEx(markers_bin, cv2.MORPH_OPEN, np.ones((3, 3), np.uint8)) # 连通域标记:每个焊点中心区域得到一个独立编号 _, markers = cv2.connectedComponents(markers_bin) # 分水岭约定:背景标记为1,未知区域标记为0 # 所以把所有标签+1,再把未知区域重新置0 markers = markers + 1 markers[markers_bin == 0] = 0 # watershed输入需要8位三通道图像,标记必须是32位单通道 # labels原地震动,边界区域会被置为-1 cv2.watershed(cv2.cvtColor(blur, cv2.COLOR_GRAY2BGR), markers)

这里两个参数值得单独说。第一个是maskSize=5,它控制距离变换邻域计算的近似精度,取5比取3更接近真实欧氏距离,代价是稍慢一点,对焊点这种需要精确半径的场景我直接用5。第二个是0.4倍阈值,这个数不是论文给定的,而是按“标记区域覆盖焊点中心但不连到边界”的原则试出来的。标记阈值取太高,一个焊点里可能出现两个分离的极值区域,分水岭会把好焊点切成两半;取太低,两个粘连焊点的中心区域连通成一个标记,分水岭无岭可切。我一般会把dist_norm的直方图画出来,取第一个峰到第二个峰之间的谷值位置换算成比例,一批产品标定一次,效果比拍脑袋定0.4稳得多。

5. 焊点缺陷判别的常见问题与避坑:面积判虚焊、灰度判焊穿的五个坑

5.1 最小二乘圆拟合:拟合对象是边缘不是区域

分水岭分割后的每个焊点区域已经独立了,但直接用连通域像素计算面积,受分割边界毛刺影响很大,而且拿不到圆心和半径,判断不了焊点圆度是否合格,所以论文在分割后加了一步圆拟合。拟合的原理是最小二乘法:设圆心为(A,B),半径为R,每个边缘样本点(xᵢ,yᵢ)到圆心距离的平方与R²的差最小化。展开后得到关于a、b、c的二次函数,对它求偏导等于零,解三元线性方程组就能得到圆心和半径。论文里公式(3)的Q(a,b,c)就是那个误差平方和。

工程实现上要注意拟合对象。分水岭标定的labels矩阵里,每个焊点区域是一个独立的标签值,先取出该标签的掩膜,再在掩膜上找轮廓。轮廓提取用RETR_EXTERNAL只取最外层轮廓,不能带内孔,否则焊点中心区域叠加出第二层点集,拟合圆会被拉偏。OpenCV里cv2.minEnclosingCircle给的是最小外接圆,cv2.fitEllipse给的是最小二乘椭圆,严格做“最小二乘拟合圆”最接近的是对轮廓点自己算方程组。我实际测试下来,合格焊点近似正圆,fitEllipse返回的长短轴之差能当一个辅助圆度特征,比单用一个圆半径信息更丰富。

circles = [] for label_id in range(1, markers.max() + 1): mask = np.where(markers == label_id, 255, 0).astype(np.uint8) contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) if not contours: continue # 多个轮廓取面积最大的,排除边缘残留碎片 contour = max(contours, key=cv2.contourArea) pts = contour.squeeze() if pts.ndim != 2 or len(pts) < 5: continue # 点数太少不构成圆 (x, y), r = cv2.minEnclosingCircle(pts) area = cv2.contourArea(contour) circles.append((x, y, r, area, label_id))

轮廓的CHAIN_APPROX_NONE保留全部轮廓点不压缩,保证最小二乘拟合有足够样本点;用max按面积挑最大轮廓,是因为分水岭偶尔会在焊点外围切出一圈薄边碎片,面积显著小于主区域,直接忽略。这里判断“点数少于5就跳过”是防止残留的小噪声区域混进后面分类。

5.2 虚焊和焊穿的判别特征组合

论文对缺陷的判别逻辑很简洁,只针对两种主要缺陷:虚焊和焊穿。虚焊是两侧电极压力过小或电流过小,导致焊件没贴紧、熔合不充分,表现是焊点面积比正常焊点小一圈;焊穿是电流过大,工件被直接烧穿,表现是焊点内部灰度均匀、没有正常焊点那种明显的亮色反射中心。前者看几何,后者看灰度。

面积阈值怎么定:正常焊点面积标定后取均值,虚焊的判定线通常设在均值的60%~80%,低于就判虚焊。这正好呼应论文里“虚焊面积较小”的结论。焊穿判定不能只看面积,因为焊穿边缘可能外扩,面积未必小。需要在拟合圆内部做一个圆形ROI,半径取拟合半径的0.7~0.8倍避开口部边缘,统计ROI内的灰度方差。正常焊点中心区域反射亮、边缘暗,方差大;焊穿区域因为穿孔破坏了金属表面结构,反射均匀,方差明显小于正常焊点。用“面积阈值判虚焊、灰度方差判焊穿”一前一后串成判断链,比单看任一特征稳。

5.3 产线落地的五个踩坑记录

坑一:Otsu二值化前景背景极性搞反。现象是距离变换图完全不按论文描述的“中心灰度小、边缘灰度大”分布,分水岭跑出来碎片极多。原因是焊点在原图里是暗底亮斑还是亮底暗斑取决于光源类型和金属反射,不同批次材料表面状态会变。解决方法是每次切换产品或调整光源后,先打印二值图确认焊点区域是255,不对就用THRESH_BINARY_INV重新生成。

坑二:距离图标记阈值0.4一把走天下,换产品就崩。现象是焊点密集排列时正常焊点被切开,稀疏排列时粘连焊点又合在一起。原因是不同位置的焊点距离分布完全不同,同一个标记阈值不可能同时适配。解决方法是每个产品型号单独标定一组阈值:收集20张有代表性的图,叠加画出距离图直方图,取波谷比例作为初始值,再按分割结果微调。

坑三:焊渣被当成小焊点,误检漏检同时升高。现象是背景焊渣经过距离变换和分水岭后自成一块,拟合出很小半径的圆,被当作虚焊,误报率几十个百分点。原因是焊渣灰度与焊点边缘接近,Otsu把它归进前景。解决方法是在面积分类前加一个最低面积过滤,取标定正常焊点面积的70%作为下限,小于下限的区域直接丢弃,不进分类器。

坑四:车间环境光变化造成灰度漂移。现象是上午调好的阈值到下午误检率飙升,Otsu自己算出的阈值跟着变化。原因是遮光罩没加或光源支架松了,日光角度变化引起背景灰度整体偏移。解决方法是先检查机械固定再谈算法,软件侧把每次Otsu算出的阈值打日志,观察它是否随时间段漂移;漂移超过10个灰度级就检查遮光和光源,这是产线视觉落地的第一课。

坑五:分水岭把一个好焊点切成了碎块。现象是一个焊点被分成两三块,每块面积都偏小,全部误判成虚焊。原因是焊点表面的纹理、划痕在距离图上形成小的局部谷底,原始分水岭把每个谷底当独立盆地。解决方法是改用标记分水岭,先用形态学开运算把细纹理抹掉,再连通域提取标记,标记数量被限制成“一个焊点最多一个中心”,分水岭只负责边界划分,不再生成新区域。

6. 效果验证与参数调优技巧:200块样本的对比实验怎么读

6.1 配备前后的对比实验设计

论文第3节的系统功能测试提供了一个很好的验证模板:在点焊机没有视觉系统前,生产200块产品用人工检测;配备视觉系统后,再生产200块用视觉检测,两边做数据对比。结论是配备视觉系统后能较好地识别出有缺陷的焊点,避免误检漏检的情况。这个实验设计的精髓在于保持样本量一致、生产条件一致,只改变检测手段。人工目检在连续工作两小时后注意力下降,漏检率会明显上升;视觉系统正好补上人眼疲劳这段短板。

在实际复现这套方案时,建议沿用这个200块样本的验证思路,但评价指标拆成三个:漏检率、误检率和判定一致性。漏检率指有缺陷焊点被当成了合格品,这是质量事故,必须压到最低;误检率指合格品被当成缺陷品,它带来的是返工和产能损失;判定一致性是同一批图像用视觉系统跑三次,结果完全一致的比例,用于验证算法稳定性。

def report_stats(gt_labels, pred_labels): # gt是人工确认的标签:1正常,0缺陷 # pred是视觉检测输出:1正常,0缺陷 tp = sum(1 for g, p in zip(gt_labels, pred_labels) if g == 1 and p == 1) fn = sum(1 for g, p in zip(gt_labels, pred_labels) if g == 1 and p == 0) fp = sum(1 for g, p in zip(gt_labels, pred_labels) if g == 0 and p == 1) tn = sum(1 for g, p in zip(gt_labels, pred_labels) if g == 0 and p == 0) print("漏检率: %.2f%%" % (fn / (tp + fn) * 100)) print("误检率: %.2f%%" % (fp / (fp + tn) * 100)) print("一致性: %.2f%%" % ((tp + tn) / len(gt_labels) * 100))

6.2 参数调优顺序与一个快速验证习惯

这套流程的调参点集中在四个位置:高斯核与中值核的尺寸、Otsu的前景极性、距离图标记阈值、面积与灰度方差分类阈值。我踩下来的顺序是:先把光源和相机曝光固定死,让同轴光下背景灰度均值稳定在一个窄区间;再确认二值图极性正确;接着调距离图标记阈值,保证分水岭不碎也不粘连;最后才是面积阈值和灰度方差阈值。前三步错了,调面积阈值全是白费。

快速验证方面,不要每调一次参数就看一两张效果图,那样对分割质量的判断会被偶然性带偏。我一般会固定抽20张跨时段、跨批次的生产图,跑一遍流程后把分水岭和圆拟合的结果叠加在原图上输出一张标注图,一张一张过,记录“碎了多少个”“漏了哪几个”“多出来哪几个”。全部改完后重新跑一遍这20张,确认没有回归。从那以后我每次给产线配视觉检测方案,都强制自己走完这20张回归验证再上线,哪怕是只改了一个核尺寸也要重跑。算法在实验室里跑出九成五不算数,产线连续焊两小时还能稳定在九成以上才算数。希望帮到你。

本文还有配套的精品资源,点击获取

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

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

立即咨询