基于VOC格式的螺丝螺帽缺陷检测数据集与YOLO训练实践

基于VOC格式的螺丝螺帽缺陷检测数据集与YOLO训练实践 简介本资源是面向工业视觉检测领域的螺丝螺帽缺陷识别专用数据集适用于计算机视觉初学者、自动化质检算法工程师及智能制造方向研究者解决小目标、高相似度金属部件表面缺陷如划痕、变形、缺失、错位等的检测模型训练与验证问题。压缩包共含2000个VOC格式XML标注文件严格遵循PASCAL VOC标准结构涵盖object类别、bndbox坐标、difficult与truncated标识等完整字段全部对应3081张真实场景采集的螺丝螺帽图像图像文件未打包需用户自行配对。资源大小为165.65MB结构精简、标注规范便于直接接入YOLOv5/v8、Faster R-CNN等主流检测框架进行数据加载与训练。目前已有1275人学习下载配套标注可支撑缺陷类型统计分析、mAP基准测试、跨模型性能对比及工业部署前的数据增强策略验证是构建轻量化质检模型的高性价比基础数据支撑。1. 项目概述与背景1.1 为什么螺丝螺帽缺陷检测这么重要螺丝螺帽这类紧固件听着不起眼但几乎每个制造行业都离不开。小到手机、家电大到汽车、工程机械、航空设备全靠它们把零部件牢牢锁在一起。一颗螺丝如果存在裂纹、滑牙、锈蚀或者螺纹损伤装上去短期可能没事时间一长在振动、载荷作用下就可能松动甚至断裂——轻则设备停机重则酿成安全事故。所以质检环节对紧固件的把控一直是生产线上不能省的一环。传统做法是人工肉眼检测老师傅拿放大镜一颗一颗看或者用灯光照、用手摸螺纹。这种方式放到小批量时代还行但现代产线一个小时要过几千上万颗料人工根本盯不过来而且人看久了会疲劳漏检率会明显上升。也正因为如此越来越多的工厂开始上视觉检测设备用工业相机加算法来代替人的眼睛。而要训练一个能稳定识别缺陷的检测算法前提就是要有质量过硬的图片数据。这里所说的“螺丝螺帽缺陷检测识别数据集支持voc格式的标记一共3081张图片”解决的就是这个数据源头问题。3061张图片加上VOC格式的标注文件意味着可以直接喂给常见的深度学习检测框架使用不需要自己做大量的转换工作。1.2 这个数据集适合谁用如果你正在做以下事情这套数据集应该能帮上忙在做工业质检方向的毕业设计比如本科论文里的目标检测实验部分需要一个不同于公开通用数据集的专业场景数据。在工厂或集成商单位做视觉检测方案需要用真实零件图片验证算法选型或者给客户做前期样品测试。在学习YOLO、Faster R-CNN、SSD这类目标检测模型想找一个尺寸适中、标注规范、场景聚焦的数据集来练手。在评估VisionMaster、Halcon等工业视觉软件的缺陷检测模块需要一批样图来做效果测试。从数据集规模来看3081张图不算特别大但也不算小。它恰好处于一个比较合适的中间档位——比学术公开数据集小比纯Demo级别的几十张图多得多。配合数据增强和迁移学习完全可以用它训练出一个具备实用性的检测模型。2. 数据集整体设计与结构解析2.1 VOC格式到底长什么样说“支持voc格式”很多新手一听就懵不知道这意味着什么。VOC格式最早来自PASCAL VOC挑战赛后来成了目标检测领域一个非常通用的标注标准。它的核心是一套文件夹组织方式加上XML标注文件。一个标准的VOC数据集通常包含以下目录JPEGImages存放所有原始图片命名一般是六位数字编号比如000001.jpg。Annotations存放与每张图片对应的XML标注文件文件名和图片名一一对应。ImageSets/Main存放train.txt、val.txt、test.txt这样的文件记录哪些图片用于训练、哪些用于验证。XML文件里写的是图片文件名、图片尺寸、通道数以及每个目标物体的类别名和边界框坐标。边界框用xmin、ymin、xmax、ymax四个值表示单位是像素。大致结构如下annotation folderJPEGImages/folder filename000001.jpg/filename size width640/width height480/height depth3/depth /size object namescratch/name bndbox xmin120/xmin ymin100/ymin xmax300/xmax ymax240/ymax /bndbox /object /annotation这个格式的优势在于信息完整、可读性好、兼容性强。YOLO系列训练时用的txt格式或者COCO格式的json标注都有现成脚本可以互相转换。所以拿到VOC格式的数据集想换到哪个框架都不费劲。2.2 3081张图片的内容构成标题里没有详细说明图片具体包含哪些缺陷类别但按螺丝螺帽这类零件的常见失效模式结合工业界实际需求可以推断这套数据集大概率覆盖了以下几个方面表面划痕和磕碰电镀或抛光后的表面出现细线状或点状损伤。锈蚀在潮湿环境下存放后产生的氧化斑尤其碳钢材质容易出现。螺纹损伤牙纹塌陷、缺牙、挤压变形。头部裂纹在冷镦成型过程中产生的应力裂纹。混料或尺寸异常不同规格的螺丝混在一起或者长短、直径超差。每一次检测标注里边界框会框出缺陷所在的位置类别名就是对应的缺陷类型。如果你打开标注文件后发现类别不是这些名称也没关系里面写的是什么一目了然按实际类别调整就能用。图片数量为3081张大约是按一个中型产线抽样拍摄的量级。拍摄环境一般包括不同光照条件、不同摆放角度、不同背景这样能提升模型在实际工况下的泛化能力。3. 基于数据集的实操从标注校验到模型训练3.1 拿到数据后先做校验很多同学拿到数据集第一反应是直接开训。但这里我建议先花半小时做一遍数据校验省得后面踩坑。第一步检查文件完整性。用Python脚本扫一遍JPEGImages和Annotations两个文件夹看看有没有图片缺少对应的XML或者XML缺少对应的图片。文件数量对不上训练时就会报错或者漏样本。import os img_dir JPEGImages ann_dir Annotations imgs set(f.split(.)[0] for f in os.listdir(img_dir)) anns set(f.split(.)[0] for f in os.listdir(ann_dir)) print(仅图片有标注缺失:, len(imgs - anns)) print(仅标注无图片:, len(anns - imgs))第二步抽查标注质量。用OpenCV把标注框画到图片上肉眼过一遍看看框的位置是否贴合缺陷区域、类别是否合理。这一步不能省因为网上分享的数据集偶尔会混入少量错标、漏标的样本而这些问题会直接影响模型精度。import cv2 import xml.etree.ElementTree as ET def draw_annotation(img_path, xml_path): img cv2.imread(img_path) tree ET.parse(xml_path) root tree.getroot() for obj in root.findall(object): name obj.find(name).text box obj.find(bndbox) xmin int(float(box.find(xmin).text)) ymin int(float(box.find(ymin).text)) xmax int(float(box.find(xmax).text)) ymax int(float(box.find(ymax).text)) cv2.rectangle(img, (xmin, ymin), (xmax, ymax), (0, 255, 0), 2) cv2.putText(img, name, (xmin, ymin-5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) return img # 只演示画一张图 img_with_boxes draw_annotation(JPEGImages/000001.jpg, Annotations/000001.xml) cv2.imwrite(check_000001.jpg, img_with_boxes)3.2 数据集的划分策略模型训练前要把数据分成训练集、验证集和测试集。一般按8:1:1或者7:2:1的比例划分。但这里有个容易被忽略的点划分时要按整个图片来分不要把同一张图片里的不同缺陷切出来分到两个集合里。划分方法有两种。一种是在VOC格式层面直接生成ImageSets/Main里的txt文件好处是后续转换到任何框架都能用。另一种是直接对图片做随机抽样分别放进train、val、test目录。我习惯的做法是写一个简单的脚本随机打乱后按比例生成train.txt、val.txt、test.txtimport os import random img_dir JPEGImages imgs [f.split(.)[0] for f in os.listdir(img_dir)] random.shuffle(imgs) train_ratio 0.8 val_ratio 0.1 n len(imgs) train_list imgs[:int(n * train_ratio)] val_list imgs[int(n * train_ratio):int(n * (train_ratio val_ratio))] test_list imgs[int(n * (train_ratio val_ratio)):] def write_list(filepath, data): with open(filepath, w) as f: for item in data: f.write(item \n) os.makedirs(ImageSets/Main, exist_okTrue) write_list(ImageSets/Main/train.txt, train_list) write_list(ImageSets/Main/val.txt, val_list) write_list(ImageSets/Main/test.txt, test_list)值得注意的是如果数据集的缺陷类别之间存在严重不均衡比如某些类别只有几十个样本而其他类别有上千个那建议改用分层抽样确保每个集合里各类别比例接近整体。3.3 转成YOLO格式并训练现在业界用得最多的检测框架大概率是YOLO系列尤其是Ultralytics的YOLOv8。虽然YOLOv8原生支持读VOC格式吗不原生支持它默认读的是YOLO txt格式。所以需要做一步转换。YOLO txt格式每一行对应一个目标含义是类别id 中心点x坐标 中心点y坐标 宽度 高度。注意这些都是归一化到0~1之间的比例值不是像素值。转换脚本的核心逻辑是读取XML里的xmin、ymin、xmax、ymax计算成中心点坐标和宽高再除以图片宽高做归一化。import xml.etree.ElementTree as ET import os def convert_voc_to_yolo(xml_file, out_dir, class_names): tree ET.parse(xml_file) root tree.getroot() size root.find(size) width int(size.find(width).text) height int(size.find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_names: continue class_id class_names.index(name) box obj.find(bndbox) xmin int(float(box.find(xmin).text)) ymin int(float(box.find(ymin).text)) xmax int(float(box.find(xmax).text)) ymax int(float(box.find(ymax).text)) x_center (xmin xmax) / 2 / width y_center (ymin ymax) / 2 / height w (xmax - xmin) / width h (ymax - ymin) / height lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) base os.path.splitext(os.path.basename(xml_file))[0] with open(os.path.join(out_dir, base .txt), w) as f: f.write(\n.join(lines))转换完成后再写一个data.yaml指定训练集、验证集路径和类别列表就可以直接跑YOLOv8训练了。train: datasets/screw/train/images val: datasets/screw/val/images nc: 5 names: [scratch, rust, thread_damage, crack, dimension_error]训练命令很简单yolo detect train datascrew.yaml modelyolov8n.pt epochs100 imgsz640 batch16如果显卡显存不够把batch调小或者把imgsz从640改成416效果差距不明显但显存占用会小不少。3.4 评估指标怎么看训练完以后模型会输出一组指标最常见的有mAP50、mAP50-95、Precision、Recall。对于缺陷检测场景我一般重点看两个东西mAP50表示IoU阈值在0.5时的平均精度低于0.6基本没法用。Recall表示缺陷被找回的比例。质检场景漏检比误检更危险所以Recall通常比Precision更重要。一个值得注意的问题如果测试集里的缺陷目标本身很小比如螺纹上的一道细裂纹只占几十个像素模型很容易漏检。这种情况下即使整体mAP看着还行也要单独统计小目标的召回率。在YOLOv8中也提供了按尺寸分层的指标训练完直接看small、medium、large三档的mAP能帮你判断模型对大目标和小目标的检测能力差异。4. 常见问题与排查技巧实录4.1 标注框与图片不匹配有朋友拿到数据后发现画出来的框跟实际缺陷对不上差了一些像素。这大概率是XML文件和图片不是同一批生成的或者中间有人编辑过文件又没对齐。排查方法很简单随便挑几张图将XML里的宽度、高度和图片实际宽度、高度做对比看差值是否固定。如果固定说明只是尺寸信息写错了框的坐标本身没问题如果不固定那就可能是图片本身被resize过而标注坐标没跟着变。后一种情况比较麻烦需要重新标注或做坐标反变换。如果只是尺寸信息写错直接批量修改XML里的width和height字段就行。4.2 类别不平衡导致模型只学少数类3081张图摊到多个缺陷类别后某些稀有类别可能只有一两百个实例。模型训练时很容易出现“多数类学到很好少数类几乎不检测”的问题。应对策略有三个针对稀有类别做离线数据增强比如旋转、翻转、仿射变化、亮度对比度调整生成更多样本来平衡数量。修改损失函数中的类别权重让少数类的错分带来更大的惩罚。YOLOv8没有直接暴露这个参数但可以通过自定义loss或选择其他框架实现比如用mmdetection。降低置信度阈值做推理。实际部署时对稀有类别单独设一个更低的conf阈值能明显提升召回。实操中我处理过一个小样本场景原始数据里某类缺陷只有80个实例做了3倍增强后达到了240个同时把推理阈值从默认的0.25降到0.15最终Recall从40%提到了72%。虽然误报也增加了但在质检场景里多出来的误报可以通过后续人工复检兜住漏检才是真正不能接受的。4.3 模型训练后loss有波动这是新手非常容易慌的问题。训练曲线里loss在下降过程中有上下波动但整体趋势向下这属于正常现象。特别是batch size比较小的时候每个batch的样本差异大loss自然会抖动。但如果loss一路降到底后又突然上升那就要小心过拟合了。最直接的解决方法是加早停YOLOv8里带patience参数默认是100轮。可以把它设小一点比如30或者50一旦验证集loss连续N轮不降就自动停省时间也防止过拟合。另一种常见情况是loss在训练初期就不下降甚至越来越大。先检查数据标注里有没有框坐标错位或者类别id对不上。这类问题在转换格式时最容易出现尤其注意YOLO格式里归一化坐标值不能超过1如果出现大于1的值说明转换脚本有bug。4.4 小目标缺陷的检测优化这是螺丝螺帽检测里最头疼的问题。缺陷发生的位置往往很小在整张图里占比不到1%普通的输入尺寸可能让这些小目标在特征图层中直接消失。几个可行的优化方向提高输入分辨率比如YOLOv8的imgsz从640改成1280。代价是显存占用变大训练时间变长。使用带P2层的模型结构比如YOLOv8n-P2或者用RTMDet这种本身就在小目标上有优势的架构。把图像切块检测。训练时不做整图检测而是把高分辨率图切成576×576甚至448×448的patch分别检测再拼接结果。这个方法在工业场景中很常见因为产线相机拍出来的大图分辨率动辄500万、1000万像素直接缩放会严重损失小目标的细节。我自己做个一个项目500万像素的图里要检测直径不到0.5mm的微小划痕一开始用整图缩放训练mAP50只有0.31。后来改成滑窗切块每个patch 640像素、重叠率20%mAP50直接提到了0.78差距非常明显。5. 数据集扩展思路与工程落地建议5.1 如何把训练好的模型用于实际产线训练完模型只是第一步真正要落地到产线上还有好几件事要做。首先是相机选型和打光方案光照对缺陷检测的影响非常大。同一个螺丝在不同角度、不同亮度的光下面拍出来的效果完全不同。工业界常用的方案是低角度环形光加同轴光组合环形光突出表面纹理同轴光用来消除阴影和反光。其次是部署环境。很多工厂用的是Windows工控机加Halcon里的深度学习模块或者VisionMaster里的推理工具。如果你的模型是用YOLOv8训练的导出成ONNX格式后可以在OpenCV DNN模块或者ONNX Runtime上跑推理不依赖Python环境部署灵活度会高很多。yolo export modelbest.pt formatonnx imgsz640导出后用ONNX Runtime加载推理速度在一般工控机CPU上也能做到单张30毫秒左右完全满足产线节拍。如果还不够快可以转成TensorRT在NVIDIA显卡上跑推理时间能压到5毫秒以内。5.2 用公开数据集打底再用私有数据微调很多人在纠结一个问题手里的缺陷数据不够模型训练效果不好怎么办一个比较成熟的做法是先用类似场景的公开数据集做预训练然后把预训练权重在自己的私有数据上微调。比如先用公开的钢材表面缺陷数据集或者螺丝产品相关的缺陷数据预训练一遍目的是让模型学到“金属表面缺陷”的长相。之后再用这套3081张的螺丝螺帽数据集微调。由于预训练阶段已经学到了大量纹理、缺陷形态的特征微调阶段只需要较少数据就能达到不错的效果。这也是我建议把3081张图作为“底料”而不是“全部”的原因。单靠它训练可能mAP在0.65左右但配上预训练权重后同样的训练轮次mAP能提到0.8以上提升非常显著。5.3 数据标注的扩展技巧如果一个项目的检测效果到了瓶颈很多问题其实不在模型而在数据质量和数量。标注时候的一个建议尽量保持边界框紧贴缺陷边缘不要留太多空白边。边界框过大会导致模型学到的特征里包含太多背景内容影响定位精度。还有一个技巧是引入难例挖掘。训练完第一轮模型后把模型在训练集上预测错误的图片——尤其是漏检和误检的——挑出来重新检查标注是否准确必要时补充标注。把这些难例合成到训练集里再训一轮效果往往立竿见影。这套流程在工业缺陷检测项目里几乎必做因为产线上的缺陷形态千奇百怪标注人员经常漏掉一些不典型的样本。而模型恰好能帮你“反向标注”把注意力引到有问题的图片上。6. 我的实操体会与建议用了不少类似的工业缺陷检测数据集这套螺丝螺帽数据算是比较实用的。3081张图片VOC格式边界框标注完整省去了大量数据清洗和格式转换的功夫。最让我满意的还是它的问题聚焦程度——所有样本都围绕螺丝、螺帽这类紧固件展开不像有些公开数据集把各种不相干的工业零件混在一起训练出来的模型也不知道到底该学什么。不过还是想提醒一句网上分享的数据集就算标注做得再好也不能直接拿去做生产级部署。我在实际项目中就遇到过一次数据集的图大多在实验室环境拍的背景干净、光照均匀但到了客户工厂背景变成了传送带光照变成了车间顶部的混合光源模型精度直接掉了20多个百分点。所以数据集只能作为起点真正的落地必须结合现场数据持续迭代优化。做法上建议拿到数据后先在验证集上跑一遍YOLOv8或者Faster R-CNN的基准实验用mAP和Recall两个指标卡住模型效果。然后再根据推理速度和精度要求去调模型结构、输入尺寸和训练策略。工业场景里没有万能的模型只有不断打磨出来的方案。这个数据集的3081张图片足够帮你把这条流程完整跑通。本文还有配套的精品资源点击获取