城市道路垃圾检测VOC数据集构建与YOLOv8模型训练全流程
2026/9/3 18:17:38 网站建设 项目流程

简介:本资源是面向计算机视觉初学者与实战开发者的城市道路垃圾检测专用数据集,适用于YOLO系列模型训练及Pascal VOC格式目标检测任务实践。数据集共1785个文件,包含892张高质量JPG图像、892份对应XML标注文件(均使用labelImg工具规范标注矩形框)及1份类别说明txt,总大小983.57MB;所有样本聚焦真实城市场景,涵盖道路、绿化带等典型区域,其中81张为常见塑料瓶类垃圾,整体标注框数达1155个,类别统一为“trash”,结构简洁、开箱即用。目前已有1089人学习下载,资源无冗余分割文件或YOLO格式转换,便于用户自主完成格式转换与数据增强实验,特别适合开展小样本目标检测 baseline 构建、标注质量评估及模型泛化能力验证等教学与科研任务。

1. 项目概述:一份专为城市道路垃圾检测打造的VOC数据集

最近在做一个城市环境智能巡检相关的项目,核心需求是要能自动识别出路面上的各类垃圾,比如塑料袋、饮料瓶、纸箱、烟头这些。找了一圈公开数据集,要么类别不对口,要么数据量太少,标注质量也参差不齐。所以,干脆自己动手,整理并标注了一份专门针对城市道路场景的垃圾检测数据集。这个数据集总共包含了892张高质量图像,全部采用标准的PASCAL VOC格式进行标注,可以直接拿来训练YOLOv5、YOLOv8等主流的目标检测模型。今天就把这个数据集的构建过程、里面的门道,以及如何用它高效训练YOLO模型的经验,完整地分享出来。

对于刚接触目标检测的朋友来说,VOC格式和YOLO训练可能听起来有点技术门槛,但其实核心逻辑很清晰。VOC格式是一种广泛使用的数据集组织规范,它用XML文件来记录图片中每个目标的位置(边界框)和类别,通用性极强。而YOLO系列算法因其速度快、精度高,成为了工业界和学术界的宠儿。我们这个数据集的价值,就在于它填补了“城市道路垃圾”这个细分领域的空白,数据都来源于真实的街道场景,光照、角度、遮挡情况多样,能很好地锻炼模型的泛化能力。无论你是想快速验证一个垃圾检测的想法,还是需要为一个实际部署的项目准备数据,这份892张的数据集都能提供一个扎实的起点。

2. 数据集核心价值与构建思路拆解

2.1 为什么选择“城市道路垃圾”这个细分场景?

在计算机视觉领域,数据集的质量和针对性往往直接决定了模型的上限。通用目标检测数据集(如COCO)虽然类别丰富,但对于“道路垃圾”这类细粒度、小目标、且外观多变的物体,检测效果往往不尽如人意。塑料袋在风中可能呈现各种形状,半掩的饮料瓶和完整的看起来差异很大,这些都需要特定场景的数据来“教导”模型。

我们构建这个数据集的初衷,就是为了解决这个“针对性”问题。所有892张图像均采集自不同时段(清晨、午后、黄昏)、不同天气(晴天、阴天、雨后)的城市道路,涵盖了人行道、自行车道、机动车道边缘等典型区域。这种设计确保了数据分布的多样性,模拟了真实世界中的复杂情况。数据集中主要包含了四类垃圾:可回收物(如塑料瓶、易拉罐)、其他垃圾(如塑料袋、食品包装)、厨余垃圾(零星水果皮等,较少)以及烟头。这样的类别划分既贴合常见的垃圾分类需求,也考虑了目标检测中类别平衡的问题。

2.2 VOC格式:经久不衰的数据集标准

尽管现在有许多新的数据集格式(如COCO JSON),但PASCAL VOC格式因其结构清晰、工具链成熟,依然是许多项目和工业流程中的首选。它的核心在于每个图像对应一个XML标注文件。这个XML文件里不仅记录了图片的尺寸、通道数等基本信息,更重要的是以<object>节点详细定义了每一个待检测目标。

