4. 工业数据集构建
数据,说白了就是模型的“饭”。没有好数据,再牛的YOLO也白搭。我在工业现场摸爬滚打这些年,见过太多项目死在数据上——要么采集得不对,要么标得稀烂。今天咱们就把这顿饭怎么做透,讲明白。
核心观点:工业视觉的数据集构建,不是简单的“拍照片+画框”。它是一套从产线光照、相机选型、标注规范到格式转换的完整工程流程。任何一个环节偷懒,模型上线后都会加倍还给你。
4.1 数据采集策略:别让模型“看”不懂产线
很多新手上来就问:“我要拍多少张?” 我的回答永远是:“先别管数量,先管质量。” 工业场景下,数据采集的核心是 覆盖真实工况。
我经历过一个项目,客户在实验室拍了1000张完美样本,模型跑起来准确率99%。一上产线,直接掉到60%。为什么?产线上的光照是暖色的,还有震动,产品表面有油污。模型没见过这些,当然懵。
4.1.1 采集策略清单
| 维度 | 策略要点 | 我的踩坑经验 |
|---|---|---|
| 光照 | 覆盖不同时段、不同角度、不同亮度 | 我曾经只拍了正光,结果模型在侧光下完全失效 |
| 角度 | 模拟产线传送带的轻微偏移和旋转 | 建议用振动台模拟产线抖动,哪怕只有±2° |
| 背景 | 包含传送带、夹具、其他产品的干扰 | 纯色背景训练出来的模型,换条传送带就废了 |
| 缺陷 | 确保正负样本比例合理,缺陷类型全覆盖 | 别只拍“标准缺陷”,真实产线上的划痕千奇百怪 |
| 分辨率 | 与部署时的相机分辨率一致 | 用高分辨率拍,训练时降采样,效果比低分辨率拍好很多 |
我的习惯:每次采集前,先写一份《数据采集SOP》,把光照色温、相机高度、拍摄距离、文件命名规则全部定死。产线工人按SOP操作,数据质量才有保障。
4.2 标注工具:LabelImg vs LabelStudio
标注工具选哪个?我个人的建议是:小项目用LabelImg,大项目或团队协作用LabelStudio。别纠结,两个我都会教你怎么用。
4.2.1 LabelImg:轻量级单兵利器
LabelImg是我最早用的工具。它轻、快、不需要装数据库。适合一个人标几百张图的小项目。
- 安装:
pip install labelImg一行命令搞定 - 输出格式: 默认Pascal VOC(XML),也支持YOLO格式(TXT)
- 快捷键: W(画框)、D(下一张)、A(上一张)——标得快全靠它
- 缺点: 不支持多人协作,没有自动保存(我吃过亏,标了一下午没保存……)
# 启动LabelImg
labelImg
# 如果想直接输出YOLO格式,启动时指定
labelImg data/ pre-defined_classes.txt
4.2.2 LabelStudio:企业级协作平台
后来项目大了,团队五六个人同时标注,LabelImg就不够用了。LabelStudio支持Web界面、多人协作、自动保存、版本管理。说白了,它就是标注界的“GitHub”。
- 安装:
pip install label-studio,然后label-studio start - 核心功能: 支持图像、文本、音频多模态标注
- 导出格式: COCO JSON、Pascal VOC、YOLO、CSV等
- 我的用法: 先让两个标注员独立标同一批数据,然后我用LabelStudio的“标注一致性检查”功能找出差异,再让专家仲裁。这样能显著提升标注质量。
注意:LabelStudio默认导出的是JSON格式,需要转换成YOLO需要的TXT格式。别慌,后面我会给转换脚本。
4.3 数据集划分:别让验证集“作弊”
数据标完了,接下来就是划分。很多教程说“训练集70%、验证集20%、测试集10%”,但工业场景下,我建议你换个思路。
为什么会这样?因为工业数据往往存在 时序相关性。比如你从产线上连续拍了1000张图,前500张是上午拍的,后500张是下午拍的。如果随机划分,模型可能“记住”了光照变化,而不是真正学会了检测目标。
4.3.1 我的划分策略
| 划分方式 | 适用场景 | 比例建议 |
|---|---|---|
| 随机划分 | 数据独立同分布,无时序依赖 | 70% / 20% / 10% |
| 时序划分 | 产线连续采集,光照/背景缓慢变化 | 前60%训练,中间20%验证,后20%测试 |
| 按批次划分 | 不同批次产品有差异(如不同模具) | 留一个完整批次做测试 |
避坑指南:我曾经犯过一个错——用随机划分训练了一个缺陷检测模型,验证集准确率95%,但上线后一塌糊涂。后来发现,训练集和验证集里混入了同一张图的不同裁剪版本。模型其实在“背答案”。所以,划分前一定要做 去重。
4.4 格式转换:从标注到YOLO能吃的格式
YOLO需要的标注格式很简单:每个图像对应一个TXT文件,每行代表一个目标,格式为 class_id x_center y_center width height,所有坐标都是归一化到[0,1]的。
但标注工具输出的格式五花八门。我整理了一个对照表:
| 标注格式 | 文件类型 | 坐标表示 | 转换难度 |
|---|---|---|---|
| Pascal VOC | XML | xmin, ymin, xmax, ymax(像素) | 低 |
| COCO JSON | JSON | x, y, width, height(像素) | 中 |
| YOLO TXT | TXT | x_center, y_center, width, height(归一化) | 无需转换 |
下面是我常用的转换脚本片段,把Pascal VOC转成YOLO格式:
import xml.etree.ElementTree as ET
import os
def convert_voc_to_yolo(xml_file, output_dir, classes):
tree = ET.parse(xml_file)
root = tree.getroot()
# 获取图像尺寸
width = int(root.find('size/width').text)
height = int(root.find('size/height').text)
# 获取文件名(不含扩展名)
filename = os.path.splitext(root.find('filename').text)[0]
with open(os.path.join(output_dir, filename + '.txt'), 'w') as f:
for obj in root.findall('object'):
class_name = obj.find('name').text
class_id = classes.index(class_name)
# 读取像素坐标
xmin = int(obj.find('bndbox/xmin').text)
ymin = int(obj.find('bndbox/ymin').text)
xmax = int(obj.find('bndbox/xmax').text)
ymax = int(obj.find('bndbox/ymax').text)
# 转换为YOLO格式(归一化)
x_center = (xmin + xmax) / 2.0 / width
y_center = (ymin + ymax) / 2.0 / height
w = (xmax - xmin) / width
h = (ymax - ymin) / height
f.write(f"{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n")
# 使用示例
classes = ['bottle', 'cap', 'label'] # 你的类别列表
convert_voc_to_yolo('annotation.xml', 'labels/', classes)
重要提醒:转换后一定要做 可视化验证。我写了一个小脚本,把YOLO标注画回原图上,肉眼检查框的位置对不对。这一步能发现很多坐标转换错误,比如宽高算反了、归一化除错了。
4.5 知识体系总览
下面这张图,是我对本章知识体系的总结。你可以把它当作一个检查清单,做项目时对照着来。
4.6 最后说几句
数据集构建这件事,听起来不酷,但它是整个项目里最值得花时间的地方。我见过太多团队花两周调模型,却只花两天准备数据——结果就是反复返工。
我的建议是:把数据集的构建流程标准化、工具化。写脚本、做检查、留文档。这样下次做类似项目时,你就能直接复用这套流程,效率翻倍。