☰
基于YOLO的垃圾分类目标检测系统实战:从数据集标注到Gradio部署全流程
2026/10/7 5:57:51 网站建设 项目流程

简介:这是一套面向高校学生与深度学习入门者的垃圾分类目标检测完整项目资料,围绕Python与主流目标检测框架展开,可用于毕业设计、期末大作业或课程设计场景,帮助读者从零搭建可运行的检测系统并完成实验报告。压缩包共126个文件,约66.06MB,包含20个py源码、13个ipynb实验笔记、12个vue前端页面、18张png效果图,以及onnx模型、sqlite3数据库、pptx汇报稿、docx参考报告与pdf说明等,覆盖训练、推理、可视化与文档全流程。目前已有252人学习下载。资源提供带注释的源码与部署指南,新手也能看懂,配套数据集、报告PPT与参考文档可直接复用,目录结构清晰,便于按模块理解数据预处理、模型训练、检测推理与前端展示的实现思路,快速完成项目复现与答辩准备。

1. 从一张宿舍楼下的垃圾桶照片说起:这套垃圾分类检测系统到底在做什么

去年帮学弟看他的大作业,题目就是「基于深度学习的垃圾分类目标检测系统」。他给我看的第一版效果:把一张宿舍楼下垃圾桶的照片丢进去,模型框出了七个目标,其中三个把「可回收物」认成了「其他垃圾」,还有一个把路过的猫当成了「厨余垃圾」。这个翻车现场其实很典型——垃圾分类目标检测的难点从来不在「能不能框出来」,而在「框出来之后类别对不对、小目标漏没漏、遮挡场景崩不崩」。

这套系统的核心任务,是让模型在一张图片或一段视频流里,同时完成两件事:定位垃圾的位置(画框),判断它属于哪一类(可回收物、厨余垃圾、有害垃圾、其他垃圾,具体类别数以你数据集为准)。它适合三类人:正在做大作业或课程设计的学生、想跑通一个完整目标检测落地流程的初学者、以及需要快速搭一个垃圾分类 demo 做验证的工程师。整条链路包括数据集准备、YOLO 系列模型训练、推理部署、报告整理,我会按我实际做过的顺序拆开讲,参数怎么设、哪里容易翻车,都写清楚。

2. 数据集怎么攒:从原始图片到 YOLO 格式标注的完整链路

2.1 垃圾分类数据集的两个来源与取舍

做这个题目,数据集是第一个卡点。常见做法有两类:一是直接用公开的垃圾分类数据集,二是自己爬取或拍摄后标注。公开数据集的好处是省时间,坏处是类别定义和你报告里写的可能对不上,比如有的数据集把「纸箱」和「报纸」分成两类,有的合并成「可回收物」一类。我一般会先明确报告里要写几个大类,再去找类别能对齐的数据集,对不齐的就自己补标。

自己标注的话,工具用 LabelImg 或 X-AnyLabeling 都行,导出 YOLO 格式的 txt。这里有个血泪经验:标注时一定要统一「框到什么程度」。比如一个塑料袋里装了瓶子,你是框整个袋子还是只框瓶子?如果标注标准不统一,模型学出来的边界会非常玄学,验证集 mAP 忽高忽低。

数据量方面,每个类别至少 300 到 500 张有效标注图,类别少的可以少一点,但不要低于 200。总图片数在 2000 到 5000 张之间,对大作业来说足够跑出一个能看的曲线。如果实在凑不够,用旋转、裁剪、亮度调整做增强,但增强后的图不要直接混进验证集,否则指标虚高。

2.2 把 VOC 格式转成 YOLO 格式的脚本与四个边界坑

很多公开数据集是 VOC 格式(XML 标注),YOLO 训练需要 txt 格式,转换脚本如下:

import xml.etree.ElementTree as ET import os # 类别映射,顺序必须和训练时的 data.yaml 一致 classes = ["recyclable", "kitchen", "hazardous", "other"] def convert_annotation(xml_path, out_txt_path, img_w, img_h): tree = ET.parse(xml_path) root = tree.getroot() with open(out_txt_path, "w") as f: for obj in root.iter("object"): cls_name = obj.find("name").text if cls_name not in classes: continue # 跳过未定义类别,避免训练时报索引越界 cls_id = classes.index(cls_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) # YOLO 格式:中心点 x,y 和宽高,全部除以图像尺寸归一化 x_center = (xmin + xmax) / 2.0 / img_w y_center = (ymin + ymax) / 2.0 / img_h w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h # 边界裁剪,防止坐标越界导致训练报错 x_center = min(max(x_center, 0), 1) y_center = min(max(y_center, 0), 1) w = min(max(w, 0), 1) h = min(max(h, 0), 1) f.write(f"{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n")

这段代码的逻辑是:读 XML 里的 object 节点,取类别名和边界框坐标,转成 YOLO 要求的归一化中心点格式。参数上,classes列表的顺序决定了 txt 里第一列的数字,必须和后面data.yaml里的names完全一致,否则模型学出来的类别是错位的。四个边界坑分别是:类别名大小写不一致导致跳过、坐标超出图像范围导致归一化后为负、图像尺寸读取错误导致比例全错、以及空标注文件没生成导致训练时找不到标签。转换完建议随机抽 10 张图用可视化脚本画框检查一遍,别直接开训。