一个典型的<object>节点包含:

  • <name>:目标的类别名称,如“plastic_bottle”。
  • <bndbox>:边界框坐标,包含<xmin>,<ymin>,<xmax>,<ymax>四个值,表示框的左上角和右下角在图像像素坐标系中的位置。

这种格式的最大优势是“可读性强”和“兼容性广”。你可以用任何文本编辑器查看和修改,并且绝大多数标注工具(如LabelImg)都直接支持生成VOC格式。在模型训练前,我们需要根据不同的训练框架(如YOLO、Faster R-CNN)将VOC格式转换成特定的格式(如YOLO的txt格式),这个转换过程是标准化的,有大量现成脚本可用。

注意:在标注时,边界框的精度至关重要。框体应紧密贴合目标物体,既不能留太多空隙,也不能切掉物体的一部分。对于被部分遮挡的物体,应根据可见部分标注一个合理的边界框。

2.3 从数据采集到标注的完整流水线

构建一个高质量数据集绝非简单的“拍照-打框”,它有一套严谨的流程:

  1. 数据采集与筛选:我们使用高清行车记录仪和手机在多个城市区域进行采集。原始视频被按帧抽取,并手动筛选出包含有效垃圾目标的画面。筛选原则是:目标清晰可辨、场景有代表性、避免重复构图。最终从数千张原始图中精选出892张。
  2. 标注规范制定:在开始标注前,必须制定统一的规范。我们明确了以下几点:
    • 类别定义:对“塑料袋”、“塑料瓶”等给出文字描述和示例图,避免歧义。
    • 遮挡处理:被遮挡超过50%的物体不予标注(或标注为“difficult”)。
    • 小目标处理:对于像素面积小于20x20的垃圾(如远处烟头),根据其重要性决定是否标注,并在后续训练中可能采用专门的小目标检测策略。
    • 边界框:必须包含物体的全部可见部分,边界紧贴物体边缘。
  3. 标注工具与质检:使用LabelImg进行人工标注。标注完成后,进行了两轮质量检查:第一轮由另一名标注员交叉检查错误和遗漏;第二轮则通过脚本进行规范性检查,如检查XML文件格式是否正确、边界框是否超出图像范围等。
  4. 数据集划分:将892张图像按大约7:2:1的比例随机划分为训练集(约625张)、验证集(约178张)和测试集(约89张)。划分时注意了类别分布的均衡性,确保每个子集中都包含所有类别的样本。

3. VOC格式详解与YOLO格式转换实操

3.1 深入解析VOC数据集的目录结构

一个标准的VOC格式数据集,其目录结构是高度规范化的,理解这个结构是进行任何操作的基础。我们的数据集组织如下:

VOC_RoadGarbage/ ├── Annotations/ # 存放所有XML标注文件 │ ├── 000001.xml │ ├── 000002.xml │ └── ... ├── JPEGImages/ # 存放所有原始图像文件 │ ├── 000001.jpg │ ├── 000002.jpg │ └── ... ├── ImageSets/ # 存放数据集划分的文本文件 │ └── Main/ │ ├── train.txt # 每行一个训练集图片名(不含后缀) │ ├── val.txt # 每行一个验证集图片名 │ └── test.txt # 每行一个测试集图片名 └── labels/ # (可选)转换后存放YOLO格式标签的目录
  • AnnotationsJPEGImages:这是核心,必须保证每个XML文件与对应的JPG文件同名(仅后缀不同)。这是后续所有脚本能正确运行的前提。
  • ImageSets/Main:这个目录下的txt文件是数据集的“索引”。例如,train.txt的内容可能就是:
    000001 000003 000005 ...
    它告诉训练程序,应该去JPEGImages里找000001.jpg,去Annotations里找000001.xml。生成这些txt文件通常通过一个简单的Python脚本随机划分并写入即可。

