
简介这份资源面向计算机、人工智能、自动化、电子信息等专业的在校学生与教师以及希望进阶学习机器视觉的开发者提供一套基于Python与OpenCV的漆包线点焊焊盘状态识别完整项目源码。项目围绕工业视觉检测场景通过图像采集与算法处理判断焊盘状态可用于毕业设计、课程设计、作业或项目初期立项演示。压缩包共13个文件包含5个Python脚本、7张jpg测试图像和1份md说明文档整体约868KB脚本覆盖主流程、图像估计、ROI提取与功能函数等模块图片则用于验证不同焊盘状态下的识别效果。目前已有107人学习。代码经过实际运行测试答辩评审平均分达96分读者可据此理解视觉检测的完整实现思路并在此基础上修改扩展实现其他识别功能。下载后建议先阅读README.md仅供学习参考切勿用于商业用途。1. 漆包线点焊焊盘状态识别为什么传统视觉方案在产线上总翻车漆包线点焊的焊盘状态识别说白了就是在焊完那一瞬间判断焊盘上到底有没有真正熔接、有没有虚焊、有没有烧穿或者偏位。这个场景在电机、电感、变压器产线上极其常见但真正用 Python OpenCV 视觉传感器把它做稳的团队并不多。原因不复杂焊盘本身只有零点几毫米到两三毫米漆包线绝缘层在高温下会飞溅、发黑、反光普通工业相机拍出来的图人眼都要盯半天更别说让算法稳定判读。很多工程师第一次上手用模板匹配或者简单阈值分割白天调好的参数到了夜班或者换了批次线材就集体翻车这就是典型的玄学现场。这篇笔记面向的是已经会用 Python 和 OpenCV 做基础图像处理、但想把漆包线点焊焊盘状态识别真正落到产线节拍里的从业者。我会把光源选型、ROI 标定、特征提取、分类逻辑和现场排查按可复现的顺序讲清楚不堆概念直接给能抄的代码和参数边界。2. 焊盘状态识别的成像链路从光源到 OpenCV 读取的第一帧2.1 为什么同轴光加低角度环形光组合是漆包线焊盘的首选漆包线点焊焊盘的核心成像难点有三个金属焊盘镜面反光、漆包线绝缘层碳化后发黑、焊点周围有飞溅颗粒。如果只用普通环形光焊盘中心会过曝成一片白OpenCV 读进来之后灰度值直接顶到 255阈值分割完全失效。如果只用低角度光焊盘边缘阴影太重焊点轮廓会被吃掉。我一般会选同轴光负责压住焊盘镜面反射让焊盘本体呈现均匀的中灰再用低角度环形光把焊点凸起和飞溅颗粒的轮廓勾出来。这个组合在 2 mm 以内的焊盘上能把焊点与焊盘本体的灰度差拉到 40 到 70 个灰度级给后面的 OpenCV 处理留出足够余量。相机方面不要盲目追高分辨率。漆包线焊盘识别真正吃的是景深和帧率。常见做法是选 500 万像素、2/3 英寸靶面、配合 0.5 倍远心镜头工作距离控制在 110 mm 左右视野大约 12 mm × 9 mm这样单个焊盘在图像里能占到 300 到 500 像素宽。帧率至少 60 fps因为点焊节拍通常在 200 到 400 ms 一次曝光时间要压到 1 ms 以内否则焊点余温产生的红外辐射会让图像发灰。曝光和增益一旦定下来产线换班时不要让人随手调这是血泪经验。2.2 用 Python 读取相机并锁定曝光的最小代码下面这段代码是 OpenCV 读取工业相机并锁定关键参数的骨架。不同品牌相机 SDK 不一样但思路一致先关自动曝光、自动增益、自动白平衡再设固定值最后连续抓帧确认稳定性。import cv2 import numpy as np # 常见做法是用相机的 DirectShow 或厂商 SDK 打开这里以 cv2.VideoCapture 索引方式示意 cap cv2.VideoCapture(0, cv2.CAP_DSHOW) if not cap.isOpened(): raise RuntimeError(相机未打开检查索引或 SDK 环境) # 锁定曝光与增益避免产线亮度漂移 cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0.25) # 0.25 表示手动曝光模式不同后端取值有差异 cap.set(cv2.CAP_PROP_EXPOSURE, -6) # 曝光值需按实际光源亮度标定 cap.set(cv2.CAP_PROP_GAIN, 0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 2448) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 2048) # 连续抓 30 帧观察灰度均值波动 means [] for i in range(30): ret, frame cap.read() if not ret: continue gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) means.append(gray.mean()) print(灰度均值波动范围:, min(means), max(means)) cap.release()逻辑说明CAP_PROP_AUTO_EXPOSURE设为 0.25 是 OpenCV 在 DirectShow 后端下切手动曝光的常见写法但不同相机后端取值可能是 0 或 1需要实测确认。CAP_PROP_EXPOSURE的负值代表曝光时间档位不是毫秒必须配合光源亮度用灰度均值来标定。参数说明如果灰度均值波动超过 3 个灰度级说明光源供电不稳或者相机自动增益没关干净先查光源控制器再查相机 SDK 里是否有隐藏的自动优化选项。这一步不做稳后面所有识别都是空中楼阁。2.3 ROI 标定把焊盘从整幅图里抠出来的三个约束整幅图里焊盘只占很小一块直接全图处理既慢又容易被飞溅干扰。ROI 标定我一般用三个约束机械定位销位置、焊盘模板匹配、以及上一帧焊点重心。产线夹具通常有定位销相机固定后焊盘在图像里的位置漂移一般在 ±15 像素以内所以可以先手动框一个比焊盘大 1.5 倍的矩形作为粗 ROI。然后用cv2.matchTemplate在粗 ROI 里找焊盘轮廓模板把 ROI 收缩到焊盘外接矩形。最后用上一帧焊点重心做二次校正防止模板匹配被飞溅颗粒带偏。def locate_pad_roi(frame_gray, template, coarse_roi): x, y, w, h coarse_roi roi frame_gray[y:yh, x:xw] res cv2.matchTemplate(roi, template, cv2.TM_CCOEFF_NORMED) _, max_val, _, max_loc cv2.minMaxLoc(res) if max_val 0.6: return None, max_val tx, ty max_loc pad_roi (x tx, y ty, template.shape[1], template.shape[0]) return pad_roi, max_val逻辑说明TM_CCOEFF_NORMED对亮度线性变化不敏感适合产线光源轻微波动。max_val低于 0.6 时直接返回 None交给上层逻辑报警不要硬着头皮往下做。参数说明模板必须从良品焊盘上截取且要包含焊盘边缘和一小圈基板不要只截焊盘中心。粗 ROI 的宽高建议是焊盘实际尺寸的 1.5 到 2 倍太小容易丢太大匹配耗时上升。3. 焊盘状态特征提取从灰度、边缘到焊点几何量3.1 用自适应阈值和形态学把焊点区域分离出来焊盘状态识别不是单纯分类而是要先稳定地把焊点区域从焊盘背景里分出来。漆包线焊点通常比焊盘本体亮或者暗取决于光源角度和焊点氧化程度。固定阈值在换批次线材时必然翻车所以要用自适应阈值。OpenCV 里cv2.adaptiveThreshold配合高斯窗口在焊盘 ROI 内做局部二值化能把焊点轮廓和飞溅颗粒同时保留下来。然后做开运算去掉小飞溅再做闭运算把焊点内部空洞填上。def extract_weld_region(pad_gray): # 自适应阈值窗口大小取焊盘宽度的 1/5 左右且为奇数 block_size 31 binary cv2.adaptiveThreshold( pad_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, block_size, 8 ) kernel cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) opened cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel, iterations1) closed cv2.morphologyEx(opened, cv2.MORPH_CLOSE, kernel, iterations2) return closed逻辑说明THRESH_BINARY_INV是因为焊点通常比周围暗反相后焊点变成白色前景。block_size取 31 是在 300 像素宽焊盘上的经验值焊盘越小要相应调小但必须是奇数。C值取 8 是偏保守的如果焊点对比度低可以降到 5但飞溅会变多。参数说明开运算迭代 1 次去掉小飞溅闭运算迭代 2 次填焊点内部空洞迭代次数不要超过 3否则焊点边缘会被腐蚀变形。3.2 焊点面积、圆度和重心偏移三个特征怎么算分离出焊点区域后用cv2.findContours拿轮廓再算三个核心特征面积、圆度、重心相对焊盘中心的偏移。面积直接反映焊点大小虚焊通常面积偏小烧穿面积偏大。圆度用4πA/P²计算良品焊点接近圆形偏位或者拉尖会明显偏离。重心偏移用轮廓矩算能捕捉焊点是否偏向焊盘一侧。def weld_features(contour, pad_center): area cv2.contourArea(contour) perimeter cv2.arcLength(contour, True) if perimeter 0: return None circularity 4 * np.pi * area / (perimeter * perimeter) M cv2.moments(contour) if M[m00] 0: return None cx M[m10] / M[m00] cy M[m01] / M[m00] offset np.sqrt((cx - pad_center[0])**2 (cy - pad_center[1])**2) return area, circularity, offset逻辑说明cv2.moments算重心是标准做法但要注意轮廓必须是闭合的且m00不能为 0。参数说明面积阈值要按实际焊盘尺寸标定比如 0.8 mm 焊盘良品面积大约在 800 到 1500 像素之间具体取决于放大倍率。圆度良品一般在 0.75 以上低于 0.6 基本可以判偏位或拉尖。重心偏移超过焊盘半径的 25% 就要警惕。3.3 用颜色通道辅助判断氧化和烧穿灰度特征对氧化和烧穿的区分能力有限这时候要引入颜色通道。漆包线绝缘层碳化后偏黑褐烧穿焊盘会发蓝或者发紫良品焊点偏银灰。把 ROI 转到 HSV 空间看 H 通道的均值和 S 通道的方差能补上灰度特征的盲区。def color_features(pad_bgr): hsv cv2.cvtColor(pad_bgr, cv2.COLOR_BGR2HSV) h_mean hsv[:, :, 0].mean() s_std hsv[:, :, 1].std() v_mean hsv[:, :, 2].mean() return h_mean, s_std, v_mean逻辑说明H 通道均值偏移超过 10 个色度单位往往意味着氧化或者烧穿。S 通道标准差大说明颜色不均匀可能是飞溅或者局部烧焦。参数说明这些阈值必须在产线现场用良品和不良品各 50 张图统计出来不要照搬网上的通用值。颜色特征只做辅助最终判定还是以几何特征为主颜色特征做二次确认。4. 分类逻辑与产线节拍规则、阈值和轻量模型怎么选4.1 规则阈值分类在什么条件下够用如果产线焊盘型号单一、光源稳定、节拍在 300 ms 以上规则阈值分类完全够用而且比模型更好维护。我一般会设三层规则第一层面积第二层圆度第三层重心偏移。三层都过判良品任意一层不过进入下一层细分。面积偏小且圆度高判虚焊面积偏大且圆度低判烧穿重心偏移大判偏位。这套规则在单一型号产线上能做到 97% 以上的准确率而且调参直观产线工程师自己就能改。def classify_weld(area, circularity, offset, pad_radius): if area 800: return 虚焊 if area 1800: return 烧穿 if circularity 0.6: return 拉尖或偏位 if offset pad_radius * 0.25: return 偏位 return 良品逻辑说明阈值 800、1800、0.6、0.25 都是示例必须按实际标定替换。参数说明pad_radius是焊盘半径的像素值不是物理半径。如果产线换型频繁建议把阈值做成配置文件不要硬编码在函数里。4.2 什么时候必须上轻量分类模型当焊盘型号超过三种、或者飞溅形态复杂到规则覆盖不住时就要上轻量分类模型。不要一上来就 YOLO焊盘状态识别是 ROI 内的分类问题不是检测问题。常见做法是把 ROI 缩放到 64×64提取几何特征和颜色特征拼成 8 维向量用一个三层的全连接网络或者 SVM 做分类。OpenCV 自带的cv2.ml.SVM_create就够用训练样本每类 200 张起步特征归一化后训练推理耗时在 1 ms 以内完全不影响节拍。import cv2 import numpy as np # 假设 features 是 N×8 的 float32 矩阵labels 是 N×1 的 int32 svm cv2.ml.SVM_create() svm.setKernel(cv2.ml.SVM_RBF) svm.setC(10) svm.setGamma(0.1) svm.train(features, cv2.ml.ROW_SAMPLE, labels) # 推理 sample np.array([[area, circularity, offset, h_mean, s_std, v_mean, area_ratio, edge_gradient]], dtypenp.float32) _, pred svm.predict(sample)逻辑说明SVM_RBF在小样本上比神经网络稳C和Gamma用网格搜索在验证集上选。参数说明特征必须做归一化否则面积会压死其他特征。area_ratio是焊点面积除以焊盘面积edge_gradient是焊点边缘平均梯度这两个特征对虚焊和烧穿区分度很高。4.3 节拍控制从抓帧到出结果的耗时预算产线节拍 300 ms意味着从抓帧到出结果不能超过 200 ms留 100 ms 给通信和机械动作。抓帧 10 msROI 定位 15 ms特征提取 20 ms分类 5 ms总共 50 ms 左右余量充足。但如果用模板匹配全图搜索或者用深度学习模型耗时可能直接冲到 150 ms 以上。优化手段ROI 定位只在第一帧做全搜索后续帧用上一帧位置做局部搜索特征提取只在焊盘 ROI 内做不要全图跑形态学。5. 避坑与排查漆包线焊盘识别现场最常见的五个翻车点5.1 现象白天良品率 98%夜班掉到 70%原因产线夜间电压波动导致光源亮度变化或者环境光从设备缝隙漏进来。OpenCV 读到的灰度均值漂移固定阈值失效。解决光源控制器加稳压设备加遮光罩同时在代码里加灰度均值监控超过 ±5 灰度级就报警并自动重标定阈值。5.2 现象换批次漆包线后虚焊误判暴增原因不同批次漆包线绝缘层厚度和碳化程度不同焊点颜色和面积分布整体偏移。解决每换批次先跑 20 个良品做阈值自适应用良品特征的均值和标准差重新设阈值不要沿用上一批次的固定值。5.3 现象飞溅颗粒被当成焊点面积特征完全乱掉原因开运算核太小或者自适应阈值C值太低飞溅被保留下来。解决开运算核从 3×3 加到 5×5C值从 5 提到 8 到 10同时加面积过滤小于 200 像素的轮廓直接丢弃。5.4 现象焊盘边缘反光导致 ROI 定位漂移原因模板匹配对高光敏感焊盘边缘过曝后模板匹配分数下降ROI 跑到飞溅区域。解决模板匹配前先做高斯模糊或者改用边缘模板匹配同时把max_val阈值从 0.6 提到 0.7宁可报警也不要乱定位。5.5 现象OpenCV 报cv2.error或ModuleNotFoundError: No module named opencv原因环境里装了多个 Python 版本或者 OpenCV 安装不完整。解决先用python -c import cv2; print(cv2.__version__)确认版本如果报错就重装opencv-python和opencv-contrib-python注意两者版本要一致。Ubuntu 下如果cv2找不到检查PYTHONPATH和apt安装的python3-opencv是否冲突。6. 把识别结果用起来从单帧判定到产线闭环的一个具体技巧单帧判定只能告诉你这一焊点好不好但产线真正需要的是趋势和闭环。我一般会在识别结果上加一个滑动窗口统计连续 20 个焊点的面积均值和圆度均值如果面积均值连续下降说明电极磨损或者焊接能量在衰减这时候提前提醒换电极比等到批量虚焊再停线要划算得多。这个技巧不需要额外硬件纯软件就能做。from collections import deque area_window deque(maxlen20) circularity_window deque(maxlen20) def trend_alert(area, circularity): area_window.append(area) circularity_window.append(circularity) if len(area_window) 20: return 预热中 area_mean np.mean(area_window) circ_mean np.mean(circularity_window) if area_mean 900 and circ_mean 0.7: return 电极磨损预警 if area_mean 1700: return 能量过高预警 return 正常逻辑说明deque固定窗口长度避免内存无限增长。面积均值下降且圆度仍然高说明焊点在变小但形状还圆典型电极磨损特征。参数说明窗口长度 20 是按节拍 300 ms 算的大约覆盖 6 秒产线状态太长反应慢太短误报多。阈值 900 和 1700 要按实际良品分布调整。验证方法上我习惯每周抽 30 个焊点做金相切片把视觉判定结果和金相结果对齐算混淆矩阵。如果虚焊漏判超过 2%就回头查光源和阈值如果烧穿误判超过 3%就查颜色特征和面积上限。这个习惯坚持了三年比任何调参玄学都管用。希望帮到你。本文还有配套的精品资源点击获取