☰
基于YOLO的垃圾分类检测系统:从训练到部署的完整实践
2026/10/16 1:42:27 网站建设 项目流程

简介:面向Python毕业设计开发者的YOLO垃圾分类目标检测系统完整源码包,基于YOLOv8与PyQt5实现垃圾的实时检测与分类展示,支持图像上传、摄像头检测和分类统计,可有效解决传统人工分拣效率低、误差大等问题。系统采用模块化设计,包含数据预处理、YOLOv8推理、图形界面交互与结果输出等模块,同时附有MySQL数据库sql脚本和配套论文文档,便于理解整体架构并直接部署。资源包共2000个文件,以txt标注/数据文件为主,另有md说明、yaml模型配置与docx论文文档,压缩包约229MB,目前已有106人参与学习。配置了完整工程代码与模型文件,可复现描述中mAP@0.5达94.2%的检测效果,适合作为毕业设计源码、课程项目模板或目标检测方向的学习范例。读者可依据md说明快速搭建环境,结合论文文档理解算法细节,并在此基础上扩展优化,适用于社区垃圾站、校园智能分类终端等场景。

1. 项目定位:一个能直接跑起来的YOLO垃圾分类检测系统

如果您正在找Python毕业设计题目,或者想快速落地一个深度学习目标检测项目,这套基于YOLO的垃圾分类检测系统值得花半小时看完。它不像网上那些只贴模型文件、连数据集都没有的“半成品”,而是把训练代码、检测脚本、Web界面和SQL脚本都整合在一起,解压之后按步骤操作就能看到摄像头或图片里的垃圾被框出来并标上类别。对于要做毕业设计的学生来说,它同时覆盖了“模型训练—评估—部署—数据管理”的完整链路;对于想二次开发的工程师,它的模块边界清晰,换数据集和改网络结构都不需要动骨架代码。这篇笔记就按“它能干什么—目录长什么样—核心代码怎么走—跑起来要避哪些坑—怎么改成自己的项目”这个顺序来拆,全程用实践视角说话。

2. 技术选型与整体架构:为什么是YOLO,数据怎么流动

2.1 技术栈:YOLO系列、PyTorch/TensorFlow、Web端与数据库的分工

这个系统的核心检测引擎采用YOLO系列模型。YOLO把目标检测当作回归问题,一次前向传播同时输出边界框和类别概率,在实时性和精度之间取得了很好的平衡。对于垃圾分类这种类别不多(常见分可回收、有害、厨余、其他四类,或者细分成几十类)但要求低延迟的场景,YOLO是比两阶段检测器(比如Faster R-CNN)更务实的选择。模型训练部分常见做法是使用PyTorch实现YOLOv5或YOLOv8结构,因为这两个版本的工程化程度高,预训练权重容易获取,而且导出ONNX或TensorRT模型都很方便。如果您的环境是老机器,也可以退回YOLOv3的Darknet版本,但项目里给出的应该是基于PyTorch的版本,便于在Windows上用GPU或CPU跑通。

后端服务我用常见套路来推断:Flask或FastAPI提供HTTP接口,前端页面负责上传图片、视频流或调用摄像头,检测结果通过JSON返回并渲染到页面上。SQL脚本存放在MySQL中,用于保存用户信息、检测历史记录、垃圾类别对照表等。整个系统的数据流是:输入图片 → 预处理(resize、归一化、letterbox填充)→ YOLO推理 → 后处理(NMS去重、置信度过滤)→ 输出类别坐标与置信度 → 存入数据库并展示。

2.2 目录结构解析:源码、模型、脚本与文档各就各位

拿到完整版的压缩包解压后,建议先按目录梳理一遍。常见的结构包括:

project_root/ ├── models/ # 网络结构定义(yolo.py、common.py等) ├── utils/ # 数据处理、增强、绘图工具 ├── detect.py # 单张图片/视频/摄像头检测入口 ├── train.py # 模型训练脚本 ├── test.py # 模型评估脚本 ├── app.py # Web服务入口(Flask/FastAPI) ├── requirements.txt # Python依赖清单 ├── data/ # 数据集配置yaml、标签文件 ├── weights/ # 预训练权重或训练好的best.pt ├── sql/ # 数据库初始化脚本 ├── templates/ # 前端HTML页面 └── static/ # 前端CSS/JS/上传图片存放