3.2 从VOC到YOLO格式的转换原理与脚本

YOLO模型训练需要的是另一种更简洁的标签格式:每个图像对应一个同名的.txt文件,每行代表一个目标,格式为:

<class_id> <x_center> <y_center> <width> <height>

这里的坐标是归一化后的,即相对于图像宽度和高度的比例值,范围在[0, 1]之间。

转换的核心计算如下:

  1. 从VOC的XML中解析出像素坐标:xmin, ymin, xmax, ymax
  2. 计算边界框的中心点坐标和宽高:
    • x_center = (xmin + xmax) / 2.0
    • y_center = (ymin + ymax) / 2.0
    • width = xmax - xmin
    • height = ymax - ymin
  3. 将上述值除以图像的宽度(img_w)和高度(img_h)进行归一化:
    • x_center /= img_w
    • width /= img_w
    • y_center /= img_h
    • height /= img_h

下面是一个实用的Python转换脚本,它读取AnnotationsImageSets/Main/train.txt,为训练集生成YOLO格式标签:

import xml.etree.ElementTree as ET import os # 类别列表,必须与标注时的名称对应,顺序决定了class_id classes = ['plastic_bottle', 'plastic_bag', 'cigarette_butt', 'paper_box'] def convert_annotation(image_id, list_file): """将单个XML文件转换为YOLO格式,并写入list_file指向的txt""" in_file = open(f'VOC_RoadGarbage/Annotations/{image_id}.xml', encoding='utf-8') tree = ET.parse(in_file) root = tree.getroot() size = root.find('size') w = int(size.find('width').text) h = int(size.find('height').text) lines = [] for obj in root.iter('object'): cls = obj.find('name').text if cls not in classes: continue # 跳过不在定义类别中的目标 cls_id = classes.index(cls) xmlbox = obj.find('bndbox') b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymax').text)) # 计算归一化坐标 x_center = (b[0] + b[2]) / 2.0 / w y_center = (b[1] + b[3]) / 2.0 / h width = (b[2] - b[0]) / w height = (b[3] - b[1]) / h # 格式化为字符串,保留6位小数 lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}") # 将转换后的内容写入对应的labels文件 if lines: label_file = open(f'VOC_RoadGarbage/labels/{image_id}.txt', 'w') label_file.write("\n".join(lines)) label_file.close() # 在数据集列表文件中记录图像路径(YOLO训练需要) list_file.write(f'./VOC_RoadGarbage/JPEGImages/{image_id}.jpg\n') # 为训练集、验证集、测试集分别执行转换和列表生成 sets = [('train'), ('val'), ('test')] for set_name in sets: image_ids = open(f'VOC_RoadGarbage/ImageSets/Main/{set_name}.txt').read().strip().split() list_file = open(f'{set_name}.txt', 'w') # 生成YOLO训练用的路径列表文件 for image_id in image_ids: convert_annotation(image_id, list_file) list_file.close()

运行这个脚本后,你会得到labels/目录下所有的YOLO格式.txt文件,以及train.txt,val.txt,test.txt这三个包含图像绝对或相对路径的列表文件,它们将直接用于YOLO的配置文件。

实操心得:务必在转换后,随机抽查几个生成的.txt标签文件,用简单的脚本或肉眼检查一下归一化后的坐标值是否都在[0,1]区间内。一个常见的错误是图像尺寸读取错误,导致归一化坐标大于1,这会在训练初期直接导致损失爆炸(NaN)。

4. 基于YOLOv8的道路垃圾检测模型训练全流程

4.1 环境配置与项目结构搭建

我们以当前最流行的Ultralytics YOLOv8为例。首先创建一个清晰的项目目录,这是保持代码和数据整洁的好习惯。

# 创建项目目录 mkdir road_garbage_detection && cd road_garbage_detection # 将我们准备好的VOC_RoadGarbage数据集文件夹放到这里 # 安装ultralytics包(建议在虚拟环境中进行) pip install ultralytics