2.3 data.yaml 的写法与路径陷阱

YOLO 训练依赖一个 yaml 文件描述数据路径和类别:

path: /home/user/garbage_dataset # 数据集根目录,建议写绝对路径 train: images/train val: images/val nc: 4 names: ["recyclable", "kitchen", "hazardous", "other"]

path用绝对路径能避开大部分「找不到图片」的报错。train和val是相对path的路径,里面放图片,对应的 labels 文件夹要和 images 同级且同名替换。常见错误是 images 和 labels 目录结构不镜像,比如 images/train 对应 labels/train,但有人放成了 labels/train_images,训练直接报标签缺失。

3. 模型训练:YOLO 环境配置与参数调优的实操记录

3.1 环境配置:Python 版本、CUDA 与 ultralytics 安装

环境这块,Python 用 3.8 到 3.10 比较稳,3.11 以上有些依赖轮子还没跟上。CUDA 版本要和显卡驱动匹配,30 系卡用 CUDA 11.8 或 12.1 都行。安装 ultralytics 的命令:

# 创建虚拟环境,避免污染系统 Python python -m venv yolo_env source yolo_env/bin/activate # Windows 用 yolo_env\Scripts\activate # 安装 PyTorch,以 CUDA 11.8 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 安装 ultralytics pip install ultralytics

装完用yolo checks验证环境,它会打印出 PyTorch 版本、CUDA 是否可用、以及依赖是否齐全。如果 CUDA 显示不可用,先别急着重装,多半是 PyTorch 装成了 CPU 版,卸载后按上面带--index-url的命令重装即可。这一步的坑在于:很多人直接pip install ultralytics,它会把 CPU 版 PyTorch 一起装上,训练时慢到怀疑人生。

3.2 训练命令与关键参数怎么设

训练用命令行或 Python 脚本都行,我习惯用脚本方便记录:

from ultralytics import YOLO # 加载预训练权重,n 表示 nano 版本,速度快适合大作业 model = YOLO("yolov8n.pt") results = model.train( data="data.yaml", epochs=100, # 大作业 100 轮足够,看曲线收敛情况可加到 150 imgsz=640, # 输入尺寸,显卡显存小于 6G 可降到 512 batch=16, # 批大小,显存不够就减半 lr0=0.01, # 初始学习率,默认值,一般不用大改 patience=20, # 20 轮没提升就早停,省时间 device=0, # 用第 0 号 GPU,CPU 训练填 "cpu" project="runs/garbage", name="exp1" )

参数说明:epochs不是越大越好,100 轮后看results.png里的 mAP 曲线,如果已经平了就停。imgsz影响小目标检测效果,垃圾目标通常不大,640 是平衡点,降到 512 可能漏检小瓶子。batch受显存限制,8G 显存跑 640 尺寸大概能到 16,报 OOM 就往下调。patience是早停耐心值,设太小可能还没收敛就停了,设太大浪费时间,20 到 30 比较合适。

训练过程中重点看三个指标:box_loss和cls_loss是否稳定下降、mAP50是否上升、验证集 loss 是否开始反弹。如果训练 loss 降但验证 loss 升,说明过拟合,可以加数据增强或减模型复杂度。

3.3 训练完怎么读结果:mAP、混淆矩阵与失败样本

训练结束后runs/garbage/exp1目录下会生成一堆文件,重点看这几个:results.png是损失和指标曲线,confusion_matrix.png是混淆矩阵,val_batch0_pred.jpg是验证集预测可视化。混淆矩阵能直接告诉你哪两类容易混,比如「厨余垃圾」和「其他垃圾」经常互相误判,这时候要么补这两类的区分性样本,要么在报告里说明类别边界本身模糊。

我一般会额外跑一个脚本,把验证集里置信度低于 0.3 的预测单独拎出来看,这些低置信样本往往就是模型没学明白的场景,比如遮挡、反光、小目标。针对性地补 50 到 100 张类似场景的图再训一轮,mAP 通常能涨 2 到 5 个点。

4. 推理部署:把训练好的模型跑成能演示的界面

4.1 单张图片与视频流的推理代码

训练完的权重在runs/garbage/exp1/weights/best.pt,推理代码:

from ultralytics import YOLO import cv2 model = YOLO("runs/garbage/exp1/weights/best.pt") # 单张图片推理 results = model.predict(source="test.jpg", conf=0.4, save=True) # conf 是置信度阈值,低于它的框不显示,0.4 是常用起点 # 视频流推理 cap = cv2.VideoCapture("test.mp4") while cap.isOpened(): ret, frame = cap.read() if not ret: break results = model.predict(source=frame, conf=0.4, verbose=False) annotated = results[0].plot() # 把框和类别画到帧上 cv2.imshow("Garbage Detection", annotated) if cv2.waitKey(1) & 0xFF == ord("q"): break cap.release() cv2.destroyAllWindows()

