ARTICLE DETAIL

资讯详情

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

基于YOLO和PyTorch的垃圾分类目标检测系统实战

基于YOLO和PyTorch的垃圾分类目标检测系统实战 简介一套基于深度学习的垃圾分类目标检测系统源码主要面向毕业设计、期末大作业和课程设计适合已有Python基础、希望快速搭建同类项目的学生使用。代码注释完善项目结构清晰下载部署后即可运行压缩包内附Jupyter Notebook教程可逐步跟进数据处理、模型训练与检测推理的完整流程。包内共117个文件大小仅7.33MB以Python脚本、YAML配置、JSON数据和前端页面文件为主同时包含Dockerfile与Shell脚本便于快速完成环境配置还包含微信小程序相关文件WXML/WXSS可作为移动端展示或实验拓展参考。源码来自一个高分项目作者自述获得98分评价整体逻辑完整从项目组织到代码风格都值得借鉴也可作为系统设计、文档撰写与答辩展示的参考样板。已有368人学习下载适合需要参考完整项目结构或快速启动垃圾分类检测开发的学习者。1. 垃圾分类目标检测这可能是你毕业设计里性价比最高的一道题如果你在找“Python基于深度学习的垃圾分类目标检测系统源码”大概率是毕设、课设或者找工作用的作品集。这个课题流行了好几年但每年都还有人往坑里跳要么下载了一份跑不起来的残缺代码要么模型训练出来精确率只有五成要么答辩时被老师问一句“你怎么证明你的模型真的学到了特征”就卡住。先说结论垃圾分类目标检测核心难点从来不是模型本身而是数据怎么处理、训练参数怎么调、以及系统怎么包装成能演示的作品。只要是做目标检测的大作业“检测系统”四个字基本就锁定了技术路线YOLO 系列作为检测器、PyTorch 作为训练框架、PyQt5 或 Web 页面做交互界面。这个组合能够覆盖“深度学习算法”和“软件工程”两块课程要求这也是为什么它成为 Python 高分大作业的常青树。这篇文章不谈虚的直接按数据准备、模型训练、界面集成、答辩验收的顺序把每一步的做法和坑都拆给你看连训练时最容易翻车的参数设置一起讲。适合的人群是有 Python 基础、看过一点深度学习理论、但第一次独立做完整目标检测项目的同学。2. 从数据集到 YOLO 格式这一步做好了训练就成功了一半2.1 公开数据集的类别映射比你想象中更麻烦做垃圾分类检测通常选有图像分类版本的公开数据集因为这类数据集的图像通常是一张图一个类别做检测时拿过来当“单目标图像”用比自己去网上 crawl 图片省很多时间。常见做法是下载含有几十个垃圾类别的图像数据集这些数据集中图像的表示形式多为“类别名/图片.jpg”但没有框的标注文件。所以第一步不是急着写训练代码而是统一类别体系。# 定义你最终要检测的类别清单这里以常见的 6 类为例 WASTE_CLASSES { cardboard: hard_paper, # 纸板 - 硬纸类 paper: hard_paper, glass: glass, metal: metal, plastic: plastic, trash: other_waste, # 数据集里的混杂垃圾归为其他 }逻辑说明这段代码解决的是类别名不统一的问题。公开数据集里的标签可能是英文常见名而中国高校题目里常见的是“可回收物/有害垃圾/厨余垃圾/其他垃圾”这种四分类口径。建议在训练前先做一次类别映射把源数据集的类别合并到你最终要展示的类别上而不是直接拿源类别去训练。参数说明映射表的键是源数据集的类名值是你自定义的类名。如果你做的是“可回收 vs 厨余 vs 有害 vs 其他”四分类就按这个维度写映射。这里有一个很多人忽略的细节类别数越少训练难度越低mAP 越高。比如 6 类与 40 类的训练难度差别不是 6 倍而是远高于这个倍数因为相似类别比如不同材质的纸会让模型频繁产生混淆预测。你的题目叫“垃圾分类目标检测”而不是“垃圾细粒度识别”所以类别控制在 4 到 8 类是稳妥的范围。2.2 批量生成标注文件并划分数据集图片分类数据没有框常见做法是用脚本为每张图生成一个覆盖整图的标注框。如果你想验证模型在真实场景下的泛化能力可以留出 20% 的图片手动用开源标注工具画几个物品堆叠场景的框。下面这个脚本负责把分类数据集转成 YOLO 需要的 txt 标注。import os import random from pathlib import Path IMAGE_DIR datasets/raw_images LABEL_DIR datasets/labels # 保存 YOLO 格式 txt 标注 IMAGE_OUT datasets/images # 保存整理后的图片 os.makedirs(LABEL_DIR, exist_okTrue) os.makedirs(IMAGE_OUT, exist_okTrue) for class_name, images in class_to_images.items(): cls_id list(WASTE_CLASSES.values()).index(class_name) for img_path in images: # 整图作为目标框x_center0.5, y_center0.5, w1, h1 txt_path os.path.join(LABEL_DIR, Path(img_path).stem .txt) with open(txt_path, w) as f: f.write(f{cls_id} 0.5 0.5 1 1\n) # 复制或移动图片到统一目录 shutil.copy(img_path, os.path.join(IMAGE_OUT, Path(img_path).name))逻辑说明YOLO 的 txt 标注行格式是“类别id x_center y_center width height”所有坐标值都是相对于图片宽高的比例值范围 0 到 1。上面生成的标注等价于“整张图里有一个目标”这在目标检测里叫弱标注能让模型学到“这个类别的东西长什么样”但学不好“定位”。参数说明0.5 0.5 1 1代表框中心在图片正中心、宽高为整图尺寸。如果你的数据集里有部分图是多个物体堆叠建议还是手动框一框借用开源标注工具画框后导出 YOLO 格式即可。数据划分这一步别用 random.shuffle 裸分先用脚本检验各类别图片数量。常见坑是测试集里某个类别只有个位数样本训练时这类样本掉点非常厉害。按类别分层抽样是更稳的方式。def split_dataset(image_paths, labels, train_ratio0.8): from sklearn.model_selection import train_test_split # 按标签分层划分保证每个类别在训练/验证集中都有足够样本 train_imgs, val_imgs, train_labels, val_labels train_test_split( image_paths, labels, test_size1 - train_ratio, stratifylabels, random_state42 ) return train_imgs, val_imgs逻辑说明stratifylabels的意思就是让划分后的训练集和验证集里每个类别的占比和原始数据集保持一致。很多同学在这里直接用random.shuffle最后验证集里塑料类 3 张图片、玻璃类 40 张训练时 loss 表现很好validation 指标却忽高忽低。参数说明random_state42固定随机种子保证每次跑出的划分一致方便复现调试。2.3 数据增强参数别把真实场景增没了垃圾分类的数据增强和做车牌识别、人脸检测不太一样因为它面向的是“垃圾放在桌子上、地上、垃圾桶旁”这类真实场景纯几何变换太多会让模型学到错误的位置相关性。我一般会把增强分成两类一类是色彩抖动亮度、对比度、饱和度模拟不同光照环境另一类是 Mosaic 和随机仿射变换用来提升模型对尺度和遮挡的鲁棒性。在 YOLOv5 或 YOLOv8 的训练配置里超参数文件中有几个关键项hsv_h: 0.015色调变化范围不用太大垃圾的颜色是重要特征hsv_s: 0.7饱和度变化范围往大调一点可以让模型适应不同颜色的垃圾桶和塑料袋hsv_v: 0.4亮度变化范围主要是模拟白天、傍晚不同光照degrees: 0.0旋转角度这里建议设 0因为“瓶子倒了”和“瓶子立着”在语义上同类但旋转过多会干扰模型理解这段不是代码是 YOLO 训练时超参数配置的语义在你的训练 yaml 中修改即可。数据增强的调试建议是先用默认参数训练一轮看 mAP如果发现验证集里“光线偏暗”的图片检测效果差再逐步增大hsv_v如果发现小目标远处的小纸团漏检率高可以把 Mosaic 概率调高到 1.0。反过来如果增强太猛导致训练 loss 降不下去优先调回色彩类增强参数而不是关掉几何增强。3. 模型选型与训练用 YOLO 系列跑通最小闭环3.1 为什么选 YOLOv5 / v8 而不是更“前沿”的模型你要交的是一个能演示、能答辩的系统不是刷榜的竞赛方案。目标检测领域每半年就有新模型出现但作为个人大作业模型的可解释性、生态成熟度、显卡资源占用才是第一位的。YOLOv5 的优点是资料全、调参经验多、任何一个报错都能搜到解决方案YOLOv8 的优点是代码结构更干净、训练接口更统一而且自带实例分割和姿态估计的扩展。选 v5 还是 v8取决于你的复现能力——如果你之前完全没有跑通 v5 的经验直接上 v8 是更快的一条路。环境配置这一步建议别跟着网上所谓的“保姆级教程”一步一步复制粘贴因为 CUDA 版本和 PyTorch 版本之间的匹配关系才是关键。用你本机nvidia-smi看到的 CUDA 版本号去官网挑对应版本的 PyTorch这条准则能避开九成环境问题。环境配不好就放弃 GPU 训练、用 CPU 跑通代码流程也比卡在环境里强因为代码跑通了之后 GPU 是顺势的事。3.2 训练命令与参数调整只看 Loss 是新手习惯YOLOv8 使用命令行工具训练常见命令如下yolo detect train datawaste.yaml modelyolov8n.pt epochs100 imgsz640 batch16 workers4 device0参数说明modelyolov8n.pt表示加载 YOLOv8 nano 预训练权重nano 是参数量最小的版本显存占用约 2GB适合学生显卡imgsz640是把输入图片统一缩放到 640×640这也是速度与精度之间的折中值batch16是每批图片数量如果你的显卡只有 6GB 显存把 batch 降到 8 或 4workers4是数据加载线程数Windows 下设 0 可以避免一些奇怪的报错。epochs100是训练轮数但对于垃圾检测这类中低难度任务50 到 80 轮基本已经收敛100 轮是为了保险。训练完成后别只看results.png里那张 loss 下降曲线。loss 降了不代表检测效果好要重点看验证集上的mAP50和mAP50-95两个指标。mAP50 是 IoU 阈值为 0.5 时的平均精确率通俗解释就是“预测框和真实框重叠一半以上就算检测成功”mAP50-95 则是在 0.5 到 0.95 一系列阈值下的平均值它对框的定位精度要求更严格。作为大作业mAP50达到 0.85 以上就算很有说服力mAP50-95能到 0.6 就已经说明你的模型不是背答案。3.3 训练结果里哪张图最值得放进答辩 PPT很多人答辩时只会展示 loss 曲线和 mAP 数值但老师更想看的是模型“错在哪里”。训练完后 YOLO 会生成val_batch0_pred.jpg这类图片里面是模型在验证集上的预测结果有框有类别有置信度。这里要特别留意两类图正确预测且置信度高0.8 以上的图放进答辩 PPT 说明“模型学到特征了”错误预测比如把玻璃瓶认成塑料瓶的图放到“分析与改进”页讲清楚为什么出错——这比只说“准确率 90%”更有技术深度再用下面这段代码从测试集中跑一遍推理并输出分类混淆矩阵from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) metrics model.val(datawaste.yaml, splittest) print(metrics.box.maps) # 每个类别的 mAP print(metrics.box.matrix) # 混淆矩阵形状为 [cls_num, cls_num]逻辑说明混淆矩阵对角线上的数值代表正确分类的比例非对角线元素代表两个类别互相混淆的程度。比如“塑料瓶”和“玻璃瓶”两类间的数值大说明模型主要靠颜色而不是形状来区分垃圾这个结论写进论文分析段就是加分项。如果发现某个类别的 mAP 显著偏低先回到数据集检查这个类别的图片数量、标注质量和场景多样性而不是急着调模型结构。4. 从模型到“系统”把源码变成能演示的 Python 大作业4.1 界面选型PyQt5 还是 Flask Web 页面大作业系统通常有两种展示形态桌面端和 Web 端。选择依据是你的项目定位与演示环境。如果你是在机房答辩、老师用投影仪看演示Web 页面的适应性更好因为不依赖本机安装 Python 环境如果要求交的是“软件系统”且需要支持本地相机实时检测则 PyQt5 桌面端更合适。两者在工程量上限上没有本质差别差别在于排查问题时的难易程度——PyQt5 的界面线程问题会比 Flask 更隐蔽。对多数人来说PyQt5 会更稳妥一些因为“上传图片→显示结果→保存结果”这三步逻辑非常直接代码量也小。以下是选择界面框架的横向对照对比维度PyQt5 桌面端Flask Web 端环境依赖需要安装 PyQt5 库和正确显示驱动需要浏览器环境更通用相机实时检测线程设计相对复杂需要 WebRTC 或 MJPEG 推流演示可靠性现场翻车概率低端口占用、浏览器兼容都有风险代码量界面代码约 100 行前后端合计约 200 行以上4.2 PyQt5 界面骨架按钮、预览、结果展示下面是基于 PyQt5 的最小检测界面实现注意去掉无关装饰只保留核心逻辑import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton, QFileDialog, QVBoxLayout, QWidget from PyQt5.QtGui import QPixmap, QImage import cv2 from ultralytics import YOLO class WasteDetectorApp(QMainWindow): def __init__(self): super().__init__() self.model YOLO(best.pt) # 加载训练好的权重 self.setWindowTitle(垃圾分类检测系统) self.image_label QLabel(请选择图片) self.btn QPushButton(选择图片并检测) self.btn.clicked.connect(self.detect_image) layout QVBoxLayout() layout.addWidget(self.image_label) layout.addWidget(self.btn) container QWidget() container.setLayout(layout) self.setCentralWidget(container) def detect_image(self): file_path, _ QFileDialog.getOpenFileName(self, 选择图片, , Images (*.jpg *.png)) if not file_path: return results self.model(file_path) # 推理 annotated results[0].plot() # 画出检测框和标签 h, w, c annotated.shape qimg QImage(annotated.data, w, h, 3 * w, QImage.Format_RGB888).rgbSwapped() self.image_label.setPixmap(QPixmap.fromImage(qimg)) if __name__ __main__: app QApplication(sys.argv) win WasteDetectorApp() win.show() sys.exit(app.exec_())逻辑说明results[0].plot()是 YOLO 库自带的绘制方法会把检测框、类别名和置信度画到图片上返回 numpy 数组。这里把 OpenCV 的 BGR 格式通过rgbSwapped()转成 Qt 能显示的 RGB 格式这是 PyQt 显示图片最容易忘记的一步。整个界面只有两个核心元素图片显示控件和触发检测的按钮。参数说明QLabel既用来提示文字也用来承载图片省去额外的显示控件QFileDialog.getOpenFileName返回文件路径若用户点击取消则返回空字符串所以这里需要做一次空值判断。界面写到这里已经是一个“系统”了但离高分还差一步视频流检测。常见的做法是在界面里加一个“打开摄像头”按钮用QThread子线程不断读取摄像头帧并送入模型。线程这块是很多学生项目里最容易写崩的地方——直接在 UI 线程里跑模型会导致界面卡死。更稳的写法是每读取一帧就送入模型但把model()调用放在子线程中等结果出来后用信号传给主线程更新画面。4.3 我见过翻车最多的地方路径全部写死测试界面时一切正常拷贝到另一台电脑演示就崩——大概率是代码里用了绝对路径。你的代码目录里应该只出现相对路径模型权重文件放在项目根目录的weights/子目录中用os.path.join(weights, best.pt)引用。同理界面里如果用了自定义图标、字体也走相对路径。这个细节虽然简单但在答辩现场价值千金因为它决定了你的项目能不能在老师电脑上直接跑起来。5. 训练与部署避坑5 个高频问题与排查顺序结合这几年见到学生项目里反复出现的问题下面按“现象 → 原因 → 解决”写几条最容易踩的坑。问题 1训练时 loss 出现 nan训练中断现象前几个 epoch 的 loss 还能下降到某一轮突然变成 nan之后一直报错。原因最常见的是学习率设置过高导致梯度爆炸其次是数据里有异常标注比如坐标值超过 1 的框另外还有可能是 batch size 太大导致显存溢出后某一步数据损坏。解决优先检查标注文件里是否有width或height大于 1 的值然后把学习率调低一半重训如果仍然出现 nan把 batch size 减半。问题 2训练时 mAP 很高但测试集上识别效果很差现象validation 上的 mAP 超过 0.9换一张没见过的图片检测效果却一塌糊涂。原因这是典型的过拟合或者你的验证集分布与测试集不一致。很多同学把同一个数据集既做训练又做验证没有留出独立的测试集导致模型“背”下了训练图片而不是学到了泛化特征。解决把数据集分成训练集70%、验证集15%、测试集15%训练过程中只允许用训练集和验证集最后用从未参与训练的测试集做最终评估。问题 3检测框偏移、框比物体大很多现象置信度很高但框的位置明显不对——框的中心在物体旁边或者框大到跨越整图。原因整图标注0.5 0.5 1 1占比太高。当训练数据里“整图一个框”的比例超过 80% 时模型会倾向于输出大框。解决把大部分分类数据转成“目标居中、框占整图 50%~80% 面积”的标注——在生成标注脚本里按 0.6–0.8 的比例缩小宽高并保持中心在图片中心附近。问题 4界面点击“选择图片”后卡死无响应现象点击按钮后界面白屏过几秒恢复检测期间无法进行任何其他操作。原因检测放在了 UI 主线程中模型推理是耗时操作阻塞了界面的事件循环。解决将检测过程放进QThread完成后通过信号把结果传回主线程。代码层面就是新建一个继承QThread的类在run()方法里执行model()和results[0].plot()。问题 5换一台电脑后 import 报错或模型加载失败现象在自己的电脑上运行正常拷贝到其他机器上运行报错比如No module named torch或模型文件路径找不到。原因没有做环境导出也没有把权重文件放进项目目录的固定路径中。Windows 下如果把权重放在桌面并通过绝对路径引用换机器必崩。解决在项目根目录建requirements.txt用pip freeze requirements.txt导出依赖清单并在文档中写明安装命令模型权重文件放在项目weights/目录下代码中统一使用相对路径引用。6. 答辩验收前的自查方法用数据证明你的系统有效如果你已完成上述步骤最后要做的事不是再调一轮模型而是系统地做一次验证与数据准备。准备一个包含 50 张新图片的测试集可以是网上找的、自己拍的运行一次完整推理并把结果保存到统一目录yolo predict modelweights/best.pt sourcetest_images/ saveTrue conf0.25然后统计这一批测试图片中成功检测出目标的比例、错误率以及平均置信度。这些数字写进论文的“结果分析”章节比任何描述都更有说服力。答辩时如果老师问“准确率为什么不是 99%”可以说明置信度阈值的影响conf0.25是允许低置信度预测出现因此框会更多但不一定更准如果把阈值提高到 0.5误检会下降但漏检可能上升“阈值选择需要根据场景来权衡”本身就是一句很好的答辩回答。还有一个容易被忽视的加分项运行一次视频推理并录屏。在代码里传入一段垃圾桶附近的视频让模型逐帧检测并输出标注后的视频文件这能直观展示你的系统不是“只在静态图上有效”。如果视频文件太大可以只截取 20 秒用来演示。我的一个习惯是在最终提交前把整台电脑断网后再跑一遍系统。因为依赖项是否完全打包好、模型文件是否被外部引用断网环境下都会暴露出来答辩现场的电脑条件通常不会比你的开发机更好提前在“最差环境”下验证是避免现场翻车的最后一道保险。这个习惯帮我避免过很多次尴尬希望能帮到你。本文还有配套的精品资源点击获取
返回列表