建议新手拿到项目后先打开requirements.txt,用pip install -r requirements.txt安装依赖。随后重点看data目录下的数据集配置文件,它决定了模型要学习哪些类别。SQL脚本则放在sql目录里,用Navicat或命令行导入即可。整个项目把“模型相关”和“业务相关”分开了,改前端或改模型不会互相干扰。

2.3 数据集与类别映射:垃圾类别怎么定义

垃圾分类检测的核心是类别标签的统一。训练脚本需要一份YAML文件,里面写入类别名称和对应ID,例如:

train: data/train.txt # 训练集图片路径列表 val: data/val.txt # 验证集图片路径列表 nc: 4 # 类别总数 names: ['recyclable', 'harmful', 'kitchen', 'other']

这段配置决定了模型输出的通道数。如果您的项目是更细分的40类垃圾(比如塑料瓶、易拉罐、电池、果皮……),就要修改nc和names。注意:SQL数据库里的类别表和YAML里的names必须一一对应,否则检测结果存进数据库时会出现对不上号的情况。常见做法是让数据库表结构里的category_code与YAML的索引ID保持一致,比如0代表可回收,1代表有害。

3. 核心模块拆解:从图片输入到检测结果落库的完整链路

3.1 预处理与推理:detect.py 的关键代码逻辑

检测模块是整个系统的主干。下面这段代码是detect.py里最常见的主流程(以YOLOv5风格为例):

import cv2 import torch from models.experimental import attempt_load from utils.general import non_max_suppression, scale_coords # 加载模型,weights/best.pt为训练好的权重 model = attempt_load('weights/best.pt', map_location='cpu') model.eval() # 读取图片 img0 = cv2.imread('test.jpg') # letterbox填充,保证输入尺寸为640x640且不失真 img = letterbox(img0, new_shape=640)[0] img = img[:, :, ::-1].transpose(2, 0, 1) # BGR转RGB,并转为CHW img = torch.from_numpy(img).float() / 255.0 # 归一化到0~1 img = img.unsqueeze(0) # 增加batch维度 with torch.no_grad(): pred = model(img)[0] # 推理,输出原始预测 pred = non_max_suppression(pred, conf_thres=0.4, iou_thres=0.5) # 将坐标从letterbox后的尺寸映射回原图 for det in pred: if len(det): det[:, :4] = scale_coords(img.shape[2:], det[:, :4], img0.shape) # det的每一行是[x1, y1, x2, y2, conf, class_id]

这段代码逻辑说明:首先通过attempt_load加载权重,这里用的是YOLOv5的加载方式;letterbox函数把原图等比缩放到640×640,同时用灰色填充边缘,避免拉伸变形影响检测精度;non_max_suppression做非极大值抑制,把同一目标的多余框合并;最后scale_coords把坐标还原到原始图像尺寸。参数方面,conf_thres=0.4表示置信度低于40%的目标会被过滤,在垃圾分类场景中建议设置在0.4~0.5之间,太低会误检,太高会漏检;iou_thres=0.5是NMS的IOU阈值,默认即可。

3.2 Web接口调用:Flask端如何接收图片并返回结果

为了让毕业设计演示更直观,系统通常带一个Web页面,用户上传照片后后端调用检测模型。核心路由代码:

from flask import Flask, request, jsonify, render_template import base64 import numpy as np import cv2 app = Flask(__name__) def predict_one(image_path): # 内部调用detect逻辑,返回检测到的类别与坐标列表 results = detect_image(image_path) return results @app.route('/upload', methods=['POST']) def upload(): file = request.files['file'] img_bytes = file.read() np_arr = np.frombuffer(img_bytes, np.uint8) img = cv2.imdecode(np_arr, cv2.IMREAD_COLOR) tmp_path = 'static/upload/temp.jpg' cv2.imwrite(tmp_path, img) results = predict_one(tmp_path) # results格式:[{'class': 'kitchen', 'conf': 0.91, 'box': [x1,y1,x2,y2]}, ...] return jsonify({'code': 0, 'data': results})

说明:前端把文件以form-data格式POST到/upload接口,后端用cv2.imdecode把字节流还原成OpenCV图像,然后调用检测函数,最后以JSON返回。这里要注意文件上传的编码格式,如果前端用的是base64字符串,则需要改为request.json['file']再解码。在实际项目中,我会把检测函数封装成独立模块,Flask路由只负责接收请求和返回响应,这样单元测试时不需要启动Web服务也能验证模型效果。

3.3 检测历史写入SQL:造一条带图片路径和结果详情的记录

