4. 数据集准备与标注:工业数据集来源、LabelImg与CVAT标注工具使用、标注格式转换(XML转TXT)
做工业视觉,最头疼的事是什么?
不是模型选型,不是调参,而是——数据。
我在好几个项目里都栽过跟头。有一次,客户给了两万张产线图片,结果打开一看,全是同一批次的产品,光照、角度、背景几乎一模一样。模型训练完,在实验室跑得飞起,一到现场就崩了。说白了,数据质量决定了模型的天花板。
这一章,我就把工业数据集怎么找、怎么标、怎么转格式,掰开了讲清楚。
4.1 工业数据集从哪来?
工业场景的数据集,不像公开数据集那样随手就能下载。我一般从三个渠道入手:
| 来源 | 特点 | 适合场景 |
|---|---|---|
| 公开数据集 | 免费、量大、但场景泛化 | 预训练、算法验证 |
| 产线采集 | 真实、但成本高、需脱敏 | 最终部署、定制化模型 |
| 合成数据 | 可控、可补长尾、但需验证 | 缺陷样本不足、极端场景 |
我的习惯:先用公开数据集做预训练,再用产线数据做微调。合成数据用来补那些“一年也碰不到几次”的缺陷——比如瓶盖歪了0.5度这种。
4.1.1 公开数据集推荐
工业视觉领域,有几个数据集我反复用过:
- MVTec AD:工业异常检测的标杆,15类物体,包含纹理、物体、药品等。我拿它做基线测试,百试不爽。
- NEU-DET:钢材表面缺陷,6类常见缺陷(裂纹、夹杂、斑块等)。做金属检测的同学可以重点关注。
- PCB-DET:印刷电路板缺陷,短路、断路、孔洞等。电子制造行业必备。
注意:公开数据集只能帮你“入门”。工业现场的光照、角度、背景千差万别,最终一定要用自己的产线数据。
4.2 标注工具:LabelImg vs CVAT
标注工具我用了不少,但真正在工业项目里站稳脚跟的,就两个:LabelImg 和 CVAT。
为什么是它们?
- LabelImg:轻量、离线、单机搞定。适合小团队、快速验证。
- CVAT:在线协作、功能强大、支持半自动标注。适合多人团队、大规模标注。
4.2.1 LabelImg:轻量级标注利器
LabelImg 是我个人最常用的工具。它基于 Python + Qt,安装简单,开箱即用。
安装方式:
# 方式一:pip 安装
pip install labelImg
# 方式二:源码运行
git clone https://github.com/tzutalin/labelImg
cd labelImg
python labelImg.py
使用步骤:
- 打开 LabelImg,点击 Open Dir 选择图片文件夹。
- 点击 Change Save Dir 设置标注文件保存路径。
- 按 w 键进入标注模式,框选目标。
- 输入类别名称(如
bottle_defect),确认。 - 按 Ctrl+S 保存,默认生成 XML 文件(Pascal VOC 格式)。
快捷键速记:
w:创建标注框d:下一张图片a:上一张图片Ctrl+S:保存
我在项目里遇到过一个问题:标注到一半,软件突然卡死,没保存的标注全丢了。后来我养成了一个习惯——每标完一张图就按一次 Ctrl+S。别嫌麻烦,血的教训。
4.2.2 CVAT:团队协作标注平台
CVAT 是 Intel 开源的在线标注平台。它最大的优势是多人协作和半自动标注。
部署方式:
# 使用 Docker 一键部署
docker run -p 8080:8080 \
-e CVAT_HOST=your-server-ip \
cvat/server
部署完成后,浏览器打开 http://localhost:8080,注册账号即可使用。
核心功能:
- 任务分配:管理员创建任务,分配给不同标注员。
- 半自动标注:内置深度学习模型(如 YOLO、Mask R-CNN),先自动标注,人工修正。
- 质量控制:可以设置审核流程,标注完成后由专人检查。
我的经验:CVAT 的半自动标注功能,在标注量超过 5000 张时特别有用。先用预训练模型跑一遍,人工只需要修正错误框,效率能提升 3-5 倍。
4.3 标注格式转换:XML 转 TXT
工业场景里,标注格式五花八门。但 YOLO 只认一种——TXT 格式。
LabelImg 默认输出的是 Pascal VOC 格式(XML),而 YOLO 需要的是归一化坐标的 TXT。所以,格式转换是绕不开的一步。
4.3.1 两种格式的差异
| 格式 | 坐标表示 | 文件结构 | 适用框架 |
|---|---|---|---|
| Pascal VOC (XML) | 坐标 (xmin, ymin, xmax, ymax) | 每个图片对应一个 XML 文件 | Faster R-CNN, SSD |
| YOLO (TXT) | 归一化坐标 (class, x_center, y_center, width, height) | 每个图片对应一个 TXT 文件 | YOLOv5, YOLOv8, YOLOX |
归一化坐标的计算公式:
x_center = (xmin + xmax) / 2 / image_width
y_center = (ymin + ymax) / 2 / image_height
width = (xmax - xmin) / image_width
height = (ymax - ymin) / image_height
4.3.2 转换脚本实战
我写了一个 Python 脚本,专门做这个转换。它是我工具箱里最常用的脚本之一。
import xml.etree.ElementTree as ET
import os
def convert_voc_to_yolo(xml_file, output_dir, classes):
"""
将 Pascal VOC XML 转换为 YOLO TXT
:param xml_file: XML 文件路径
:param output_dir: 输出目录
:param classes: 类别列表,如 ['bottle', 'cap', 'label']
"""
tree = ET.parse(xml_file)
root = tree.getroot()
# 获取图片尺寸
size = root.find('size')
img_width = int(size.find('width').text)
img_height = int(size.find('height').text)
# 生成 TXT 文件名
txt_name = os.path.splitext(os.path.basename(xml_file))[0] + '.txt'
txt_path = os.path.join(output_dir, txt_name)
with open(txt_path, 'w') as f:
for obj in root.findall('object'):
class_name = obj.find('name').text
if class_name not in classes:
continue
class_id = classes.index(class_name)
bbox = obj.find('bndbox')
xmin = int(bbox.find('xmin').text)
ymin = int(bbox.find('ymin').text)
xmax = int(bbox.find('xmax').text)
ymax = int(bbox.find('ymax').text)
# 归一化
x_center = (xmin + xmax) / 2.0 / img_width
y_center = (ymin + ymax) / 2.0 / img_height
width = (xmax - xmin) / img_width
height = (ymax - ymin) / img_height
f.write(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n")
# 使用示例
classes = ['bottle', 'cap', 'label']
xml_dir = 'path/to/xml_files'
output_dir = 'path/to/txt_files'
for xml_file in os.listdir(xml_dir):
if xml_file.endswith('.xml'):
convert_voc_to_yolo(os.path.join(xml_dir, xml_file), output_dir, classes)
踩坑提醒:我曾经在转换时忘记检查图片尺寸。结果有一批图片是 1920x1080,但 XML 里写的是 640x480。转换出来的坐标全错了。所以,一定要确保 XML 里的尺寸和实际图片一致。
4.4 本章知识体系
我把这一章的核心逻辑画成了流程图,方便你理解数据准备的完整链路:
从数据来源到标注工具,再到格式转换,每一步都有坑。但只要你按这个流程走,至少能保证数据准备阶段不出大问题。
本章要点回顾:
- 工业数据集来源:公开数据集(MVTec AD、NEU-DET)、产线采集、合成数据
- 标注工具:LabelImg(单机离线) vs CVAT(在线协作)
- 格式转换:Pascal VOC (XML) → YOLO (TXT),注意归一化坐标计算
- 避坑:标注及时保存、检查图片尺寸一致性