安装完成后,你的项目结构应该大致如下:

road_garbage_detection/ ├── VOC_RoadGarbage/ # 我们的数据集 │ ├── Annotations/ │ ├── JPEGImages/ │ ├── ImageSets/ │ └── labels/ # 转换后的YOLO标签 ├── runs/ # YOLOv8训练后自动生成的,存放权重和日志 ├── data.yaml # 数据集配置文件(核心!) └── train.py # 训练脚本

接下来,创建最重要的data.yaml文件。这个文件告诉YOLOv8去哪里找数据、有哪些类别。

# data.yaml path: ./VOC_RoadGarbage # 数据集根目录 train: train.txt # 训练集列表文件路径(相对于path) val: val.txt # 验证集列表文件路径 test: test.txt # 测试集列表文件路径(可选) # 类别数量 nc: 4 # 类别名称列表,必须与转换脚本中的classes列表顺序完全一致! names: ['plastic_bottle', 'plastic_bag', 'cigarette_butt', 'paper_box']

这里的关键是train.txtval.txt的内容。它们是在上一步转换脚本中生成的,里面是像./VOC_RoadGarbage/JPEGImages/000001.jpg这样的路径。确保这些路径能正确指向你的图片文件。

4.2 模型训练与关键参数解析

YOLOv8提供了极其简洁的API进行训练。创建一个train.py脚本:

from ultralytics import YOLO # 加载一个预训练模型,这里以YOLOv8n(nano版)为例,平衡速度和精度 model = YOLO('yolov8n.pt') # 开始训练 results = model.train( data='./data.yaml', # 数据集配置文件路径 epochs=100, # 训练轮数,对于小数据集可以适当增加 imgsz=640, # 输入图像尺寸,默认640,可根据显存调整 batch=16, # 批次大小,取决于GPU显存(如8GB显存可设8-16) workers=4, # 数据加载线程数 device='0', # 使用GPU 0,如果是CPU则设为'cpu' project='runs/train', # 结果保存目录 name='exp1', # 实验名称 pretrained=True, # 使用预训练权重 optimizer='AdamW', # 优化器,AdamW通常效果不错 lr0=0.01, # 初始学习率 weight_decay=0.0005, # 权重衰减,防止过拟合 # 数据增强配置(对小数据集至关重要) hsv_h=0.015, # 色调增强 hsv_s=0.7, # 饱和度增强 hsv_v=0.4, # 明度增强 degrees=10.0, # 旋转角度 translate=0.1, # 平移 scale=0.5, # 缩放 shear=0.0, # 剪切 flipud=0.0, # 上下翻转概率 fliplr=0.5, # 左右翻转概率(对水平对称场景有效) mosaic=1.0, # Mosaic数据增强概率(YOLO特色,对小目标友好) mixup=0.0, # MixUp增强概率(可尝试0.1-0.2) )

关键参数深度解读:

  • epochs:训练轮数。892张图不算多,100轮是个合理的起点。需要通过观察验证集损失曲线来判断是否过拟合,如果验证损失很早就停止下降甚至上升,就需要早停。
  • imgsz:图像尺寸。更大的尺寸(如1280)能检测到更小的垃圾,但会显著增加显存消耗和训练时间。对于道路垃圾,640是一个在精度和效率间取得平衡的常用值。
  • batch:批次大小。这是影响训练稳定性和显存占用的首要参数。基本原则是在不爆显存的前提下,使用你能承受的最大batch。更大的batch通常意味着更稳定的梯度估计。
  • 数据增强:这是小数据集训练的命门mosaic将四张图拼成一张,极大地增加了背景复杂性和目标上下文信息。fliplr(水平翻转)对道路场景非常有效,因为垃圾在路的左边或右边没有本质区别。hsv增强模拟不同光照条件。适度使用这些增强可以显著提升模型鲁棒性,防止过拟合。

4.3 训练过程监控与模型评估