conf参数是演示效果的关键,设太高会漏检,设太低会满屏假框。我一般先用 0.4 跑一遍,看漏检多还是误检多,再微调。results[0].plot()返回的是画好框的 numpy 数组,可以直接喂给 OpenCV 显示或写视频文件。

4.2 用 Gradio 搭一个能交作业的演示界面

大作业通常需要一个能点的界面,Gradio 是最省事的方案:

import gradio as gr from ultralytics import YOLO from PIL import Image model = YOLO("runs/garbage/exp1/weights/best.pt") def detect(img): results = model.predict(source=img, conf=0.4) return Image.fromarray(results[0].plot()[..., ::-1]) # BGR 转 RGB demo = gr.Interface( fn=detect, inputs=gr.Image(type="numpy"), outputs=gr.Image(type="pil"), title="垃圾分类检测演示" ) demo.launch(server_name="0.0.0.0", server_port=7860)

这段代码起一个本地网页,上传图片就能看到检测结果。server_name设成0.0.0.0方便局域网访问,答辩时用手机也能演示。注意plot()返回的是 BGR 顺序,转 PIL 前要切片反转通道,否则颜色会偏蓝。

4.3 推理速度优化:从 30 FPS 到 60 FPS 的两个开关

如果演示视频卡顿,先看推理耗时。model.predict里加half=True可以用 FP16 推理,速度提升明显,精度损失很小。另一个开关是imgsz,推理时降到 480 或 416,速度能再提一截,但小目标可能漏。我一般演示用half=True加imgsz=512,在 3060 上能跑到 50 FPS 以上,足够流畅。

5. 避坑与排查:训练和部署中最容易翻车的五个点

5.1 训练 loss 不降反升

现象:第一轮 loss 就很大,后面几轮还在涨。原因通常是学习率设太大,或者数据标签格式错了。解决:先把lr0降到 0.001 试一轮,如果 loss 开始降说明是学习率问题;如果还是乱,用可视化脚本检查标签文件,重点看有没有类别 id 超出nc范围、坐标是不是全零。

5.2 验证集 mAP 一直是 0

现象:训练 loss 正常降,但mAP50始终为 0。原因多半是data.yaml里val路径下没有图片,或者图片和标签没对上。解决:手动数一下images/val和labels/val的文件数是否一致,文件名是否一一对应(除了扩展名)。YOLO 是按文件名找标签的,abc.jpg必须对应abc.txt。

5.3 推理时类别名显示成数字

现象:画出来的框上写的是0、1而不是类别名。原因是推理时没加载data.yaml里的names。解决:model.predict时模型会从权重里读类别名,如果权重训练时data.yaml的names写的是数字,推理就是数字。重新训练时把names写成中文或英文类别名即可。

5.4 显存溢出 OOM

现象:训练到一半报CUDA out of memory。原因是batch或imgsz太大。解决:先把batch减半,还不行就降imgsz到 512 或 416。另外,训练前关掉其他占显存的程序,浏览器看视频也会占显存。

5.5 演示界面图片颜色发蓝

现象:Gradio 界面上传图片后,检测结果颜色偏蓝。原因是 OpenCV 和 PIL 的颜色通道顺序不同,plot()返回 BGR,PIL 要 RGB。解决:在转 PIL 前加[..., ::-1]反转通道,或者用cv2.cvtColor转换。

6. 报告与答辩:怎么把 98 分大作业的细节讲清楚

6.1 报告里必须有的四张图和三个表

报告不是把代码贴一遍就完事。四张图:数据集类别分布图、训练损失曲线、mAP 曲线、混淆矩阵。三个表:不同模型的对比表(比如 YOLOv8n 和 YOLOv8s 的 mAP 和速度)、不同conf阈值下的精度召回表、消融实验表(加没加数据增强的对比)。这些图表直接对应评分点,缺一个就少一块分。

6.2 答辩时被问到「为什么选 YOLO 不选 Faster R-CNN」怎么答

这个问题几乎必问。我的答法是:YOLO 是单阶段检测,推理速度快,适合演示和部署;Faster R-CNN 是两阶段,精度可能略高但速度慢,大作业场景下 YOLO 的性价比更高。如果追问精度,就补一句:在垃圾这类目标上,YOLO 的 mAP 和 Faster R-CNN 差距通常在 1 到 2 个点以内,但速度快好几倍。

6.3 一个让报告加分的技巧:失败案例分析

大部分人报告只写成功案例,我会专门留一节写失败案例:哪类垃圾容易混、什么光照条件下漏检、遮挡场景表现如何。然后给出改进方向,比如补数据、调conf、换更大模型。这一节能体现你真的跑过、分析过,而不是套模板。我那次帮学弟加了这个,他答辩时老师直接说「这部分做得扎实」。

最后说个习惯:每次训完模型,我都会把best.pt、data.yaml、训练命令和关键参数记在一个README.md里,过两周再回头看,不用重新翻聊天记录。这个习惯帮我省了太多后悔药。希望帮到你。

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

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

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

立即咨询