数据库这块,SQL脚本里至少会有三张表:用户表、垃圾类别表、检测记录表。检测记录表字段设计大致如下:

CREATE TABLE `detect_history` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `user_id` INT NOT NULL, `image_path` VARCHAR(255) NOT NULL COMMENT '图片保存路径', `result_json` TEXT COMMENT '检测结果JSON,含类别、坐标、置信度', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, KEY `idx_user` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

每次检测成功后,将图片副本保存到static/upload/目录,并将结果序列化为JSON存入result_json字段。这样做的优点是不用为了存储多个检测框而建一张子表,直接塞JSON,读取时再解析,非常适合毕业设计这种数据量不大的场景。如果要统计每个用户检测了多少次可回收垃圾,用SELECT * FROM detect_history WHERE result_json LIKE '%recyclable%'也能凑合,但更规范的做法是在写入时额外用一列存储主类别,比如main_class字段,方便后续做报表。

4. 模型训练与效果评估:从数据集到best.pt的实操路径

4.1 训练脚本参数与启动方式

拿到项目后,如果您想从头训练而不是用附带的权重,需要先准备好标注数据集。训练入口通常是train.py,关键参数如下:

python train.py --data data/garbage.yaml --weights yolov5s.pt \ --epochs 100 --batch-size 16 --img 640 --device 0

参数说明:--data指向数据集配置文件,--weights可以填预训练权重(如yolov5s.pt)或已有的best.pt做微调,--epochs训练轮数,垃圾检测数据集一般100轮能收敛,--batch-size为16或32取决于显存大小,--img输入分辨率640,--device 0表示用第一块GPU,CPU环境可以改为--device cpu但速度会很慢。训练过程中会生成runs/train/exp*/目录,里面有损失曲线图和验证集预测结果,您可以根据results.png判断是否过拟合。

4.2 模型评估指标:mAP、Precision、Recall怎么看

训练完成后,运行test.py --weights weights/best.pt --data data/garbage.yaml会输出一套指标。重点看三个值:Precision(查准率,检测出的目标中有多少是正确的)、Recall(查全率,真实垃圾中有多少被找出来)、mAP@0.5(IOU阈值为0.5时各类别AP的平均值)。垃圾分类场景里,漏检比误检更让人头疼,所以我会优先追求Recall,如果Recall低,说明阈值设高了或者模型容量不够。同时要检查每个类别的单类AP,比如“有害垃圾”往往因为样本少导致AP偏低,这时需要做数据增强或补充样本。

4.3 训练失败常见情况:显存溢出、数据集路径错误、标签修正

第一类:显存溢出(CUDA out of memory)。原因通常是batch-size太大或模型输入尺寸太大。解决方法是调小batch-size到8或4,或者换用更小的模型如yolov5s代替yolov5m。第二类:训练时报错“Can't find dataset”。原因多半是data/garbage.yaml里的train和val路径是绝对路径,换电脑后没改。解决:把图片路径列表写成txt并放到固定目录,或者在项目根目录下创建data/images文件夹统一管理。第三类:加载预训练权重时报key mismatch。原因是类别数量不一致,解决办法是忽略匹配不到的权重层,在train.py中找到exclude参数(如exclude='head')或删除weights文件里的分类层再加载。

5. 避坑指南:运行这个YOLO项目最容易翻车的四个地方

5.1 坑一:requirements.txt版本不一致导致torch加载崩溃

现象:运行detect.py时提示AttributeError: module 'torch' has no attribute 'from_numpy'或者直接段错误。原因:PyTorch版本太旧,或者本地装了多个环境,pip把依赖装错地方了。解决方案:先python -m pip list | findstr torch确认版本,如果项目要求是1.9.0以上,直接卸载重装指定版本:pip install torch==1.12.0+cu116 -f https://download.pytorch.org/whl/torch_stable.html。如果实在装不上,去官网下载对应CUDA的whl文件本地安装。注意:YOLOv5的代码对不同torch版本兼容性有差异,强烈建议严格按requirements.txt里面的版本号创建虚拟环境。

5.2 坑二:中文垃圾图片路径或文件名导致OpenCV读不出图

现象:cv2.imread返回None,但路径明明存在。原因:OpenCV的imread不支持中文路径(严格说是Windows下编码问题),当图片放在桌面/测试图/厨余1.jpg这种路径下就会读不到。解决方式:修改读图代码,改用cv2.imdecode配合numpy。以下代码可以代替imread:

