简介基于SVM的焊接缺陷图片识别分类Python工程包适合计算机视觉、智能制造相关专业学生及入门者学习。项目围绕未焊透、未熔合等典型缺陷类别提供完整图像数据集与可直接运行的Python源码需自行训练模型便于深入理解支持向量机在图像分类任务中的实际应用与调参流程。资源共144个文件包括140张样本图片、3个Python脚本及1个数据压缩包整体仅1.7MB结构简洁适合快速上手实验与二次开发。已有518人学习下载。通过该项目可掌握图片预处理、特征提取、SVM模型训练与分类评估的完整链路并可根据自身数据扩展缺陷类别作为课程设计或毕业设计的基础方案。1. 焊接缺陷识别为什么值得用 SVM 而不是一上来就堆 CNN焊接质量检测在制造业里是典型的「小样本、高误判代价」场景。焊缝表面缺陷的常见形态包括气孔、夹渣、未熔合、咬边和裂纹这类缺陷图像往往结构单一、背景相对固定和有数百万参数可调的数据驱动模型相比SVM 在几百到几千张样本量下反而更容易训练收敛过程不依赖昂贵的 GPU而且决策边界清晰便于在生产线上做单一类别的阈值卡控。你拿到的这个「基于SVM实现焊接缺陷图片识别分类Python源码(含数据集)」本质上就是一套完整的特征工程加浅层分类器流程先用图像处理手段把像素矩阵变成紧凑的描述子再交给 SVM 做多分类。这个方向对 Python 基础要求不高但非常依赖你对数据预处理和特征设计是否敏感。数据集里通常包含正常的无缺陷样本和各类缺陷样本训练集与测试集往往已经按目录分好你需要自己跑通 HOG/LBP/颜色矩这类特征抽取再用交叉验证挑 SVM 的核函数与惩罚系数。适合的人群是刚接触图片识别分类的工程师、需要对产线做快速缺陷初筛的质检开发以及想在传统机器学习和深度学习之间找一条低成本落地路径的团队。2. SVM 处理焊接缺陷图片的建模思路与数据准备细节2.1 为什么 SVM 在焊接缺陷场景下能保住精度底线SVM 的核心思想是寻找几何间隔最大的超平面这在高维空间里等价于让少数支持向量决定边界。焊接缺陷图片的类别之间差异往往是局部纹理和灰度的集中差异比如气孔呈现为均匀暗斑、裂纹表现为细条状暗区、未熔合则是边缘不规则的灰白区域。这些特征在原始像素空间里重叠度尚可接受但经过 HOG 或 LBP 编码后会被映射到更容易线性分开的描述子空间中。SVM 的优势这时候就体现出来了它对小样本的泛化能力远好于随机森林或朴素贝叶斯在几百个样本上也不容易出现过拟合。核函数的选择会让这个结论成立与否产生巨大变化。线性核在焊接缺陷这类低中维特征上往往是首选RBF 核则是在你无法确定特征尺度、又有足够样本调参时才值得投入。RBF 核对应无限维映射几乎总能找到一个分界面但也意味着稍微改一下 γ 值模型就会在「欠拟合」和「边界的每个点都是支持向量」之间剧烈摇摆。2.2 拿到训练集后必须做的三个预处理动作步骤常用操作为什么重要灰度化与去噪cv2.cvtColor cv2.bilateralFilter焊接飞溅产生的椒盐噪声会直接污染纹理特征双边滤波能在保边的前提下去除孤立亮点尺寸统一cv2.resize 到 64×64 或 128×128SVM 不接收变长输入而特征向量维度也依赖图像尺寸归一化像素除以 255 或做 Z-scoreRBF 核基于距离计算特征尺度不一致会让数值大的维度主导决策实际项目里你会发现「尺寸统一」的重要性可能超过很多人的预期。焊接缺陷的尺度在图像里有时候只有十几个像素宽如果你把 512×512 的原图直接压到 32×32气孔和夹渣的区分度就几乎消失了。我一般会先做一个简单统计查看数据集中每个类别的包围盒面积如果面积差异超过五倍就考虑按长边等比缩放并填充黑边到固定尺寸而不是粗暴拉伸变形。2.3 训练集划分里最容易踩的坑组内相关性泄漏很多焊接缺陷数据集是按「焊缝段」为单位采样的同一段焊缝的照片之间光照和背景高度相似。直接 random split 会导致模型记住的是焊缝本身的背景特征而非缺陷特征测试集准确率会虚高五个点以上。正确的做法是先按焊缝段标签做分组再拆训练集和验证集。如果源代码里没有提供 group 信息你可以按文件名前缀推断或者用聚类给图片打上近似组号总之不能裸用 train_test_split。3. 用 Python 在本地跑通焊接缺陷分类的最小特征工程加 SVM 流程3.1 特征抽取HOG 描述焊缝纹理结构LBP 补充局部灰度模式下面是一段可直接替换数据路径的代码。我假设数据集目录结构为train/与val/各自下分normal、porosity、slag、lack_of_fusion等子目录。import os import cv2 import numpy as np from skimage.feature import hog, local_binary_pattern IMG_SIZE 128 HOG_ORIENTATIONS 9 PIX_PER_CELL (8, 8) CELLS_PER_BLOCK (2, 2) LBP_RADIUS 3 LBP_POINTS 8 * LBP_RADIUS def extract_features(image): gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) gray cv2.bilateralFilter(gray, d5, sigmaColor75, sigmaSpace75) gray cv2.resize(gray, (IMG_SIZE, IMG_SIZE)) # HOG 特征捕获梯度方向和强度分布 hog_vec hog(gray, orientationsHOG_ORIENTATIONS, pixels_per_cellPIX_PER_CELL, cells_per_blockCELLS_PER_BLOCK, block_normL2-Hys) # LBP 特征捕获局部灰度模式对光照变化相对鲁棒 lbp local_binary_pattern(gray, LBP_POINTS, LBP_RADIUS, methoduniform) lbp_hist, _ np.histogram(lbp.ravel(), binsnp.arange(0, LBP_POINTS 3), range(0, LBP_POINTS 2)) lbp_hist lbp_hist.astype(float) lbp_hist / (lbp_hist.sum() 1e-6) return np.concatenate([hog_vec, lbp_hist]) def load_dataset(base_dir): X, y [], [] for label_id, label_name in enumerate(sorted(os.listdir(base_dir))): label_dir os.path.join(base_dir, label_name) if not os.path.isdir(label_dir): continue for fname in os.listdir(label_dir): path os.path.join(label_dir, fname) img cv2.imread(path) if img is None: continue X.append(extract_features(img)) y.append(label_id) return np.array(X), np.array(y)HOG 参数中orientations9是经典配置表示把梯度方向划分为 9 个桶pixels_per_cell(8, 8)决定局部区域的粒度。焊接缺陷的边缘轮廓在 8×8 的窗口下能被较好地描述更小的(4, 4)会让维度爆炸而(16, 16)可能漏掉细小裂纹。LBP 的methoduniform会保留大多数有意义又对旋转敏感度较低的二进制模式直方图归一化后每个图像的 LBP 特征是确定维度的不用担心中间值不同导致维度不一致。3.2 训练与验证先标准化再做 PCA 降维特征维度通常是一千到两千这对 SVM 来说尚可接受但高相关性的特征会让核矩阵的条件数变大训练收敛变慢。所以我会在特征进 SVM 之前加StandardScaler和PCA把主成分保留数量设置在解释方差 95% 或者固定维度 100 到 200。from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from sklearn.decomposition import PCA from sklearn.svm import SVC from sklearn.model_selection import GridSearchCV, StratifiedKFold X_train, y_train load_dataset(path/to/train) X_val, y_val load_dataset(path/to/val) pipeline Pipeline([ (scaler, StandardScaler()), (pca, PCA(n_components0.95)), (svm, SVC(kernelrbf, probabilityTrue)) ]) param_grid { svm__C: [0.1, 1, 10, 100], svm__gamma: [scale, 0.001, 0.01, 0.1], } cv StratifiedKFold(n_splits5, shuffleTrue, random_state42) grid GridSearchCV(pipeline, param_grid, cvcv, scoringf1_macro, n_jobs-1) grid.fit(X_train, y_train) print(best params:, grid.best_params_) print(val score:, grid.score(X_val, y_val))StratifiedKFold在这里是必须的因为焊接缺陷类别极不平衡普通 KFold 可能在某一折里完全看不到normal类。f1_macro作为评分指标比accuracy更能反映少数类被正确识别的能力因为如果一个模型把所有缺陷图都判成正常准确率可能高达 80%但产线上根本没法用。probabilityTrue表示启用 Platt 缩放为每个样本输出一个置信度这在后面做漏检回查和阈值调整时非常关键。PCA 使用n_components0.95是自动选择主成分个数的写法比硬编码 200 更稳妥因为不同数据集的解释方差曲线形状差异很大。3.3 多分类策略SVM 默认的一对一投票是否适用焊接缺陷默认SVC多分类是decision_function_shapeovr只在接口上改变返回值风格真正起作用的还是底层的一对多或一对一。焊接缺陷类别之间不是完全互斥的夹渣和未熔合在视觉上都是亮块和不规则暗区共存它们的特征分布会有重叠。一对一投票通常比一对多更适合这种局部混淆严重的场景因为每个子分类器只需要在正负两个类别之间找边界不会被迫学习「其他所有类」的混合分布。因为sklearn的SVC内部本来就是一对一外部不用改参数只要别被文档里的decision_function_shape搞混就行。4. 训练焊接缺陷 SVM 时的超参数边界与性能卡控4.1 C 和 gamma 的合理取值区间到底怎么划定焊接缺陷图片的特征在归一化后C 的语义是误分类惩罚强度太小会欠拟合太小会导致每个训练样本都要被正确分类。对一百到一千张图像的数据集C 在 1 到 100 之间通常有可接受的表现超过 100 容易让模型记住噪声。gamma 是 RBF 核的半径因子gammascale让 sklearn 根据特征方差自动设初值一般够用手动设的话可以看训练集和验证集准确率的差值差值超过五到六个点就说明 gamma 太大了。现象参数嫌疑纠正手段训练集 99%验证集 82%gamma 过大或 C 过大gamma 减小到 0.001 级别C 退回 10 以内训练集 70%验证集 69%C 过小或 gamma 太小增大 C 到 10 或 100gamma 改 0.01验证集波动超过 8%数据划分或特征不稳检查组泄漏改用分组交叉验证4.2 数据不均衡的后果比想象中严重偏向多数类与不可用的召回率焊接缺陷数据里normal往往占 60% 以上crack可能只占 5%。直接用原始分布训练SVM 为了最大化整体准确率会把少数类推向决策边界外侧表现出「缺陷召回率极低」。解决思路不是在 SVM 里改 class_weight而是先观察混淆矩阵确认哪些缺陷之间发生了混淆。from sklearn.metrics import classification_report, confusion_matrix pred grid.predict(X_val) print(classification_report(y_val, pred, target_names[normal, porosity, slag, lack_of_fusion, crack])) cm confusion_matrix(y_val, pred) print(cm)若输出显示crack被大量误判为normal说明特征维度里裂纹的信息太弱。我一般会先尝试把HOG_ORIENTATIONS从 9 调到 12因为裂纹方向性极强更多的方向桶能更好编码这个信息。如果仍然不行再加入一个针对裂纹的专用特征计算灰度图像在不同方向上的梯度响应极值比比直接调class_weight更有效。4.3 训练时长与硬件定位CPU 上跑多久才合理焊接缺陷图片数量通常在几百到几千张特征维度 1000 多。PCA 后降到 200 以下这种情况下 RBF 核 SVM 在 CPU 上训练时间从秒级到十几分钟不等交叉验证乘以五折后也就半小时左右。若训练超过一小时还没结束建议优先检查特征维度是否一万以上其次看 cachesize 是否被改小了。不需要 GPU只要内存足够即可。这个特点让 SVM 在边缘侧或质检工控机上部署非常有吸引力。5. 提高缺陷漏检召回的两个监督信号校准阈值与折中代价5.1 利用概率输出调阈值缺陷的代价函数并不对称焊接流水线的漏检成本远高于误判成本漏检一个气孔可能让整批工件报废而把合格焊点误判为缺陷最多是返工检查。SVM 的decision_function或predict_proba输出的是相对置信度默认 0.5 分界线只是数学最优不是工程最优。用验证集画出每个类别的 PR 曲线选择召回率达到 95% 以上的位置作为判定阈值这样可以极大减少漏检。from sklearn.metrics import precision_recall_curve proba grid.predict_proba(X_val) # 以 porosity 为例其他缺陷类似 y_true_binary (y_val 1).astype(int) y_score proba[:, 1] precision, recall, thresholds precision_recall_curve(y_true_binary, y_score) for r, p, t in zip(recall, precision, thresholds): if r 0.95: print(fthreshold{t:.4f}, precision{p:.4f}, recall{r:.4f}) break一个常见做法是找出所有「被判定为 normal 但置信度低于某个下限」的样本单独送去人工复审。这比单纯调低所有阈值更精细因为不同缺陷的最优阈值其实不一样不能用一个全局分界线一刀切。5.2 类别代价与误分类矩阵让 SVM 的决策朝着生产目标偏移在训练阶段可通过class_weight{0: 1.0, 1: 2.0}这类字典告诉 SVM 某个缺陷类的一分错误等同两分正常错误。但真正更精细的地方在于误分类矩阵可能是不对称的把crack判成normal的代价 5把slag判成normal的代价 3而porosity误报为crack代价 1。SVM 自带机制没有直接承接这种代价矩阵的能力但你可以用代价敏感的样本重采样对代价高的类别进行 SMOTE 过采样或者叠加一个带代价权重的后处理分类器。我实际处理时是把 SVM 的decision_function输出当作一维特征再在第二层接一个逻辑回归把代价矩阵折算到损失函数里。这么做的好处是 SVM 在高维特征空间里的强判别力被保留而逻辑回归又给了代价权重一个干净的注入点。考虑某一晚期磁盘的工程排错建议时可以用grid.cv_results_查看不同参数组合下各折的召回率比只看平均分数更能暴露特定类别的波动。若某个类别在某一折里召回率骤降回看该折的验证集里此类别样本数是否偏少。这些都是使用 SVM 做焊接缺陷分类的特有排错手段也是代码包拿到的可调杠杆。本文还有配套的精品资源点击获取