ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

VOC垃圾分类数据集详解:15000张真实场景图与YOLO训练实战

VOC垃圾分类数据集详解:15000张真实场景图与YOLO训练实战 简介VOC垃圾分类检测数据集面向需要训练目标检测模型的开发者、研究人员及学生提供约一万五千张真实场景高质量标注图片覆盖纸张、塑料、果皮、玻璃杯、易拉罐、厨余垃圾等常见类别场景丰富、角度多样。全部图片以jpg格式保存采用LabelImg工具完成人工标注标签同时提供VOC格式xml文件与YOLO格式txt文件两套分别存放于独立文件夹用户可根据训练框架灵活选用无需额外转换即可直接用于YOLO系列模型训练。资源包共包含58921个文件其中jpg图片19640张、xml标注文件19640个、txt标注文件19641个整体约994.56MB压缩包结构清晰。目前已有1334人浏览学习适合用于垃圾分类检测相关的课程设计、毕设项目或实际工程落地既能帮助快速搭建训练数据集也能作为模型调参与效果验证的参考。1. 把VOC垃圾分类检测数据集讲清楚15000张真实场景图双格式标签直接喂给YOLO做垃圾分类检测时最头疼的不是YOLO调参而是数据。白底模拟图训出来的模型一进真实垃圾桶场景就翻车。这份VOC垃圾分类检测数据集全部来自真实拍摄共15000张jpglabelImg逐张标注VOC和YOLO两套标签分开存放解压后就能直接开工。覆盖纸张、塑料、果皮、玻璃杯、易拉罐、厨余垃圾这些常见类别场景包括路边、食堂、家庭垃圾袋等光线遮挡接近实际。适合做垃圾分类检测demo或毕设的人也适合想用YOLO验证真实场景效果的一线工程师。作者在CSDN放了检测效果示例文章编号124230743https://blog.csdn.net/zhiqingAI/article/details/124230743可以先看结果再决定下载。下面按我处理数据的完整流程走拆结构、做校验、跑YOLOv8、讲踩坑。2. 数据集结构拆解labelImg标注产物里VOC和YOLO格式差在哪里2.1 两个标签文件夹的目录组织与文件命名下载包解压后图片集中在一个文件夹里标签按VOC和YOLO两种格式分别装在两个文件夹中。图片文件名有两种风格P90818-212351.jpg这种是相机按拍摄时间自动命名的IMG20190818110344.jpg这种来自手机拍摄。文件名本身无所谓关键是每张图片都能找到同名的标签文件——VOC侧是.xmlYOLO侧是.txt。我拿到任何标注数据集第一件事是数文件。图片15000张标签也要能对应上15000份。数文件时注意labelImg标注会生成classes.txt记录标注时用到的全部类别名这份数据集的YOLO标签文件夹里通常带着它。训练前先打开看一眼确认里面是paper/plastic/peel/glass/can/kitchen_waste这类英文名顺序就是class id顺序直接决定后面data.yaml里names怎么写。提示如果发现classes.txt里类别数量和顺序与预期不一致以classes.txt为准后续所有配置跟着它改。2.2 VOC的XML和YOLO的TXT同一目标两种坐标表达同一张图在VOC和YOLO两个文件夹里看到的是同一个标注框的两种表达。VOC格式的XML长这样annotation filenameP90818-212351.jpg/filename size width1280/width height720/height depth3/depth /size object namepaper/name bndbox xmin142/xmin ymin85/ymin xmax634/xmax ymax512/ymax /bndbox /object /annotation而这个框在YOLO格式的txt里只有一行0 0.303 0.415 0.384 0.593YOLO格式五个数依次是类别id、归一化中心点x、中心点y、框宽、框高。归一化公式是x_center (xmin xmax) / 2 / width y_center (ymin ymax) / 2 / height w (xmax - xmin) / width h (ymax - ymin) / height代入上面xml的数字x_center (142 634) / 2 / 1280 ≈ 0.303和txt完全对得上。理解这套换算不是为了让你手动转格式——这份数据已经转好了——而是为了排查问题。训练时直接使用现成的txt后续要加自己的标注图片或者要在不同工具之间倒腾格式坐标换算绕不开。另外注意xml里的filename字段只是参考YOLO训练时不会用这个字段匹配图片匹配全靠同名。如果某个工具导入后出现文件名对不上别去改xml直接从图片文件夹重新生成同名文件更省事。2.3 类别映射表六类垃圾的class id分配这份数据集按常见场景分了六类我的归类习惯如下表。最终名称以数据集里classes.txt的真实内容为准作者在简介里写过“等常见类别”下载后先核对再训练。class idVOC name含义典型样本0paper纸张传单、纸箱、A4纸、报纸、餐巾纸1plastic塑料塑料袋、塑料瓶、泡沫盒、包装膜2peel果皮香蕉皮、橘子皮、苹果皮、果核3glass玻璃杯玻璃瓶、玻璃杯、碎玻璃4can易拉罐铝罐、铁罐、罐头盒5kitchen_waste厨余垃圾剩饭剩菜、骨头、菜叶类别顺序直接决定txt里的数字和data.yaml里的names列表。如果你把names写成[glass, can, ...]而txt里0是paper模型会把所有paper当glass框的位置还对类别全错mAP看着也不低。这种错最难发现所以拿到数据的第一件事是随机抽查三个txt人工核对class id和类别名的对应关系。VOC格式里同样有name字段。用可视化工具标注确认不方便时直接对照xml看这张图里有没有易混淆类别比如“果皮”和“厨余垃圾”——这两类的界限在后续训练中会成为最大的坑第5章和第6章都会反复提到。3. 训练前的数据准备目录整理、标签校验、类别分布统计3.1 把下载的文件夹整理成YOLO标准目录结构YOLO系列默认读的数据结构是images/train、images/val、labels/train、labels/val。下载包往往是扁平目录或自定义结构直接用会报dataset not found。第一步就是把图片和YOLO标签按比例切分我通常用下面这段脚本import os, shutil, random root D:/garbage # 数据集根目录改成你的实际路径 img_src images # 图片目录名 lab_src labels_yolo # YOLO标签目录名 for sub in [images/train, images/val, labels/train, labels/val]: os.makedirs(os.path.join(root, sub), exist_okTrue) names [f for f in os.listdir(os.path.join(root, img_src)) if f.lower().endswith(.jpg)] random.seed(42) random.shuffle(names) val_n int(len(names) * 0.2) for i, name in enumerate(names): split val if i val_n else train stem os.path.splitext(name)[0] shutil.copy2(os.path.join(root, img_src, name), os.path.join(root, fimages/{split}, name)) # 同名txt存在才复制避免训练时标签对不上 src_lab os.path.join(root, lab_src, stem .txt) if os.path.exists(src_lab): shutil.copy2(src_lab, os.path.join(root, flabels/{split}, stem .txt)) else: print(缺标签:, name)脚本逻辑先建好四个目录再按8:2比例随机切分图片和标签。random.seed(42)固定了随机顺序保证每次运行结果一致方便复现。用copy2而不是move是因为原始VOC备份还要留着排查问题后面第6章挑失败样本时经常要回去看原始标注边界。train/val按8:2切对垃圾检测这种目标多、类别不平衡的场景够用如果你后续要做知识蒸馏或者更细致的调参可以改成9:1。VOC的xml不用进训练目录但建议整个文件夹原样保留。3.2 用脚本一次性校验图片与标签是否对得上切分完不要急着开训。真实拍摄的图片经过压缩、改名、拷贝常见问题有图片本身就是坏的、txt文件名对不上、坐标越界、类别id超范围。这些问题在训练时表现为随机报错或性能莫名变差。我每次处理数据集都固定跑一遍校验脚本from PIL import Image import os root D:/garbage bad_img, bad_label, out_of_bounds [], [], [] seen_ids set() for split in [train, val]: img_dir os.path.join(root, fimages/{split}) lab_dir os.path.join(root, flabels/{split}) for name in sorted(os.listdir(img_dir)): stem os.path.splitext(name)[0] lab_path os.path.join(lab_dir, stem .txt) if not os.path.exists(lab_path): bad_label.append(name) continue try: with Image.open(os.path.join(img_dir, name)) as im: w, h im.size # 获取真实宽高用于越界判断 except Exception: bad_img.append(name) continue for line in open(lab_path, encodingutf-8): parts line.strip().split() if len(parts) ! 5: bad_label.append(name) continue cls, xc, yc, bw, bh map(float, parts) seen_ids.add(int(cls)) # 允许1%浮点误差超过说明框出界 if xc 0 or yc 0 or bw 0 or bh 0: out_of_bounds.append((name, line)) if xc bw / 2 1.01 or yc bh / 2 1.01: out_of_bounds.append((name, line)) print(图片损坏:, len(bad_img)) print(标签缺失/格式错:, len(bad_label)) print(坐标越界:, len(out_of_bounds)) print(出现的类别id:, sorted(seen_ids))越界阈值用1.01而不是1.0是因为YOLO归一化时可能出现单个像素级的浮点误差1.01能容忍边界误差又能抓住明显出界。出现越界的文件直接删掉或人工修正这类框训练时会被当成背景负样本影响不可控。seen_ids如果出现比类别总数大的id说明txt和data.yaml对不上这是最容易埋雷的地方。3.3 先统计类别分布再决定要不要做样本均衡六类垃圾在真实场景中的分布并不均匀。纸张、塑料这类常见垃圾占了大头玻璃杯、易拉罐相对少。不均衡不一定会让模型崩但会让小类别recall偏低。先统计再决定策略from collections import Counter counter Counter() for split in [train, val]: lab_dir os.path.join(root, flabels/{split}) for name in os.listdir(lab_dir): for line in open(os.path.join(lab_dir, name), encodingutf-8): cls int(line.strip().split()[0]) counter[cls] 1 for cls, cnt in sorted(counter.items()): print(fclass {cls}: {cnt} boxes) total sum(counter.values()) for cls, cnt in counter.items(): print(fclass {cls} 占比: {cnt / total * 100:.1f}%)统计的是框数量不是图片数量因为一张图里可能多个同类目标。如果发现某一类占比低于5%不要盲目加大epochs期望它自愈先判断这一类的短板是漏检还是误检。漏检多优先做增量标注补充这类样本误检多多半是标注边界问题——注意看框里包了多少背景这类问题不是数量能解决的。4. 用YOLOv8跑垃圾分类检测data.yaml、训练参数与导出测试4.1 一份能直接用的data.yamlYOLOv8的数据配置核心是一个yaml文件。针对这份数据集我的写法是path: D:/garbage # 数据集绝对路径 train: images/train val: images/val names: 0: paper 1: plastic 2: peel 3: glass 4: can 5: kitchen_wastepath建议用绝对路径不要用相对路径因为训练命令的执行目录可能和你以为的不一样。train和val是相对于path的路径前面不要带斜杠。names顺序必须与3.2脚本里seen_ids的取值一致0必须是paper。如果某个类别在标签里一次都没出现过可以保留在names里YOLO不会报错但混淆矩阵里它会一直是零——这其实是有用信息说明数据里该类缺失需要重点关注。4.2 训练参数怎么设imgsz、batch、epochs、workers配置好yaml后用ultralytics命令行直接开训yolo detect train dataD:/garbage/data.yaml modelyolov8s.pt epochs100 imgsz640 batch16 device0 workers4我用的参数与理由如下参数建议值说明modelyolov8s.pt15000张的中型数据集s足够显存大或追求精度换yolov8mimgsz640垃圾目标大小跨度大640是速度和精度平衡点小目标多就提到768batch168G显存能跑6G显存就降到8epochs100这个数据量100轮足够50轮时看val loss就能判断要不要停workers2~4Windows下建议2超过8容易在启动时卡死数据加载epochs不需要硬凑100如果50轮后val曲线已经平坦可以提前停。真实场景数据噪声大训太狠反而过拟合到当天的光线条件。device0是GPU没CUDA就删掉device参数会自动用CPU但100轮会慢很多。workers在Windows上如果报DataLoader error直接改成2。还有一个很多人忽略的点ultralytics第一次训练会扫描并缓存图片路径数据集大或磁盘慢时第一次启动会卡很久。看到进度条没动别急观察磁盘IO。如果实在不耐烦训练命令可以加cacheTrue首次构建后后续读取快很多。4.3 训练完导出与快速测试训练结束后在runs/detect/train/weights/下出现best.pt和last.pt。best.pt是val mAP最高的权重部署优先用它last.pt是最后一轮的权重继续训练时用它。拿best.pt做推理测试yolo predict modelD:/garbage/runs/detect/train/weights/best.pt sourceD:/garbage/test_images/ saveTrue conf0.25这个命令把test_images里的每张图检测一遍画出框和置信度。conf0.25是我做垃圾分类时的常用下限垃圾场景里漏检比误检更影响体验没检出等于完全没分类如果现场误检率高再往上调到0.35或0.4这是个业务权衡问题。如果要部署到边缘设备导出onnxyolo export modelD:/garbage/runs/detect/train/weights/best.pt formatonnx imgsz640导出后可以用onnxruntime在CPU上跑也可以继续转TensorRT加速。imgsz必须和训练时一致否则导出模型在边缘设备上的输入尺寸和训练时的分辨率习惯不匹配精度会明显损耗。5. 避坑VOC垃圾分类检测数据集训练与推理的五个翻车点训练这套数据集时我踩的坑不算少整理五个最典型的基本覆盖从读数据到上线的全程。5.1 现象训练一开始就报 unable to load image原因真实拍摄数据集经过多次拷贝部分jpg文件头损坏或者实际上是网络传输残留的半截文件。Windows下路径含中文同样会触发读取失败。文件名里IMG2019开头的照片尤其容易出问题因为它们可能来自手机直传exif信息完整但压缩格式特殊。解决先跑3.2的校验脚本把损坏图片筛掉数据集和训练工程都放到纯英文路径比如D:/garbage不要放在“桌面/下载”这类中文目录下。5.2 现象验证集mAP很高但拿到现场一测就稀烂原因这类真实拍摄数据集拍摄时间和光线条件相对固定训练集和验证集同源mAP天然乐观。而现场环境——垃圾桶内壁反光、夜间灯光、俯视角度——和数据集分布差异巨大。解决不要迷信mAP。训练完马上拿手机去实际场景拍20张图做盲测。如果盲测翻车把现场图补标注后做增量训练而不是急着调anchor或换模型。第3章强调的校验流程就是为了给这一步留出足够干净的底子。5.3 现象同一张图的VOC和YOLO标签对不上原因大概率是图片被压缩过但xml里的width/height还是原始值。比如原图1280x720被压成640x360YOLO标签如果按原尺寸归一化已经不对VOC的bndbox像素坐标则全偏了。解决训练直接用YOLO文件夹里的txt。数据已经转好不自己二次转换就不存在偏差如果非要从VOC重新转一遍跑3.2的越界检查出界的框全部人工核对。5.4 现象果皮和厨余垃圾互相误检原因这两类视觉特征高度重合香蕉皮既可以叫peel也可以叫kitchen_waste。标注时人为分类不一致模型学到的边界就混乱。这在垃圾分类任务里几乎是必然遇到的坑。解决训练前自己定标注口径水果果皮、果核一律peel剩饭剩菜、骨头、菜叶一律kitchen_waste。然后挑选20张两类的样本人工复核一遍有争议的单独放一个文件后续增量训练当难例用。5.5 现象脚本读VOC的xml时name字段乱码原因labelImg在Windows下默认utf-8保存但有的转换脚本用open(path)默认编码读取GBK和utf-8在中文类名上直接就乱了。解决读xml时强制指定encodingutf-8。更省事的做法是只依赖YOLO格式的txttxt里类别是英文和数字不存在编码问题。如果你在Windows下用PyCharm调试把项目默认编码也统一成utf-8省得后面一堆烂事。6. 最后一个技巧用混淆矩阵和失败样本定位误检根因6.1 用val命令生成混淆矩阵训练完不要看几张测试图就收工。先跑验证yolo val modelD:/garbage/runs/detect/train/weights/best.pt dataD:/garbage/data.yaml splitval跑完在runs/detect/val/下会生成confusion_matrix.png和一系列指标图。看混淆矩阵里对角线之外最高的格子那里就是误检最严重的两类。比如peel和kitchen_waste互踩就是第5.4节说的标注口径问题。6.2 挑低置信度样本看标注边界混淆矩阵告诉你哪两类在混但没告诉你为什么。我的做法是把推理时置信度在0.25到0.45之间的样本导出来人工看一遍。看的时候重点不是模型准不准而是标注框本身是不是把背景包进去了、是不是有半遮挡、是不是一个框框了两个类。这些信息训练日志里看不到只有肉眼能发现。6.3 固定一套“先校验再训练再复盘”的流程到这里就能回答最开始的问题了为什么这个数据集能直接用。它本身是VOCYOLO双格式、六类覆盖相对完整下载后按第3章整理校验按第4章训练按第5章避坑再按6.1和6.2做过一次误检复盘基本能稳定进入迭代循环。说实话我也翻过车。早期拿到数据集上来就跑训练mAP漂亮就以为自己搞定了结果现场被垃圾桶照片打回原形。从那以后我每次拿到数据集都强制先跑一遍3.2的校验脚本训练完必看混淆矩阵再挑失败样本过一遍标注边界。这套流程听着慢实际比盲目重训省太多时间。希望帮到你。本文还有配套的精品资源点击获取
返回列表