启动训练后,YOLOv8会在控制台打印进度,并在runs/train/exp1目录下生成大量有用文件:

  • weights/best.pt:验证集上表现最好的模型权重。
  • weights/last.pt:最后一轮的模型权重。
  • results.csv:记录每轮训练/验证的损失、精度指标。
  • confusion_matrix.png:混淆矩阵,查看各类别的分类混淆情况。
  • F1_curve.png,P_curve.png,R_curve.png:F1分数、精确率、召回率随置信度阈值变化的曲线。
  • val_batchX_pred.jpg:随机验证批次的可视化预测结果,这是最直观的调试工具

如何判断模型训练得好不好?

  1. 看损失曲线:打开results.csv或用TensorBoard(YOLOv8支持)查看。训练损失应稳步下降并逐渐平缓。验证损失应在初期下降后,在一个值附近小幅波动。如果验证损失持续显著上升,就是过拟合了。
  2. 看指标:重点关注mAP50-95(即COCO mAP),这是综合衡量检测精度(在不同IoU阈值下)的核心指标。对于我们的垃圾检测任务,mAP50(IoU阈值为0.5时的平均精度)也很有参考价值。一个在验证集上mAP50能达到0.85以上的模型,通常在实际场景中就有不错的表现了。
  3. 看预测图片:定期查看val_batchX_pred.jpg。看模型是否漏检(特别是小目标烟头)、误检(将树叶阴影当成塑料袋)、定位是否准确。这是发现数据集标注问题或模型缺陷的最快方法。

5. 模型优化、部署与常见问题排查

5.1 针对小目标垃圾的优化策略

在实际的街道图像中,烟头、小纸片等垃圾可能只占几十个像素,属于典型的小目标。YOLO模型本身对小目标检测不算特别擅长,但我们可以通过以下策略优化:

  1. 数据层面

    • 提高输入分辨率:将imgsz从640提升到1280。这是最直接有效的方法,但计算成本呈平方增长。
    • 针对性增强:增加mosaic的概率(如设为1.0),并配合copy-paste增强(YOLOv8部分版本支持),即将小目标随机复制粘贴到其他图像上,增加其出现频率和多样性。
    • 重新审视标注:确保所有可辨识的小目标都被标注了,即使它们很小。有时候标注员会无意中忽略这些小物体。
  2. 模型层面

    • 更换模型尺度:如果用的是yolov8n.pt(nano),可以尝试更大的模型,如yolov8s.ptyolov8m.pt。更大的模型拥有更强大的特征提取能力,对小目标更敏感。
    • 修改检测头:YOLOv8的官方代码结构清晰,高级用户可以尝试修改检测头(Head)部分,例如借鉴YOLOv5的Focus结构或添加针对小目标的检测层(更浅的特征图)。但这需要较强的深度学习功底。
    • 调整Anchor(先验框):YOLOv8是Anchor-Free的,但我们可以通过分析数据集中所有目标框的宽高分布,来理解我们目标的尺度。使用K-means聚类算法在训练集标签上聚类,可以得出最适合我们数据集的“典型目标尺寸”,虽然不直接设置Anchor,但这个分析能告诉我们模型需要关注什么尺度的目标。

5.2 模型导出与轻量化部署

训练得到满意的best.pt后,我们通常需要将其导出为更适合部署的格式。

from ultralytics import YOLO model = YOLO('runs/train/exp1/weights/best.pt') # 导出为ONNX格式(通用性强,支持多种推理引擎) success = model.export(format='onnx', imgsz=640, simplify=True) # 导出为TensorRT FP16格式(NVIDIA GPU上极致加速) success = model.export(format='engine', device=0, imgsz=640, half=True)

部署选择:

  • ONNX Runtime:跨平台,支持CPU/GPU,易于集成,是快速验证和跨平台部署的首选。
  • TensorRT:如果你在NVIDIA Jetson(如NX、Orin)或服务器GPU上部署,TensorRT能提供最大的推理速度提升,通常有数倍的加速比。
  • OpenVINO:针对Intel CPU和集成显卡优化。
  • CoreML:用于苹果设备(iOS/macOS)。

