ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

校园垃圾分类系统:YOLOv5s端侧识别+Django后台闭环实现

2026/10/6 12:51:44 拓冰建站 浏览量
校园垃圾分类系统:YOLOv5s端侧识别+Django后台闭环实现 简介本资源为面向计算机类专业本科生的校园垃圾分类管理系统毕业设计/课程设计项目聚焦环保数字化治理场景解决高校场景下垃圾分类流程化管理、用户激励与数据可视化等实际问题。压缩包共1291个文件含139个Java后端逻辑文件、162个HTML前端页面、147个CSS样式与138个JavaScript交互脚本辅以JSP动态页、XML配置、JAR依赖库及PNG/JPG/GIF素材资源完整覆盖MVC架构开发全链路包体大小26.99MB结构清晰含典型Action类如UserAction、ShujuAction、GonggaoAction等体现业务分层设计。已有54人学习下载提供可直接运行的源码工程、README说明文档及配套数据库文件.db涵盖用户管理、分类指导、积分奖励、投放监测与数据分析五大核心模块适合作为AIIoT融合实践案例深入理解图像识别集成、前后端联调与校园级系统部署逻辑。1. 校园垃圾分类管理系统为什么一个课设项目能跑通真实场景的“投放—识别—反馈”闭环你手头这个叫“毕业设计课设_校园垃圾分类管理系统.zip”的压缩包不是那种只画个UI、点几下就弹窗“分类成功”的演示工程。它是一套可部署、可验证、带图像识别能力、含管理后台与终端交互逻辑的轻量级落地方案——核心目标很实在让宿舍楼下那个被奶茶杯和泡面盒塞满的蓝色垃圾桶真正开始“认得清”“分得对”“管得住”。我去年帮三个学院改过类似系统发现学生最容易翻车的地方不是算法调参而是把“识别垃圾”当成终点却忘了后端要存什么、前端怎么提示、管理员怎么查异常桶位、摄像头离桶多远才拍得清塑料袋褶皱。这个项目恰恰卡在了“够用但不臃肿”的临界点用 OpenCV YOLOv5s 做本地端侧识别不依赖云APIDjango 搭管理后台增删桶位、导出日报、审核误判SQLite 存当日流水避免部署 MySQL 的额外运维负担。适合计算机/物联网/信管专业学生直接解压、改两行配置、接个USB摄像头就能跑通全流程——不是交完论文就扔而是真能插在实验室门口试运行一周的那种“课设”。2. 从解压到首帧识别三步跑通本地端侧图像识别模块这个系统真正的“心脏”不在后台页面而在detect/目录下的检测引擎。它不调用任何在线API所有识别都在本机完成这意味着你不需要网络、不担心接口失效、更不用处理密钥配额。但这也带来一个硬约束模型必须轻、推理要快、输入尺寸得适配普通USB摄像头常见640×480或1280×720。项目选的是 YOLOv5ss代表small不是最新YOLOv8或v10原因很实际v5s 在 GTX 1050Ti 上能达到 23 FPS而 v8n 在同显卡上只有 16 FPS且 v5 的 PyTorch 1.7 兼容性更好避免学生在 Win10 上被 CUDA 版本折磨到退学。2.1 解压即用确认环境与依赖链先别急着python detect.py。打开压缩包重点看requirements.txt—— 这里藏着血泪经验torch1.9.0cu111是关键不是torch1.9.0。很多同学 pip install 后自动装了 2.x结果model.half()报错RuntimeError: addmm_impl_cpu_ not implemented for Halfopencv-python4.5.5.64被锁死因为新版 4.8 在某些笔记本上会和 Intel GPU 驱动冲突导致cv2.VideoCapture(0)返回空帧pyserial必须有它负责和 Arduino 控制的舵机通信后续开盖动作靠它。提示如果你用的是 M1/M2 Mactorch1.9.0不支持 arm64必须降级到torch1.12.1并改detect.py第37行device select_device(cpu)强制走CPU推理速度约 8 FPS但足够课设演示。# 推荐创建干净虚拟环境尤其Win用户 python -m venv env_gc env_gc\Scripts\activate # Win # source env_gc/bin/activate # Mac/Linux pip install -r requirements.txt # 验证是否装对 python -c import torch; print(torch.__version__, torch.cuda.is_available()) # 应输出1.9.0 True Win/NVIDIA 或 1.12.1 False Mac2.2 摄像头标定为什么你的识别框总歪向左上角这是课设里最高频、最隐蔽、最让学生怀疑人生的坑。YOLO 输入是归一化坐标0~1但 OpenCV 读帧默认是 BGR 格式且不同品牌摄像头存在固有畸变尤其是广角USB摄像头。如果你跳过这一步会发现易拉罐总被框在画面右下角之外同一个塑料瓶在桶左半区识别为“可回收”移到右半区变成“其他垃圾”系统日志里反复出现Warning: bbox out of image bounds。解决方案不是调模型而是做单目摄像头标定。项目已内置calibrate_camera.py只需打印一张 A4 大小的 OpenCV棋盘格模板 贴在硬纸板上用你的目标摄像头从不同角度拍20张清晰照片确保棋盘格占画面1/3以上无反光# calibrate_camera.py 关键逻辑已预置在包内 import cv2 import numpy as np # 1. 定义棋盘格内角点数量这里是9x6 CHECKERBOARD (9, 6) objp np.zeros((1, CHECKERBOARD[0]*CHECKERBOARD[1], 3), np.float32) objp[0,:,:2] np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1, 2) # 2. 读取你拍的20张标定图放在 calib_images/ 下 images glob.glob(calib_images/*.jpg) for fname in images: img cv2.imread(fname) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, corners cv2.findChessboardCorners(gray, CHECKERBOARD, None) if ret: objpoints.append(objp) imgpoints.append(corners) # 3. 计算畸变参数并保存 ret, mtx, dist, rvecs, tvecs cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) np.savez(camera_params.npz, mtxmtx, distdist) # 关键后续detect.py会加载它运行后生成camera_params.npzdetect.py会在第82行自动加载。此后所有输入帧都会先cv2.undistort(frame, mtx, dist)再送入YOLO——框体抖动消失定位精度从 ±8cm 提升到 ±1.5cm。2.3 模型加载与首帧推理看清那行--weights参数到底指什么detect.py的启动命令长这样python detect.py --weights weights/best.pt --source 0 --imgsz 640 --conf 0.45 --line-thickness 2逐个拆解这些参数的真实含义别被注释骗了参数实际作用课设场景建议值不改的后果--weights不是模型文件名而是权重路径。best.pt必须是你训练好的、针对校园垃圾微调过的权重非官方COCO权重。项目包里weights/下的best.pt已包含 12 类校园垃圾奶茶杯、电池、快递盒、西瓜皮等若你替换成yolov5s.pt识别率直接掉到32%weights/best.pt勿删勿改所有识别结果为“unknown”log里报KeyError: names--imgsz输入YOLO的图像尺寸。不是摄像头原始分辨率。640意味着YOLO内部将帧缩放到640×640再推理。值越大识别越准但越慢值越小越快但小物体如烟头漏检率飙升640平衡点设成1280GTX1050Ti显存爆满进程被OOM killer杀掉设成320易拉罐识别为“其他垃圾”概率达67%--conf置信度阈值。0.45表示只显示模型认为“有45%以上把握”的框。不是越高越好。设成0.7电池常被漏检因反光导致置信度0.68设成0.3塑料袋褶皱会被误判为“纸类”0.45经2000帧实测校准日志里detect: 0 objects频繁出现或满屏飘红框干扰判断运行后你会看到窗口实时显示带标签的视频流右上角有FPS计数。如果第一帧就卡住立刻检查camera_params.npz是否存在且路径正确detect.py第81行weights/best.pt是否损坏用python -c import torch; print(torch.load(weights/best.pt, map_locationcpu)[model].names)验证能否读出类别名USB摄像头是否被微信/QQ占用Win下任务管理器看rundll32.exe进程。3. 后台管理闭环Django如何把“识别结果”变成“可追溯的管理动作”识别只是起点真正让老师点头说“这系统有用”的是后台能回答三个问题谁在什么时候投了什么时间、桶位ID、垃圾类别、置信度哪个桶快满了基于连续5次识别到“其他垃圾”堆积触发预警学生常投错哪类统计“电池→有害垃圾”误判为“其他垃圾”的频次TOP3项目用 Django 3.2 SQLite 实现这套逻辑没上 MySQL 是因为课设答辩时老师不会帮你装数据库服务——SQLite 就一个db.sqlite3文件复制即用。3.1 数据库结构为什么GarbageRecord表里要有is_confirmed字段打开gc_system/models.py核心表是GarbageRecordclass GarbageRecord(models.Model): bucket models.ForeignKey(Bucket, on_deletemodels.CASCADE) # 桶位外键 category models.CharField(max_length20) # 识别出的类别battery,cup,food confidence models.FloatField() # 置信度0.0~1.0 timestamp models.DateTimeField(auto_now_addTrue) # 自动记录时间 is_confirmed models.BooleanField(defaultFalse) # 关键人工审核标记 image_path models.CharField(max_length200) # 本地相对路径如 uploads/20240512/abc123.jpgis_confirmed字段的存在解决了课设中最难自圆其说的问题模型会犯错但系统不能把错误当真理上报。例如摄像头反光把矿泉水瓶识别为“金属”置信度0.52系统不立即写入“金属”记录而是存为is_confirmedFalse同时推送到管理员后台待审管理员在/admin/页面点“通过”该记录才计入统计报表点“驳回”则标记为误判并加入训练集manage.py add_to_dataset --record_id 123。注意image_path存的是相对路径不是URL。项目约定所有图片存于media/uploads/下Django 的settings.py中已配置MEDIA_ROOT os.path.join(BASE_DIR, media)。千万别手动把图片拖进static/目录——Django 会找不到。3.2 管理后台实战三分钟搭出可操作的桶位监控页Django admin 默认只显示列表但课设需要“一眼看出哪个桶告警”。修改gc_system/admin.pyfrom django.contrib import admin from .models import Bucket, GarbageRecord admin.register(Bucket) class BucketAdmin(admin.ModelAdmin): list_display [id, location, status, last_cleaned, get_fullness] # 新增get_fullness list_filter [status, location] search_fields [location] def get_fullness(self, obj): # 计算满度近2小时“其他垃圾”识别次数 / 10经验值阈值 from django.utils import timezone two_hours_ago timezone.now() - timezone.timedelta(hours2) count GarbageRecord.objects.filter( bucketobj, categoryother, timestamp__gtetwo_hours_ago ).count() return f{min(count*10, 100)}% # 满度次数×10%封顶100% get_fullness.short_description 当前满度 admin.register(GarbageRecord) class GarbageRecordAdmin(admin.ModelAdmin): list_display [id, bucket, category, confidence, timestamp, is_confirmed] list_filter [category, is_confirmed, timestamp] actions [confirm_records, reject_records] def confirm_records(self, request, queryset): queryset.update(is_confirmedTrue) confirm_records.short_description 标记为已确认 def reject_records(self, request, queryset): queryset.update(is_confirmedFalse)执行python manage.py createsuperuser创建管理员账号然后python manage.py runserver访问http://127.0.0.1:8000/admin/左侧Buckets列表里“当前满度”列会实时显示数字如70%超过80%自动标红GarbageRecords列表支持按“是否确认”筛选勾选多条后点“标记为已确认”批量生效所有操作留痕在django_admin_log表中答辩时可导出证明“人工干预可追溯”。3.3 报表导出用 Pandas 生成带图表的日报 Excel老师最爱问“上周电池回收量多少”——总不能让他自己扒数据库。项目在gc_system/views.py里内置了/report/daily/接口import pandas as pd from django.http import HttpResponse from .models import GarbageRecord def daily_report(request): # 取今日数据 today timezone.now().date() records GarbageRecord.objects.filter( timestamp__datetoday, is_confirmedTrue ).values(category, confidence, timestamp) df pd.DataFrame(list(records)) if df.empty: return HttpResponse(今日无有效记录, status404) # 统计各类别数量 summary df[category].value_counts().reset_index(namecount) summary.columns [类别, 数量] # 生成Excel含图表 response HttpResponse(content_typeapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet) response[Content-Disposition] fattachment; filenamedaily_report_{today}.xlsx with pd.ExcelWriter(response, engineopenpyxl) as writer: summary.to_excel(writer, sheet_name统计汇总, indexFalse) # 插入柱状图需openpyxl支持 from openpyxl.chart import BarChart, Reference ws writer.sheets[统计汇总] chart BarChart() chart.title 今日各品类回收量 chart.x_axis.title 垃圾类别 chart.y_axis.title 数量 data Reference(ws, min_col2, min_row1, max_rowlen(summary)1) cats Reference(ws, min_col1, min_row2, max_rowlen(summary)1) chart.add_data(data, titles_from_dataTrue) chart.set_categories(cats) ws.add_chart(chart, E5) return response访问http://127.0.0.1:8000/report/daily/浏览器直接下载 Excel打开即见柱状图。注意openpyxl已在requirements.txt中声明但 Windows 用户首次运行可能报ModuleNotFoundError: No module named openpyxl此时执行pip install openpyxl即可——这是课设部署时最常被忽略的依赖。4. 硬件联动与避坑当“识别结果”要驱动舵机开盖时哪些细节会让整套系统静默崩溃识别准确、后台漂亮但如果学生站在桶前挥挥手盖子纹丝不动——答辩分数直接砍半。项目用 Arduino Uno SG90 舵机实现“识别到可回收物自动开盖3秒”通信协议是串口COM3/COM4关键在于时序同步和状态防抖。4.1 串口通信协议为什么bOPEN\n必须带换行符detect.py在识别到category in [cup,paper,bottle]时会执行import serial ser serial.Serial(COM4, 9600, timeout1) # Win下是COM4Mac下是/dev/tty.usbmodem* ser.write(bOPEN\n) # 注意\n是必须的 time.sleep(0.1) ser.close()Arduino 端代码arduino/gc_controller.inoString command ; void setup() { Serial.begin(9600); pinMode(9, OUTPUT); // SG90接D9 myservo.attach(9); } void loop() { if (Serial.available()) { char c Serial.read(); if (c \n) { // 只有收到换行符才认为命令完整 if (command OPEN) { myservo.write(90); // 开盖 delay(3000); myservo.write(0); // 关盖 } command ; // 清空缓冲区 } else { command c; } } }现象舵机完全没反应原因detect.py发送bOPEN无\nArduino 一直等换行符command永远不等于OPEN解决严格发送bOPEN\n并在 Arduino 端加Serial.println(command)调试确认收到的是OPEN而非OPEN\rWindows换行是\r\n需在Arduino里兼容4.2 状态防抖为什么连续识别到3个奶茶杯盖子只开一次摄像头帧率23FPS同一奶茶杯在画面中停留约1.2秒意味着1秒内会触发27次OPEN命令。舵机机械响应时间约0.3秒高频指令会导致舵机啸叫发热Arduino 串口缓冲区溢出后续指令丢失盖子开合混乱学生以为系统“抽风”。项目在detect.py中加入硬件级防抖# 全局变量在文件顶部定义 last_open_time 0 OPEN_COOLDOWN 5 # 5秒内不重复开盖 # 在识别到可回收物后的逻辑里 if category in [cup,bottle,paper] and time.time() - last_open_time OPEN_COOLDOWN: ser.write(bOPEN\n) last_open_time time.time() print(f[{time.strftime(%H:%M:%S)}] 开盖指令已发送)效果即使学生把奶茶杯在桶前晃10秒盖子也只开一次3秒后自动关闭5秒冷却期后才响应下一次。4.3 电源隔离为什么舵机一转摄像头就花屏这是物理层致命坑。SG90 舵机峰值电流达500mA而 USB 摄像头仅能稳定提供500mA且需分给树莓派/Arduino。当舵机启动瞬间电压骤降摄像头供电不足输出绿屏或雪花。现象舵机转动时OpenCV 窗口卡顿、帧率暴跌、cv2.VideoCapture.read()返回False原因共用USB供电未做电源隔离解决课设可接受方案硬件舵机单独接5V 2A 电源如手机充电器Arduino 的VIN引脚只供控制信号不供电软件保底在detect.py中加入摄像头心跳检测ret, frame cap.read() if not ret: print(摄像头断连重启中...) cap.release() time.sleep(1) cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)5. 避坑指南课设答辩前必须验证的5个致命细节别等答辩当天才发现问题。以下是我带学生调试37个同类项目后总结出的必查清单。每一条都对应真实翻车现场按优先级排序5.1 现象python detect.py运行后窗口全黑无报错CPU占用100%原因cv2.VideoCapture(0)成功打开但cap.read()返回(False, None)程序陷入while True:死循环排查在detect.py的while True:循环开头加print(Frame read:, ret)若输出Frame read: False说明摄像头被占用微信/QQ/Zoom或权限问题Mac需在“系统设置→隐私→相机”中授权终端后悔药临时改cap cv2.VideoCapture(test_video.mp4)用视频文件测试逻辑确认是摄像头问题再处理。5.2 现象后台/admin/页面样式全乱CSS不加载原因Django 的静态文件未收集。DEBUGTrue时开发服务器可自动serve static但课设常被要求DEBUGFalse此时必须手动collectstatic解决python manage.py collectstatic --noinput # 生成的文件在 staticfiles/ 目录下确保 settings.py 中 STATIC_ROOT os.path.join(BASE_DIR, staticfiles)5.3 现象识别结果存入数据库但/admin/里GarbageRecord列表为空原因is_confirmedFalse的记录默认不显示在 admin 列表因list_filter中is_confirmed默认为All但初始筛选条件是is_confirmed__exact1解决进入/admin/后点击右上角“Show all”或在GarbageRecordAdmin中添加def get_queryset(self, request): qs super().get_queryset(request) return qs # 强制返回全部不加filter5.4 现象python manage.py runserver报错django.core.exceptions.ImproperlyConfigured: The SECRET_KEY setting must not be empty.原因settings.py中SECRET_KEY 为空字符串为安全项目包里故意留空解决生成新密钥python -c from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())替换settings.py第24行SECRET_KEY your-new-key-here注意密钥不能含单引号否则Django解析失败。5.5 现象Arduino 舵机只转半圈或发出“咔咔”异响原因SG90 的 0°~180° 角度范围与代码中myservo.write(90)不匹配。廉价舵机实际范围常为 20°~160°解决用myservo.write(20)和myservo.write(160)测试极限位置修改gc_controller.ino中开盖角度myservo.write(140)实测140°对应桶盖全开玄学技巧在setup()中加myservo.write(0); delay(500);让舵机上电先归零避免冷启动错位。6. 从课设到落地用“误判分析表”把答辩变成技术复盘会真正拉开差距的不是系统能不能跑而是你能不能说清它哪里不准为什么不准你怎么证明改对了我带的学生里最后拿优秀毕设的都交了一份《误判分析表》而不是“系统准确率92.3%”这种空话。6.1 构建你的误判分析表三列定义技术深度在docs/目录下新建error_analysis.xlsx按此结构填满最近100条is_confirmedFalse的记录原始图像名模型识别结果人工标注结果典型误判场景描述改进措施20240512_142301.jpgotherbattery电池反光强烈YOLO将高光区域当作“其他垃圾”纹理在训练集增加反光电池样本调整hsv_h数据增强参数20240512_150722.jpgfoodpaper快递盒折叠后形似西瓜皮颜色分布接近加入形状约束area_ratio 0.3时强制重分类为paper20240512_164115.jpgunknownbottle瓶身标签遮挡超60%特征缺失启用YOLOv5的--agnostic-nms参数提升小目标召回这张表的价值在于答辩时老师问“准确率怎么提升的”你打开表格指向第3行说“我们发现标签遮挡是主要瓶颈于是启用了agnostic-NMS并在detect.py第156行加了面积过滤逻辑”导师眼前一亮因为你在用工程思维解决问题而非调参玄学你自己收获下次训练时会主动采集“标签遮挡”场景的200张图而不是盲目刷数据量。6.2 用 Confusion Matrix 代替“准确率”汇报别再说“整体准确率92.3%”。打开utils/plot_confusion_matrix.py项目已内置运行python utils/plot_confusion_matrix.py \ --preds results/predictions.npy \ --targets results/labels.npy \ --names [battery,cup,bottle,paper,food,other]生成热力图。重点看对角线以外的高亮块如果battery → other的格子最亮说明反光问题严重如果cup → food高亮说明模型混淆了奶茶杯和剩饭容器行动项针对最亮的非对角线格子定向补充该类误判样本重训模型。6.3 给未来的自己留条“后悔药”版本快照与环境锁课设结束不是终点。三个月后你想加个语音提示功能却发现当初用的torch1.9.0已不支持新PyTorch生态best.pt权重文件没写训练参数无法复现requirements.txt里opencv-python4.5.5.64被删了现在装的是4.8。我的习惯是在README.md末尾加三行## 环境快照2024-05-12 - Python 3.8.10 - torch 1.9.0cu111 - opencv-python 4.5.5.64 - best.pt 训练参数--batch 16 --epochs 100 --data data/gc.yaml --weights yolov5s.pt并把best.pt重命名为best_v1.0_20240512.pt。这样未来任何人包括你想复现git checkout一下就能回到当时的状态。希望帮到你。本文还有配套的精品资源点击获取