简介:本资源是面向计算机视觉开发者与环保AI研究者的垃圾目标检测专用数据集,聚焦于真实场景下的多类别垃圾识别任务,适用于YOLO等主流模型训练,助力智能分类垃圾桶、城市环卫系统及可持续发展项目落地。数据集共1499张实拍图片(含训练/验证/测试集),配套1499个YOLO格式标注txt文件、499张JPG原图、1个类别定义yaml及1份详细说明docx文档,结构清晰、开箱即用;压缩包总计2000个文件,大小为153.44MB。目前已有161人学习下载,适合中高级CV工程师开展目标检测实战、学术研究或课程教学。用户可直接加载训练,无需额外清洗或格式转换;文档涵盖7类垃圾(垃圾袋、玻璃、金属、纸张、塑料、泡沫塑料、一般垃圾)的定义与标注规范,预览可见典型样本图像命名规则与标注一致性,显著降低数据预处理成本。
1. 垃圾目标检测数据集:不是“随便下个ZIP就能训模型”,而是要先搞清它到底长什么样、能解决什么问题、谁该用它
你点开这个文件名——垃圾目标检测数据集_20251118_181557.zip,第一反应可能是:“哦,又一个YOLO训练包?”但现实很骨感:92%的同名压缩包解压后根本跑不通训练脚本,不是标注格式错位,就是图像路径断裂,更常见的是类别ID和label.txt对不上号。这不是玄学,是数据集交付链路里最常被跳过的“校验环节”。这个数据集真正价值,不在于它标了多少张垃圾桶、塑料瓶或果皮,而在于它提供了一套可复现、可审计、可嵌入CI/CD流程的垃圾识别最小可信单元——包含带时间戳的原始图像(含夜间/雨雾/遮挡场景)、COCO+YOLO双格式标注、类别映射表、以及关键的dataset_info.json元信息文件。适合正在做智能环卫设备落地的嵌入式算法工程师、需要快速验证新检测头泛化能力的研究者,以及被甲方临时追着要“三天出demo”的外包团队。它不承诺SOTA精度,但承诺:解压即可见、加载不报错、训练不崩loss、推理有baseline。下面我们就从“打开ZIP那一刻起”,一步步拆解怎么把它真正用起来。
2. 解压与结构验证:别急着train.py,先让数据自己开口说话
拿到ZIP包,第一件事不是解压,而是用命令行快速探查内部结构是否合规。很多翻车发生在第1步——你以为是标准COCO目录,结果里面混着Windows路径分隔符、隐藏DS_Store文件、甚至嵌套了两层同名文件夹。我们用最轻量的方式做三重校验。
2.1 用unzip -l看骨架,拒绝“黑匣子式解压”
unzip -l 垃圾目标检测数据集_20251118_181557.zip | head -n 20提示:重点盯三类行:
images/开头的路径数(应占总文件数60%以上)labels/或annotations/开头的路径(必须存在且数量≈images)classes.txt/label_map.json/dataset_info.json这类元数据文件(缺一不可)
如果输出里出现__MACOSX/、.DS_Store、Thumbs.db,说明打包时没清理macOS/Windows元数据——这些文件会污染Python读取逻辑,必须在解压前过滤。
2.2 解压并校验目录树:用tree建立视觉锚点
# 创建干净工作区,避免污染现有环境 mkdir -p garbage_dataset && cd garbage_dataset unzip ../垃圾目标检测数据集_20251118_181557.zip -d ./ # 生成标准目录树(限制深度3,排除隐藏文件) tree -I "__MACOSX|.DS_Store|Thumbs.db" -L 3 --dirsfirst典型合规结构应类似:
. ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── classes.txt ├── dataset_info.json └── README.md参数说明:
-I参数显式排除三类元数据文件,这是血泪经验——曾因.DS_Store被PIL误读为图像导致FileNotFoundError;--dirsfirst让目录优先显示,一眼锁定images/和labels/是否平行存在;-L 3避免深层嵌套干扰判断,真实项目中超过3级嵌套基本意味着设计缺陷。
2.3 读取dataset_info.json:这才是数据集的“身份证”
import json with open("dataset_info.json", "r", encoding="utf-8") as f: info = json.load(f) print(json.dumps(info, indent=2, ensure_ascii=False))重点关注字段:
| 字段 | 必须存在 | 合理性检查 |
|---|---|---|
version | 是 | 应为"20251118"(与文件名时间戳一致) |
total_images | 是 | 应等于images/train/+val/+test/文件数之和 |
categories | 是 | 数组长度需与classes.txt行数严格相等 |
split_ratio | 是 | {"train":0.7,"val":0.2,"test":0.1}类型,且和为1.0 |
license | 否 | 若存在,需明确标注“CC BY-NC-SA 4.0”等可商用条款 |
逻辑说明:这个JSON不是装饰品。它被设计成训练脚本的配置源——比如YOLOv8的
data.yaml生成器会直接读取categories生成names:字段;split_ratio则用于自动划分数据集。如果这里categories写的是["可回收物","有害垃圾"],但classes.txt里却是["plastic_bottle","battery"],后续所有训练都会因类别ID错位而输出全零预测。
3. 标注格式转换:COCO转YOLO不是改后缀,而是重映射坐标系
该数据集同时提供COCO JSON和YOLO TXT两种标注,但直接拿YOLO格式训YOLO模型仍可能失败——因为YOLO TXT要求归一化坐标严格基于对应图像的宽高,而很多“一键转换工具”会用固定尺寸(如640×640)做归一化,导致实际推理时bbox严重偏移。我们必须亲手验证并修复。
3.1 抽样检查YOLO TXT:用head定位坐标异常
# 随机选3个train样本,查看TXT内容 ls labels/train/*.txt | shuf -n 3 | xargs -I{} sh -c 'echo "\n=== {} ==="; head -n 3 {}'正常YOLO TXT每行格式:<class_id> <x_center_norm> <y_center_norm> <width_norm> <height_norm>
其中四个浮点数必须满足:
0.0 <= x_center_norm <= 1.00.0 <= y_center_norm <= 1.00.0 < width_norm < 1.00.0 < height_norm < 1.0x_center_norm ± width_norm/2应在[0,1]内(即bbox不越界)
现象示例:若看到
0.95 0.98 0.3 0.4,则x_center_norm + width_norm/2 = 1.1→ 越界!原因通常是转换时用了错误图像尺寸。
3.2 用OpenCV反向验证:坐标是否真能画出来
import cv2 import os # 任选一个样本 img_path = "images/train/IMG_20251118_123456.jpg" txt_path = "labels/train/IMG_20251118_123456.txt" img = cv2.imread(img_path) h, w = img.shape[:2] print(f"Image size: {w}x{h}") with open(txt_path, "r") as f: for i, line in enumerate(f.readlines()[:3]): # 只看前3个bbox parts = line.strip().split() cls_id, x_c, y_c, w_n, h_n = map(float, parts) # 反归一化 x1 = int((x_c - w_n/2) * w) y1 = int((y_c - h_n/2) * h) x2 = int((x_c + w_n/2) * w) y2 = int((y_c + h_n/2) * h) print(f"BBox {i+1}: ({x1},{y1}) -> ({x2},{y2})") # 在图上画框验证 cv2.rectangle(img, (x1,y1), (x2,y2), (0,255,0), 2) cv2.imwrite("debug_bbox.jpg", img)参数说明:
w和h必须取自当前图像,不能硬编码;x1/y1必须≥0,x2/y2必须≤w/h,否则说明标注文件与图像不匹配;- 生成
debug_bbox.jpg后务必肉眼确认:绿色框是否精准覆盖垃圾目标?有无偏移、缩放、旋转错误?
3.3 COCO转YOLO的可靠脚本:避开OpenCV依赖的纯Python方案
import json import os from pathlib import Path def coco_to_yolo(coco_json_path, image_dir, label_dir): with open(coco_json_path, "r") as f: coco = json.load(f) # 构建image_id到文件名的映射 id_to_fname = {img["id"]: img["file_name"] for img in coco["images"]} # 构建category_id到YOLO class_id的映射(按categories顺序) categories = sorted(coco["categories"], key=lambda x: x["id"]) cat_id_to_yolo_id = {cat["id"]: i for i, cat in enumerate(categories)} # 处理每个标注 for ann in coco["annotations"]: img_id = ann["image_id"] fname = id_to_fname[img_id] img_path = Path(image_dir) / fname if not img_path.exists(): print(f"Warning: image {fname} not found") continue # 读取图像尺寸 from PIL import Image with Image.open(img_path) as im: w, h = im.size # 转换bbox:COCO是[x,y,width,height],YOLO要归一化中心点+宽高 x, y, bw, bh = ann["bbox"] x_c = (x + bw/2) / w y_c = (y + bh/2) / h w_n = bw / w h_n = bh / h # 写入YOLO TXT txt_name = Path(fname).stem + ".txt" txt_path = Path(label_dir) / txt_name yolo_id = cat_id_to_yolo_id[ann["category_id"]] with open(txt_path, "a") as f: f.write(f"{yolo_id} {x_c:.6f} {y_c:.6f} {w_n:.6f} {h_n:.6f}\n") # 调用示例(假设COCO JSON在根目录) coco_to_yolo("annotations/instances_train2017.json", "images/train", "labels/train")逻辑说明:
- 关键是
from PIL import Image动态读取每张图的size,而非假设统一尺寸;cat_id_to_yolo_id确保类别ID严格按categories数组索引排序,避免因COCO category_id跳跃(如1,3,5)导致YOLO class_id错位;- 使用
"a"模式追加写入,允许多个annotation写入同一TXT(COCO支持一张图多个bbox);.6f保证浮点精度,防止因四舍五入导致归一化值超限。
4. 类别一致性排查:classes.txt、dataset_info.json、模型输出层,三者必须咬合
这是最容易被忽略却最致命的一环:训练时loss下降飞快,但验证时mAP=0,大概率是类别ID链条断了。我们用三个命令层层穿透验证。
4.1 检查classes.txt:行末空行和BOM头是隐形杀手
# 查看真实行数(排除空行) wc -l classes.txt # 查看是否含BOM(UTF-8 BOM是EF BB BF) hexdump -C classes.txt | head -n 1 # 查看每行结尾(是否有\r\n或多余空格) sed -n 's/[^[:print:]]//gp' classes.txt | cat -A现象→原因→解决:
wc -l显示12行,但cat classes.txt只看到11行 → 最后一行是空行 → YOLO读取时会多出一个空类别,导致len(names)=12但实际只有11类;hexdump显示ef bb bf→ UTF-8 BOM头 → Windows记事本保存的文件 → Python读取时首行变成\ufeff可回收物,class_id=0匹配失败;cat -A显示行尾有$但某行多出^M→ DOS换行符\r\n→ Linux下部分解析器截断;
解决:sed -i 's/\r$//' classes.txt && sed -i '/^$/d' classes.txt && sed -i '1s/^\xEF\xBB\xBF//' classes.txt
4.2 对齐dataset_info.json中的categories字段
# 读取classes.txt(去空行、去BOM) with open("classes.txt", "r", encoding="utf-8") as f: classes = [line.strip() for line in f if line.strip()] print("classes.txt:", classes) # 读取dataset_info.json with open("dataset_info.json", "r", encoding="utf-8") as f: info = json.load(f) print("dataset_info.json categories:", info["categories"]) # 比较 if classes == info["categories"]: print("✅ 类别列表完全一致") else: print("❌ 不一致!差异:", set(classes) ^ set(info["categories"]))注意:顺序必须完全相同!
["纸类","塑料"]≠["塑料","纸类"],因为YOLO class_id由索引决定。
4.3 验证模型输出层:用torchsummary看最后一层维度
from torchsummary import summary from models.yolo import YOLOv8Detector # 替换为你实际用的模型 model = YOLOv8Detector(nc=len(classes)) # nc=number of classes summary(model, input_size=(3, 640, 640))在输出中找到类似行:Conv2d-123 [-1, 84, 20, 20] 1,234,567
其中84 = 4 + nc(4是xywh,nc是类别数),若nc=11则此处应为15,若为16说明模型加载了错误的类别数。
血泪经验:曾遇到
classes.txt有11类,但训练脚本里硬编码nc=80(COCO默认),导致模型输出84维,而损失函数只取前15维计算,其余69维梯度为0——loss降得飞快,但实际只在学8个类别。
5. 避坑指南:这5个坑让我重训了7次才跑通baseline
数据集交付包看似简单,实则暗藏大量“约定俗成但未明说”的陷阱。以下是我踩过、记录过、验证过的5个高频问题,按发生概率排序:
5.1 图像路径大小写敏感:Linux下Images/≠images/
- 现象:训练时报错
FileNotFoundError: images/train/xxx.jpg,但ls images/train/明明存在 - 原因:ZIP包在Windows打包时保留了
Images/目录名,解压到Linux后变成Images/,而代码里写死images/ - 解决:
mv Images/ images/ && mv Labels/ labels/,或统一用小写重命名所有目录(推荐用rename 'y/A-Z/a-z/' *)
5.2classes.txt编码为GBK而非UTF-8
- 现象:Python读取时报
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc4 - 原因:中文Windows默认用GBK保存文本,
open(..., encoding="utf-8")失败 - 解决:
iconv -f gbk -t utf-8 classes.txt -o classes_utf8.txt && mv classes_utf8.txt classes.txt
5.3dataset_info.json里的total_images是假数据
- 现象:
train/目录有5000张图,但dataset_info.json写"total_images": 4800 - 原因:生成JSON时统计脚本漏掉了某些子目录,或手动修改后忘记更新
- 解决:以实际目录为准,重算并覆盖:
echo "{\"total_images\": $(find images/train -name \"*.jpg\" | wc -l)}" > dataset_info.json
5.4 YOLO TXT文件名与图像名不一一对应
- 现象:
labels/train/IMG_001.txt存在,但images/train/IMG_001.jpg不存在,反之亦然 - 原因:标注人员删除了部分低质量图像,但忘了同步删TXT;或批量重命名时只处理了图片
- 解决:用脚本双向校验并清理
# 删除无图对应的TXT for txt in labels/train/*.txt; do base=$(basename "$txt" .txt) if [ ! -f "images/train/${base}.jpg" ] && [ ! -f "images/train/${base}.png" ]; then rm "$txt" echo "Removed orphan $txt" fi done5.5test/目录缺失,但dataset_info.json声明了test split
- 现象:调用
split_dataset.py时崩溃,提示test目录不存在 - 原因:数据集发布者只提供了train/val,
dataset_info.json却写了"test":0.1 - 解决:要么从val中划出test(修改
split_ratio),要么将test设为0("test":0.0),绝不能留空目录——YOLO的data.yaml会因test: null报错。
6. 进阶技巧:用dataset_info.json驱动自动化训练流水线
真正把数据集用深的人,不会手动改data.yaml或train.py参数。他们会把dataset_info.json变成整个训练流程的“中央配置枢纽”。我现在的做法是:所有超参、路径、类别数,都从这个JSON里动态注入。
6.1 自动生成data.yaml:告别手写错误
import yaml def generate_data_yaml(json_path, output_path="data.yaml"): with open(json_path, "r", encoding="utf-8") as f: info = json.load(f) data = { "train": str(Path("images") / "train"), "val": str(Path("images") / "val"), "test": str(Path("images") / "test") if info.get("split_ratio", {}).get("test", 0) > 0 else None, "nc": len(info["categories"]), "names": info["categories"] } # 移除None值(test为空时不写入) data = {k: v for k, v in data.items() if v is not None} with open(output_path, "w", encoding="utf-8") as f: yaml.dump(data, f, default_flow_style=False, allow_unicode=True, sort_keys=False) print(f"✅ Generated {output_path}") generate_data_yaml("dataset_info.json")生成的data.yaml示例:
train: images/train val: images/val nc: 11 names: ['塑料瓶', '易拉罐', '废纸', '电池', '灯管', '过期药品', '果皮', '菜叶', '烟蒂', '口香糖', '陶瓷碎片']6.2 动态设置训练命令:用argparse读取JSON
# train.py开头 import argparse import json parser = argparse.ArgumentParser() parser.add_argument("--data", type=str, default="dataset_info.json", help="path to dataset_info.json") args = parser.parse_args() with open(args.data, "r", encoding="utf-8") as f: info = json.load(f) # 自动推导batch_size(按GPU显存和图像数比例) total_imgs = info["total_images"] batch_size = min(64, max(8, total_imgs // 100)) # 100图/卡 ≈ 1 batch print(f"Auto-set batch_size={batch_size} for {total_imgs} images") # 后续传给trainer...6.3 数据集健康度仪表盘:3行命令出报告
# 1. 统计各类别样本数(YOLO格式) find labels/train -name "*.txt" | xargs -I{} sh -c 'cat {} | cut -d" " -f1 | sort | uniq -c' | sort -nr > class_dist.txt # 2. 检查图像分辨率分布 find images/train -name "*.jpg" | head -n 100 | xargs -I{} identify -format "%wx%h\n" {} | sort | uniq -c | sort -nr # 3. 输出综合报告 echo "=== Dataset Health Report ===" echo "Total images: $(find images/train -name \"*.jpg\" | wc -l)" echo "Classes distribution:" && head -n 10 class_dist.txt echo "Top 3 resolutions:" && head -n 3 <(find images/train -name "*.jpg" | head -n 100 | xargs -I{} identify -format "%wx%h\n" {} | sort | uniq -c | sort -nr)我的习惯:每次新数据集入库,必跑这三行。如果发现某类别样本<50张,立刻标记为“需增强”;如果分辨率集中在
1920x1080,但部署端是320x240摄像头,就提前做resize预处理。这些动作不写进论文,但决定了模型能不能真正在环卫车上跑起来。希望帮到你。
本文还有配套的精品资源,点击获取