对于道路垃圾检测这种可能需要部署到移动端或边缘设备(如巡检机器人、智能摄像头)的场景,模型轻量化至关重要。除了选择YOLOv8n这样的轻量模型,还可以在导出时进行动态量化或训练后量化(PTQ),进一步压缩模型大小、提升推理速度,对精度影响通常很小。

5.3 训练过程中的常见问题与解决方案

即使按照流程操作,训练过程中也可能遇到各种“坑”。这里记录几个我踩过的典型问题:

问题一:Loss(损失)值为NaN或突然变得巨大。

  • 可能原因1:学习率(lr0)过高。这是最常见的原因。过高的学习率会导致优化过程“冲过头”,权重更新幅度太大而失控。
    • 解决:将lr0降低一个数量级,例如从0.01降到0.001,甚至0.0001重新开始训练。
  • 可能原因2:数据标注有误。例如,边界框的坐标超出了图像范围(如xmax > 图像宽度),或者在VOC转YOLO格式时归一化计算错误,导致坐标不在[0,1]区间内。
    • 解决:运行一个数据检查脚本,遍历所有标签文件,确保所有坐标值都是合法的浮点数且在合理范围内。
  • 可能原因3:批次大小(batch)太小,同时使用了Batch Normalization层。
    • 解决:尝试增大batch大小,或者使用YOLOv8内置的batch自适应逻辑,或换用Group Normalization等对小批量更友好的归一化方法(这通常需要修改模型结构)。

问题二:验证集mAP很低,但训练集损失正常下降。

  • 可能原因:严重过拟合。模型只是记住了训练集,而没有学到泛化规律。
    • 解决
      1. 加强数据增强:提高mosaic,mixup,fliplr等增强的概率和强度。
      2. 使用早停(Early Stopping):监控验证集mAP,当其在连续10-20个epoch内不再提升时,停止训练。
      3. 增加正则化:适当提高weight_decay参数(如从0.0005调到0.001),或在模型结构中添加Dropout层(需要修改代码)。
      4. 获取更多数据:892张对于复杂场景可能仍显不足。可以考虑使用生成对抗网络(GAN)生成一些合成数据,或者进行更广泛的数据采集。

问题三:某一类垃圾(如“烟头”)的检测精度(AP)远低于其他类。

  • 可能原因:类别不平衡。数据集中“烟头”的样本数量可能远少于“塑料袋”。
    • 解决
      1. 数据层面:有针对性地补充“烟头”的图片,或使用过采样技术。
      2. 损失函数层面:YOLOv8默认使用带类别权重的损失函数。你可以尝试进一步调整类别权重,给样本少的类别赋予更高的权重。这需要在损失函数代码层面进行修改。
      3. 后处理层面:在推理时,可以针对“烟头”类别单独设置一个更低的置信度阈值,以提高其召回率,但可能会增加误检。

问题四:训练速度非常慢。

  • 可能原因1:workers参数设置不当。数据加载是瓶颈。
    • 解决:将workers设置为CPU核心数的2-4倍。但注意,设置过高可能导致内存不足。可以通过top或任务管理器观察CPU利用率来调整。
  • 可能原因2:图像尺寸imgsz过大。
    • 解决:在精度可接受的范围内,尝试减小imgsz,如从640降到512,速度会有显著提升。
  • 可能原因3:使用了CPU训练。
    • 解决:确保device参数设置为0cuda:0,并且PyTorch正确安装了CUDA版本。

最后,模型训练更像一门实验科学,没有一成不变的“最优参数”。最好的方法是基于一份基线配置(如本文提供的),然后系统地调整一两个关键参数(如lr0imgsz、数据增强强度),观察验证集指标的变化,通过多次迭代实验来找到最适合你具体数据和硬件条件的配方。这份892张的VOC格式道路垃圾数据集,就是你开始这一切实验的绝佳沙盒。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询