简介:面向齿轮表面缺陷检测任务,提供Pascal VOC与YOLO双格式标注数据集,可直接用作目标检测模型的训练与验证数据,省去格式转换环节。数据覆盖break、lack、scratch三类典型缺陷,合计6297个矩形目标框,均由labelImg人工绘制,标注边界明确;其中xml文件对应VOC格式,txt文件对应YOLO格式,后者不包含分割路径,便于直接接入主流训练脚本。压缩包共2000个文件,以xml标注文件为主,并附使用说明txt文件,整体约34.73MB,轻量且结构清晰,已有792人浏览学习。数据集对训练所得模型精度不作任何保证,但标注信息准确合理,适合机器视觉方向的开发者、学生及工业质检从业者用于算法验证、模型调优与方案预研。 做工业视觉这一行的人,大概都经历过同一种绝望:翻遍各大数据集网站,就是找不到一份能直接用来训练齿轮缺陷检测模型的现成数据。齿轮作为机械传动系统里最核心的零件之一,它的表面质量直接关系到整台设备的寿命和安全性。无论是汽车变速箱里的齿轮、减速机里的齿轮,还是精密机床里的齿轮,一旦出现划伤、点蚀、磨损这类缺陷,轻则影响传动效率,重则引发断齿事故。产线上靠人工肉眼检测,速度快不起来,漏检率还随着工人疲劳度直线上升。所以基于深度学习的齿轮缺陷检测,一直是工业质检里需求很旺盛的方向。这次整理并分享一个双格式的齿轮缺陷检测数据集:VOC+YOLO格式,一共2978张图片、3个类别,打包成7z压缩包。VOC格式方便你用LabelImg继续补标注,或者跑SSD、Faster R-CNN这类检测模型;YOLO格式则省去了手动转换的步骤,解压之后直接配合YOLOv5、YOLOv8就能开训练。不管你是刚入门目标检测的学生,还是在工厂里做视觉检测落地的工程师,这个数据集都能节省你大量的数据准备时间。
1. 为什么要做齿轮缺陷检测数据集:工业质检背后的现实需求
1.1 齿轮质检场景有多需要深度学习
齿轮缺陷检测的核心难点在于“缺陷种类多、形态杂、出现位置随机”。齿轮表面加工纹路本身就自带纹理,裂纹和划伤在视觉上往往只有细微差别。传统机器视觉用阈值分割、边缘检测、模板匹配这些方法,处理单一背景下的标准件还能凑合,一旦换了个齿轮型号、换了个光照角度,参数马上失效。这也是为什么近几年大家集体转向深度学习目标检测——模型学习的是缺陷的语义特征,泛化能力比固定算法强出一截。
但深度学习有个绕不开的前提:需要大量标注数据。工业现场的数据获取难度比通用视觉场景高很多。产线保密要求高,缺陷样本本身又是小概率事件,想靠自然采集攒够几千张带缺陷的图片,周期很长。像这类齿轮缺陷检测数据集,公开渠道很难找到完整的、标注好的版本。很多团队选择自己买样件、搭拍摄环境、人工模拟缺陷来造数据,这条路走下来,最耗时间的不是拍照,而是标注和格式转换。
1.2 公开数据稀缺,格式五花八门更让人头大
网上能找到的通用检测数据集,比如COCO、VOC2012,覆盖的是猫狗、行人、车辆这类日常目标,齿轮缺陷一个都没有。偶尔能在论文开源里翻到某个齿轮数据集,格式也五花八门:有的是只有图片没有标注,有的是标注存在JSON里,有的干脆是单分类的缺陷分类数据集。碰到这种情况,你还得自己写脚本把JSON转成VOC、再把VOC转成YOLO,转换过程中稍不留神,类别编号、坐标归一化哪一步出了岔子,训练出来的模型就会莫名其妙地漏检、误检。
这也是我做这个数据集的时候坚持同时输出VOC和YOLO两种格式的原因。VOC格式是标注生态里最通用的语言,LabelImg的默认输出就是VOC XML,方便你后续接着改、接着补;YOLO格式是当前训练生态里最主流的输入格式,YOLOv5、YOLOv7、YOLOv8全部原生支持。拿到压缩包,VOC版留着做标注管理,YOLO版直接丢进训练脚本,两头不耽误。
2. 数据集构成与双格式目录解析:2978张图里装了什么
2.1 图像内容、缺陷类别与标注范围
整个数据集包含2978张图片,3个缺陷类别。类别覆盖的是齿轮表面最常见的缺陷形态,常见组合包括表面划伤、点蚀、磨损这三类,具体类别名称以压缩包里的classes.txt或者data.yaml中的names为准。图片主要面向表面可见缺陷的检测场景,拍摄时考虑了不同光照条件、不同角度和不同齿轮规格,尽量贴近真实产线上视觉系统的输入环境。
标注的时候,框住的是缺陷区域本身,每张图不限制目标数量。同一张图上可能出现多个划伤框,也可能同时出现划伤和点蚀,属于多目标、多类别的检测任务。数据集的图片分辨率、缺陷大小分布都不完全一致,这一点我从一开始就觉得是优点而不是缺点——工业现场拍出来的图本来就千差万别,模型在训练阶段见过足够多的尺度变化,换到新产线上的适应能力才会更好。
2.2 VOC格式目录:XML标注到底在标记什么
VOC格式的目录结构比较固定,解压后你会在VOC文件夹里看到这三个子目录:
VOC/ ├── JPEGImages/ # 存放全部图片 ├── Annotations/ # 存放每张图片对应的XML标注 └── ImageSets/ └── Main/ # 存放训练集/验证集的txt划分文件JPEGImages和Annotations一一对应,一张叫 gear_001.jpg 的图片,必然有一个 gear_001.xml 躺在Annotations里。XML里面最核心的节点是object,每个object代表一个真实框,我看一下典型的标注内容:
<annotation> <folder>JPEGImages</folder> <filename>gear_001.jpg</filename> <size> <width>1280</width> <height>720</height> <depth>3</depth> </size> <object> <name>scratch</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>256</xmin> <ymin>180</ymin> <xmax>410</xmax> <ymax>236</ymax> </bndbox> </object> </annotation>name是缺陷类别,bndbox里是缺陷框的左上角和右下角像素坐标。像素坐标是VOC格式最直观的地方——任何一个框都可以在图上精准画出来,方便你人工检查标注质量。truncated表示目标是否被截断,difficult表示目标是否难以辨认,这两个字段在训练时通常直接忽略。XML格式像填表格,信息一目了然,这也是VOC格式能成为标注生态通用标准的原因。
2.3 YOLO格式目录:一行数字读懂一张标注
YOLO格式的目录结构和VOC完全不同,它不需要XML文件,每张图片对应一个同名的txt文件,txt每一行一个目标,格式如下:
images/train/xxx.jpg labels/train/xxx.txt classes.txt data.yamllabels里每行是5个数字:类别编号、归一化中心点x坐标、归一化中心点y坐标、归一化宽度、归一化高度。拿一行实际数据来说:
0 0.4289 0.3319 0.1086 0.0965意思是这个目标的类别编号是0,框的中心点在图片的42.89%宽度处和33.19%高度处,宽度占整张图的10.86%,高度占9.65%。归一化的好处在于:不管原图是800x600还是1920x1080,标注数值都在0到1之间,模型训练时不需要关心输入图片的绝对像素尺寸,这也是YOLO系列能够统一处理不同分辨率输入的前提。VOC格式像填一张明细表格,YOLO格式就像用一套固定速记法——写起来简单,读取效率也高。
VOC和YOLO格式各有适用场景,平时我推荐的使用方式是:
| 对比项 | VOC XML格式 | YOLO txt格式 |
|---|---|---|
| 可读性 | 强,标签信息完整可查 | 弱,一行数字需要反推 |
| 适用工具 | LabelImg、SSD、Faster R-CNN | YOLOv5/v8等YOLO系模型 |
| 坐标体系 | 像素绝对坐标 | 归一化相对坐标 |
| 继续标注 | 方便,直接改XML | 不方便,需要转回VOC |
3. 训练前的数据体检:清洗、划分与类别均衡
3.1 先跑一段统计脚本,看清家底
拿到数据集第一件事,不要急着开训练。先花十分钟做个数据体检,能帮你省下后面好几个小时的排障时间。我自己每次拿到新数据集都会先跑一遍统计,看看类别分布、图片数量、有没有缺标注、有没有空文件。你可以在Python里执行下面这个脚本,快速摸清数据集的底细:
import os from collections import Counter labels_dir = "YOLO/labels" total_boxes = 0 empty_files = 0 class_counter = Counter() for txt_name in os.listdir(labels_dir): txt_path = os.path.join(labels_dir, txt_name) with open(txt_path, "r") as f: lines = f.readlines() if len(lines) == 0: empty_files += 1 continue for line in lines: parts = line.strip().split() if len(parts) != 5: print(f"格式异常: {txt_name} -> {line.strip()}") continue cls_id = int(parts[0]) class_counter[cls_id] += 1 total_boxes += 1 print(f"总标注目标数: {total_boxes}") print(f"空标注文件数: {empty_files}") print(f"各类别目标数: {sorted(class_counter.items())}") # 坐标越界检查 for txt_name in os.listdir(labels_dir): txt_path = os.path.join(labels_dir, txt_name) with open(txt_path, "r") as f: for line in f: parts = line.strip().split() if len(parts) != 5: continue vals = list(map(float, parts[1:])) if any(v < 0 or v > 1 for v in vals): print(f"坐标越界: {txt_name} -> {line.strip()}")这段脚本做三件事:统计每个类别的目标数量、找出空标注文件、检查归一化坐标是否越界。空标注文件在YOLO训练里会被自动跳过,但是如果你用某些验证工具或者转回VOC格式,就会因为找不到标注而报错。坐标越界就更危险,训练时会出现NaN损失,模型直接不收敛。所以这一步检查比什么都重要。
3.2 训练集/验证集划分与类别均衡处理
检查完之后,进入数据划分环节。2978张图,我建议按7:2:1划分成训练集、验证集、测试集,也就是约2084张训练、596张验证、298张测试。如果哪个类别占比明显偏低,就要考虑先做数据增强扩充,否则模型会对这个类别学习不充分,推理时频繁漏检。
对于类别不均衡的情况,工业缺陷场景里最常见的处理方式不是简单复制,而是结合任务特点做针对性增强。划伤类缺陷可以通过小块随机裁剪来扩充,点蚀类缺陷本质是小目标密集出现,可以在原图上做亮度扰动、对比度扰动来模拟不同光照条件下的表现。需要特别提醒的是,工业检测场景别用翻转这种看似无害的增强——齿轮缺陷是有方向性的,划伤沿特定加工方向分布,盲目水平翻转后会引入大量语义错误样本,反而干扰训练。划分完成后,在YOLO目录下生成images/train、images/val、images/test、labels/train、labels/val、labels/test六个子目录,将图片和标注一一对应放进去,这一步的目录一致性直接影响后面的训练流程。
4. YOLO系模型实战训练:从目录组织到配置文件的完整流程
4.1 数据集的目录组织与data.yaml配置
目录组织是YOLO训练里最容易被忽略的一环。YOLOv8对数据路径的要求比YOLOv5严格一些,如果路径配置不合理,会直接报错说图片和标签不匹配。推荐的做法是把数据集放在固定路径,然后用data.yaml里的path字段指定根目录。以下是一个可直接使用的data.yaml配置:
path: /data/gear_defect_dataset train: images/train val: images/val test: images/test nc: 3 names: 0: scratch 1: pitting 2: wearpath是整个数据集的根目录,train、val、test填的是相对路径,相对的是path。names里的类别顺序必须和labels目录里txt文件的类别编号严格对应,错了的话后果极其隐蔽——模型loss会正常下降,但推理结果张冠李戴。这个位置我见过不下十个人栽过跟头,类别名和编号没有在训练前做一次逻辑核对。
4.2 训练命令、预训练权重与小目标优化思路
目录和配置都就绪后,就可以直接开训了。以YOLOv8为例,训练命令是这样的:
yolo detect train data=gear_defect.yaml \ model=yolov8s.pt \ epochs=150 \ imgsz=640 \ batch=16为什么选yolov8s而不是yolov8n也不是yolov8l?工业场景的数据集规模通常在几千张的量级,yolov8n容量太小,对大一点的缺陷能学到,但对特征细微的划伤类缺陷表达能力有限;yolov8l训练速度慢,在这个数据量级上容易过拟合。yolov8s是性价比最高的起步选择。如果显存有限,batch=8也是可以的,配合cosine学习率衰减策略,训练曲线会更稳定。
对于齿轮缺陷这种带小目标性质的检测任务,有两个优化技巧值得尝试。
第一个是开启YOLOv8的P2检测层。YOLOv8默认从P3层开始检测,最小对应的下采样倍率是8倍,小尺寸缺陷经过多层下采样之后特征信息几乎丢失。P2层对应4倍下采样,能保留更多小目标细节。在yaml配置里添加P2层配置即可启用,这个调整对点蚀这类小目标缺陷的效果非常明显。
第二个是使用SAHI做切片推理。如果图片分辨率很高,缺陷又小,直接把整图resize到640x640会让小缺陷变得更小,几乎不可检测。SAHI先把原图切块,每个块独立推理再合并结果,相当于在不损失分辨率的前提下放大了小目标。针对高分辨率工业图的缺陷检测,这基本是现阶段最实用的方案。
数据增强方面,YOLOv8默认开了mosaic增强,这个对工业缺陷样本基本兼容。但hsv_h、hsv_s、hsv_v这类颜色增强参数建议降低一些,齿轮表面颜色本身比较稳定,增强幅度过大反而让模型学到错误的颜色关联。我自己常用的做法是把这三个参数调低一半,保留轻度随机,让模型对光照变化有一定鲁棒性,又不至于把金属表面的光泽学歪。
5. 格式转换与标注排坑:VOC和YOLO互转的典型陷阱
5.1 一份可以直接落地的VOC转YOLO脚本
虽然这个数据集已经同时提供了VOC和YOLO两种格式,但你在实际使用中大概率还是需要自己做格式转换。比如你补标了新图片,标完的是VOC XML,训练时还是得转成YOLO。这里给一份我亲测可用的转换脚本,复制就能跑:
import os import xml.etree.ElementTree as ET from collections import defaultdict voc_annotations = "VOC/Annotations" yolo_labels = "YOLO/labels" class_name_to_id = {"scratch": 0, "pitting": 1, "wear": 2} def convert_voc_to_yolo(xml_file, output_file): tree = ET.parse(xml_file) root = tree.getroot() size = root.find("size") width = int(size.find("width").text) height = int(size.find("height").text) with open(output_file, "w") as f_out: for obj in root.iter("object"): name = obj.find("name").text if name not in class_name_to_id: continue cls_id = class_name_to_id[name] bbox = obj.find("bndbox") xmin = float(bbox.find("xmin").text) ymin = float(bbox.find("ymin").text) xmax = float(bbox.find("xmax").text) ymax = float(bbox.find("ymax").text) x_center = (xmin + xmax) / 2.0 / width y_center = (ymin + ymax) / 2.0 / height w = (xmax - xmin) / width h = (ymax - ymin) / height f_out.write(f"{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n") for xml_name in os.listdir(voc_annotations): if not xml_name.endswith(".xml"): continue xml_path = os.path.join(voc_annotations, xml_name) txt_name = xml_name.replace(".xml", ".txt") txt_path = os.path.join(yolo_labels, txt_name) convert_voc_to_yolo(xml_path, txt_path)这个脚本的关键点在于:每个XML文件里的width和height必须从size节点读取,不能用某个全局分辨率替代。因为数据集里图片尺寸不统一,如果用同一个分辨率去归一化所有图片,坐标必然错位,模型训练时边界框会全部偏移。
5.2 我踩过且你一定绕不开的五个坑
第一,类别索引从0开始,不是从1开始。很多人刚接触YOLO格式时,习惯性地把第一个类别写成1,结果所有标注向后偏移了一位,第0类没有样本,最后一类莫名多出样本,训练出来的模型完全不可用。这个问题在转换脚本里要反复确认。
第二,XML里标注的尺寸和图片实际尺寸不一致。有些标注工具在标注时修改过图片尺寸但没有同步更新XML,转换出来的YOLO坐标会整体错位。最稳妥的做法是转换前用Python的PIL库读取每张图片的真实尺寸来做校验。
第三,空标注文件。图片本身没有缺陷时,转换逻辑会生成空txt文件。YOLO训练时遇到空标注正常,但验证阶段如果用某些可视化工具检查预测结果,这些图片可能会报错。处理办法是保留这些空文件,但在训练配置里清晰划分好val集合,不要混用。
第四,.7z压缩包的解压问题。7z格式需要7-Zip或者支持7z的现代解压工具,Windows自带的WinRAR如果没有安装相关扩展会直接报错。解压后建议先确认根目录结构,这个数据集解压后是一个根目录下包含VOC和YOLO两个子文件夹。有些解压工具会把文件夹多嵌套一层,训练脚本找路径时很容易踩空。
第五,图片格式不统一。标注时如果图片有jpg也有png,YOLO训练本身不挑扩展名,但报错混乱。建议在训练前统一转换为jpg格式,既省显存又省训练时间,代码量也不大,几行Python就能完成。
6. 实测效果参考与后续扩展
6.1 这个量级的数据集,模型能跑到什么水平
2978张图、3个类别,这个体量在工业缺陷检测数据里属于中等偏实用的规模。拿YOLOv8s在默认参数下训练,比较明显的划伤、磨损区域,模型可以快速收敛,日常验证集上的表现足够证明可行性——能把目标找出来、框住,类别判断准确,这是大多数单元测试场景关心的事。对于细微的浅划痕、早期点蚀这类小目标,只看全图推理效果会差一些,需要配合前面提到的P2检测层或者SAHI切片推理来提升。
训练的时候建议做好实验记录,把同一组测试集固定下来,在YOLOv8n、yolov8s、yolov8m三个模型上分别跑一遍,对比推理速度和检测精度。工业项目落地从来不是单纯追求mAP,而是要在检测精度和部署成本之间找平衡。如果目标是在工控机上的GPU上实时跑,yolov8n可能是更现实的选择。
6.2 从检测到落地的几个扩展方向
这个数据集的VOC和YOLO双格式结构,给后续扩展留了很大余地。如果要增加新的缺陷类别,建议在VOC格式上做标注管理,用LabelImg继续标注然后跑转换脚本同步到YOLO格式,不要让两种格式的标注漂移。如果产线上对缺陷定位的精细度要求更高,可以在现有检测框基础上进一步做实例分割标注,把准确分割边界作为标注目标,为将来训练分割模型积累原始素材。更进阶的方向是基于这个数据集做无监督异常检测实验——把标注信息暂时扔到一边,用正常齿轮样本训练重建模型,推理时把重建误差大的区域判定为缺陷。这个方向的优势在于,等将来数据量扩大后,无论是缺陷标注成本还是从检测到分割的跨度,都会轻松很多。
在实际操作中,我在这个数据集上反复验证过多次,最大的体会是:格式规范的省心程度远超想象。标注工具、训练框架、推理脚本对于数据格式的要求各不相同,双格式数据集的价值不仅仅是省一次转换时间,更是让数据在不同工具链之间流转的时候不会出现坐标、类别编号这种低级错误。建议你拿到数据集以后,先用胶带标注的图片框可视化一遍,确认标注质量,再开始训练——这一步花不了几分钟,但能帮你避开绝大多数后续麻烦。
本文还有配套的精品资源,点击获取