【工业质检实战】铝型材表面缺陷数据集构建与YOLO模型训练全流程解析
1. 铝型材表面缺陷检测的工业挑战
在铝型材生产线上,表面缺陷检测一直是个让人头疼的问题。想象一下,每天要盯着数千米长的铝型材表面,寻找比头发丝还细的裂纹或几乎与纹理融为一体的划痕,这工作不仅费眼睛,还特别容易漏检。我见过不少工厂的质检员,拿着强光手电筒一寸寸检查,一天下来眼睛都花了,效率还不到80%。
铝型材表面常见的十类缺陷——凹陷、不导电、擦花、桔皮、漏底、碰伤、起坑、凸粉、涂层开裂、脏点,每种的形态特征都不同。最麻烦的是,这些缺陷往往和铝材本身的纹理混在一起,就像在迷彩服上找另一块迷彩图案。传统人工检测的漏检率普遍在15-20%,而一个漏网的缺陷可能导致整批产品被退货。
2. 数据集构建实战
2.1 数据采集要点
我们使用的1885张2560×1920高分辨率图像,全部来自真实生产线。这里有个坑要注意:拍摄角度必须保持垂直,任何倾斜都会导致纹理阴影被误判为缺陷。我们专门设计了带LED环形灯的工业相机支架,确保每张图片的光照均匀度差异不超过5%。
数据分布也很关键。比如"不导电"这类缺陷只有58个样本,而"脏点"有638个。直接训练会导致模型对少数类别视而不见。我的做法是用过采样(Oversampling)+CutMix数据增强:把不导电缺陷区域随机粘贴到正常图像上,既增加样本又保持背景多样性。
2.2 XML标注规范
标注文件要包含这些关键信息:
<object> <name>pengshang</name> <!-- 缺陷类型 --> <bndbox> <xmin>1254</xmin> <!-- 左上角X坐标 --> <ymin>872</ymin> <!-- 左上角Y坐标 --> <xmax>1388</xmax> <!-- 右下角X坐标 --> <ymax>945</ymax> <!-- 右下角Y坐标 --> </bndbox> </object>标注时容易犯两个错误:一是框选范围过大,把正常纹理包含进去;二是对模糊缺陷的标注不一致。我们采用三人交叉验证法,只有两人以上确认的标注才会入库。
2.3 数据增强技巧
针对铝型材特性,我推荐这些增强组合:
transform = A.Compose([ A.RandomRotate90(p=0.5), # 90度旋转 A.GaussNoise(var_limit=(10,50),p=0.3), # 高斯噪声 A.RandomGamma(gamma_limit=(80,120),p=0.2), # 伽马变换 A.Cutout(num_holes=8,max_h_size=32,p=0.5) # 随机遮挡 ])特别注意要禁用水平翻转——产线上的铝型材纹理有固定方向,翻转后会引入不存在的模式。
3. YOLOv5模型训练全流程
3.1 环境配置避坑指南
推荐使用这个Docker镜像,已经预装好所有依赖:
docker pull ultralytics/yolov5:latest pip install -r requirements.txt # 额外安装albumentations遇到过最坑的问题是CUDA版本冲突。实测在RTX 3090上,CUDA 11.1+PyTorch 1.8.0组合训练速度最快。如果看到NaN损失值,大概率是环境不匹配。
3.2 数据准备技巧
用这个脚本把XML转YOLO格式:
import xml.etree.ElementTree as ET import os def convert(size, box): dw = 1./size[0] dh = 1./size[1] x = (box[0] + box[2])/2.0 y = (box[1] + box[3])/2.0 w = box[2] - box[0] h = box[3] - box[1] x = x*dw w = w*dw y = y*dh h = h*dh return (x,y,w,h) for xml_file in xml_files: tree = ET.parse(xml_file) root = tree.getroot() size = root.find('size') w = int(size.find('width').text) h = int(size.find('height').text) with open(txt_file, 'w') as f: for obj in root.iter('object'): cls = obj.find('name').text box = obj.find('bndbox') b = (float(box.find('xmin').text), float(box.find('ymin').text), float(box.find('xmax').text), float(box.find('ymax').text)) bb = convert((w,h), b) f.write(f"{class_dict[cls]} {' '.join([str(a) for a in bb])}\n")3.3 模型训练参数调优
在铝型材场景下,这些参数效果最好:
# yolov5s.yaml anchors: - [4,5, 8,10, 13,16] # 小目标层 - [23,29, 43,55, 73,105] # 中目标层 - [146,217, 231,300, 335,433] # 大目标层 # 训练命令 python train.py --img 640 --batch 32 --epochs 100 --data aluminum.yaml --weights yolov5s.pt --hyp hyp.scratch-low.yaml --rect --multi-scale关键调整点:
- 修改anchors适应铝材缺陷尺寸
- 启用矩形训练(--rect)节省显存
- 多尺度训练(--multi-scale)提升小缺陷检测
3.4 模型评估与优化
测试时发现三个典型问题:
- 误检:把纹理误认为缺陷
- 漏检:小尺寸缺陷检测不到
- 分类错误:擦花和划痕混淆
解决方案:
# 增加小目标检测层 model.model[-1].anchor_grid = [torch.zeros(1)] * 4 # 原3层改为4层 # 添加注意力机制 class SEBlock(nn.Module): def __init__(self, c): super().__init__() self.avgpool = nn.AdaptiveAvgPool2d(1) self.fc = nn.Sequential( nn.Linear(c, c//16, bias=False), nn.ReLU(inplace=True), nn.Linear(c//16, c, bias=False), nn.Sigmoid() )最终在测试集上达到:
- mAP@0.5: 0.892
- 推理速度:15ms/张(T4 GPU)
- 漏检率:<3%
4. 产线部署实战经验
4.1 模型轻量化技巧
使用TensorRT加速后的模型体积缩小75%:
python export.py --weights best.pt --include engine --device 0 --half --simplify --topk-all 100在Jetson Xavier NX上实测:
- FP32: 45ms
- FP16: 22ms
- INT8: 15ms
4.2 异常处理机制
产线环境复杂,必须添加这些保护:
try: img = cv2.imread(path) if img is None: raise ValueError("图像读取失败") if np.mean(img) < 10: # 检测黑图 raise ValueError("相机信号异常") if img.shape != (1920,2560,3): img = cv2.resize(img,(2560,1920)) except Exception as e: logging.error(f"预处理异常: {str(e)}") trigger_alarm()4.3 持续学习方案
我们设计了一套在线更新机制:
graph LR A[新数据] --> B(自动标注) B --> C{置信度>0.9?} C -->|Yes| D[加入训练集] C -->|No| E[人工复核] D --> F[每周增量训练]实际应用中,这套系统使模型准确率每月提升约2%。