import numpy as np import cv2 def imread_unicode(path): data = np.fromfile(path, dtype=np.uint8) img = cv2.imdecode(data, cv2.IMREAD_COLOR) return img

这是血泪经验,凡是做中文项目,所有图片读取入口都该用这个函数,否则用户上传的中文文件名图片会把整个检测流程打断。

5.3 坑三:Web后端返回结果,前端画框时坐标错位

现象:页面上标记框的位置明显偏了,比如框跑到垃圾的左边。原因:前端使用原始图片的宽度给像素坐标,但后端返回的是letterbox填充后还原的坐标,而还原时scale_coords输入参数顺序写错。解决:检查detect.py中scale_coords的第一个参数必须用letterbox处理后的尺寸img.shape[2:](即H和W),第二个参数传prediction,第三个参数传img0.shape(原始图像的H和W)。另外一个容易忽视的点是前端渲染时,如果图片是CSS缩放显示的,需要按缩放比例换算坐标。比如CSS里图片宽度显示为400px,而原图是800px,那么前端画框时要乘0.5。

5.4 坑四:SQL脚本导入时报错,表结构与代码字段对不上

现象:项目跑通了,但保存检测记录时报Unknown column 'main_class'。原因:sql文件夹里的脚本是初始版,而代码里后来加了字段没更新脚本。解决:先对比代码中的SQL语句与实体类字段,如果改动不大就直接改数据库表:ALTER TABLE detect_history ADD COLUMN main_class VARCHAR(50) DEFAULT NULL;。如果脚本版本混乱,干脆把库删了重新执行一次完整的sql脚本。注意MySQL的字符集要统一为utf8mb4,否则存emoji或特殊字符会报错,垃圾分类名称里偶尔有生僻字,utf8mb4能兜住。

5.5 坑五:摄像头检测延迟大,画面像幻灯片

现象:用usb摄像头做实时检测时,摄像头画面一卡一卡,帧率只有个位数。原因:每帧都调用模型推理,而没有控制帧率;以及没有用GPU推理。解决:两步走,第一在摄像头循环中加入跳帧逻辑,比如每检测一帧,跳过中间5帧直接显示原始帧;第二把model加载时指定device='cuda',并且使用torch.no_grad()和torch.cuda.synchronize()配合,减少CPU与GPU之间的同步次数。实际项目中把输入分辨率从640降到416,推理速度能提升一倍,精度在垃圾分类上几乎不降。

6. 二次开发:把这套检测系统改成属于自己的小创新

拿到完整版之后,大部分人不会只满足于原样跑通,而是想加一点自己的亮点。最简单的微创新方向是“语音播报分类结果”,在检测到垃圾后调用系统TTS。基于Flask后端,在返回结果给前端时,前端用Web Speech API直接播放中文类别名,30行代码以内就能完成。如果你想把检测做进答题小程序或调用API的App,只需要改动app.py里的返回格式,把原来的JSON结构改成{code:0, list:[{name:'可回收垃圾', score:0.9}]},不需要动模型层。

另一个更具技术含量的改造是“数据集自扩展”。原系统自带的数据集可能只有几百张图,遇到形态多变的垃圾容易漏检。我实践过一套流程:先跑一遍检测,把置信度低于0.6但是人工确认属于正确类别的图片收集到“难例池”,然后用YOLOv5的--resume从best.pt继续训练难例池数据。这样做的好处是模型能记住之前分错或者犹豫不决的样本。注意难例池的图片要包含被误检背景,不要只裁剪目标本身,否则会破坏上下文信息。

如果您想把系统升级为“多模型融合投票”,思路是同时加载YOLOv5和YOLOv8,分别在两张卡上推理,如果两个模型输出的框IOU大于0.6且类别一致,则视为高置信度结果,否则判为待人工复核。这种模式在垃圾分类PK竞赛里挺常见,虽然增加了推理耗时,但能把总精度提升3到5个百分点,而且代码改动集中在detect环节,不影响数据库结构。

最后说说我对这套项目的实践习惯:拿到项目的第一时间,我先复制一份原始压缩包备份,然后把训练数据和权重单独放在一个不被Git跟踪的目录里,再对detect.py做最小侵入改造——把图片输入输出抽象成process_image(image_array) -> list。从那以后,每次换数据集或换Web框架,我都强制走一遍“先跑原始版本,再改接口,最后调阈值”的流程。这个顺序能避免一半以上的玄学问题。希望今天的拆解能帮您少走些弯路,尽快把这份项目变成自己的作品。

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

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

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

立即咨询