1. 项目概述:基于YOLOv11的智能垃圾分类系统
作为一名计算机视觉方向的毕业生,我在毕设中开发了一套基于YOLOv11的智能垃圾分类系统。这个项目源于一个现实痛点:虽然垃圾分类政策已在全国推行,但人工分类效率低下且准确率难以保证。我的系统通过深度学习技术,实现了92.5%的平均检测准确率和45FPS的实时处理速度,能够识别6大类生活垃圾。
系统最核心的创新点在于对YOLOv11算法的三项改进:
- 针对小目标检测优化了损失函数
- 设计了动态NMS阈值调整策略
- 引入了通道注意力机制
这些改进使系统在保持实时性的同时,显著提升了在复杂场景下的检测性能。下面我将从技术选型到实现细节,完整分享这个项目的开发过程。
2. 技术选型与系统架构
2.1 核心技术栈选择
选择YOLOv11作为基础框架主要基于三点考量:
- 单阶段检测器的实时性优势(相比Faster R-CNN等两阶段检测器)
- v11版本针对小目标的优化(垃圾场景中存在大量小尺寸目标)
- 官方实现的易用性和社区支持
开发环境配置如下:
bash复制# 基础环境
Python 3.8.10
PyTorch 1.12.1+cu113
CUDA 11.3
# 主要依赖库
ultralytics==8.0.0 # YOLOv11官方实现
opencv-python==4.5.5.64
PyQt5==5.15.7
numpy==1.21.6
注意:PyTorch版本需要与CUDA版本严格匹配,否则会导致GPU加速失效。建议通过官方命令安装:
pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 --extra-index-url https://download.pytorch.org/whl/cu113
2.2 系统架构设计
系统采用典型的三层架构:
code复制┌─────────────────┐
│ 用户界面层 │ PyQt5实现
├─────────────────┤
│ 业务逻辑层 │ 检测流程控制/状态管理
├─────────────────┤
│ 模型推理层 │ YOLOv11核心算法
└─────────────────┘
关键模块划分:
-
输入处理模块:支持三种输入方式
- 摄像头实时流(OpenCV VideoCapture)
- 本地视频文件(FFmpeg解码)
- 静态图片处理
-
推理加速模块:
- 使用TensorRT对模型进行量化(FP16精度)
- 多线程处理框架(生产者-消费者模式)
-
结果显示模块:
- 检测框动态绘制(OpenCV)
- 分类结果可视化(PyQt5 QLabel)
3. 核心算法实现与优化
3.1 YOLOv11改进方案
3.1.1 损失函数优化
原始YOLO损失由三部分组成:
- 分类损失(BCE)
- 定位损失(CIoU)
- 置信度损失(BCE)
针对垃圾检测场景,我做了两点改进:
python复制class ImprovedLoss(nn.Module):
def __init__(self):
super().__init__()
# 使用Focal Loss解决类别不平衡
self.cls_loss = FocalLoss(alpha=0.75, gamma=2.0)
# 对小目标增加定位损失权重
self.box_loss = CIoULoss(iou_type='giou', box_scale=5.0)
def forward(self, pred, target):
# 小目标检测增强
small_obj_mask = target[..., 4] < 32*32 # 面积小于32x32的视为小目标
small_obj_weight = 2.0 if small_obj_mask.any() else 1.0
loss = (self.cls_loss(pred_class, target_class) +
small_obj_weight * self.box_loss(pred_box, target_box))
return loss
3.1.2 动态NMS策略
传统NMS使用固定阈值(通常0.5),这在密集垃圾场景会导致:
- 高阈值:漏检相邻目标
- 低阈值:重复检测
我的解决方案是根据目标密度动态调整阈值:
python复制def dynamic_nms(boxes, scores, img_size):
# 计算目标密度 = 检测框总面积 / 图像面积
total_area = sum((x2-x1)*(y2-y1) for x1,y1,x2,y2 in boxes)
density = total_area / (img_size[0]*img_size[1])
# 动态调整阈值 [0.3, 0.7]区间
threshold = 0.7 - 0.4 * min(max(density, 0), 1)
# 执行标准NMS
keep = torchvision.ops.nms(boxes, scores, threshold)
return keep
3.2 数据处理流程
3.2.1 数据集构建
收集了来自三个来源的数据:
- 公开数据集:TrashNet(6类,2,500张)
- 自行拍摄:校园场景(3,200张)
- 网络爬取:百度图片(1,800张)
标注采用LabelImg工具,保存为YOLO格式:
code复制<object-class> <x_center> <y_center> <width> <height>
数据增强策略:
python复制transform = A.Compose([
A.HorizontalFlip(p=0.5),
A.RandomBrightnessContrast(p=0.2),
A.RandomSizedBBoxSafeCrop(640, 640, p=0.5),
A.HueSaturationValue(p=0.3),
], bbox_params=A.BboxParams(format='yolo'))
3.2.2 模型训练细节
采用两阶段训练策略:
-
预训练阶段:
- 初始化:yolov11s.pt官方权重
- 冻结骨干网络(backbone)
- 训练参数:100 epoch, lr=0.01, batch=32
-
微调阶段:
- 解冻全部层
- 启用改进损失函数
- 训练参数:50 epoch, lr=0.001, batch=16
关键训练命令:
bash复制python train.py --data trash.yaml --cfg yolov11s.yaml --weights yolov11s.pt \
--batch-size 32 --epochs 100 --img-size 640 --device 0
4. 系统实现与性能优化
4.1 PyQt5界面开发
主界面采用多窗口设计:
python复制class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setup_ui()
def setup_ui(self):
# 中央部件
central_widget = QWidget()
self.setCentralWidget(central_widget)
# 主布局
main_layout = QHBoxLayout()
central_widget.setLayout(main_layout)
# 左侧图像显示区
self.image_label = QLabel()
self.image_label.setAlignment(Qt.AlignCenter)
main_layout.addWidget(self.image_label, 70)
# 右侧控制面板
control_panel = QVBoxLayout()
main_layout.addLayout(control_panel, 30)
# 模式选择按钮组
self.mode_group = QButtonGroup()
for i, mode in enumerate(['图片', '视频', '摄像头']):
btn = QRadioButton(mode)
self.mode_group.addButton(btn, i)
control_panel.addWidget(btn)
4.2 多线程处理框架
为避免界面卡顿,采用生产者-消费者模式:
python复制class DetectorThread(QThread):
result_ready = pyqtSignal(np.ndarray)
def __init__(self, model_path):
super().__init__()
self.model = YOLO(model_path)
self.queue = Queue(maxsize=3)
def run(self):
while True:
frame = self.queue.get()
if frame is None: # 终止信号
break
results = self.model(frame)
self.result_ready.emit(results.render()[0])
4.3 TensorRT加速
将PyTorch模型转换为TensorRT引擎:
python复制# 转换脚本
from torch2trt import torch2trt
model = YOLO('best.pt').model.eval().cuda()
x = torch.randn(1, 3, 640, 640).cuda()
model_trt = torch2trt(model, [x], fp16_mode=True)
torch.save(model_trt.state_dict(), 'best_trt.pth')
实测加速效果:
| 设备 | 原始FPS | TRT加速后FPS | 提升 |
|---|---|---|---|
| RTX 3060 | 38 | 62 | 63% |
| Jetson Xavier | 12 | 21 | 75% |
5. 常见问题与解决方案
5.1 小目标检测效果差
现象:易漏检小尺寸垃圾(如瓶盖、烟头)
解决方案:
-
数据层面:
- 增加小目标样本比例
- 使用马赛克增强(mosaic augmentation)
-
模型层面:
- 减小下采样倍��(从32x改为16x)
- 添加高分辨率检测头
python复制# 模型配置yaml修改
head:
- [15, 18, 21] # 原P3-P5
- [9, 12, 15] # 新增P2层(高分辨率)
5.2 类别混淆问题
现象:易混淆相似类别(如塑料瓶与玻璃瓶)
改进措施:
-
特征工程:
- 在neck部分添加CBAM注意力模块
python复制class CBAM(nn.Module): def __init__(self, channels): super().__init__() self.ca = ChannelAttention(channels) self.sa = SpatialAttention() def forward(self, x): x = self.ca(x) * x x = self.sa(x) * x return x -
后处理优化:
- 添加材质分析分支(基于表面反光特征)
5.3 实时性优化技巧
-
输入分辨率调整:
- 默认640x640,根据设备性能动态调整
python复制def get_optimal_size(device_type): if device_type == 'high_end': return 640 elif device_type == 'mobile': return 320 else: return 480 -
帧采样策略:
- 对视频流每2帧处理1帧
- 运动目标检测补偿
-
模型剪枝:
- 移除冗余卷积层
- 通道数缩减20%
6. 项目部署与测试
6.1 跨平台打包
使用PyInstaller生成可执行文件:
bash复制pyinstaller --onefile --windowed --add-data "best.pt;." \
--hidden-import torch --hidden-import ultralytics \
main.py
打包注意事项:
- 模型文件需手动包含(通过--add-data)
- 需要隐藏导入的依赖项
- 建议在纯净虚拟环境中打包
6.2 性能测试结果
测试环境:
- CPU: Intel i7-11800H
- GPU: RTX 3060 Laptop
- RAM: 32GB
指标对比:
| 方法 | mAP@0.5 | FPS | 显存占用 |
|---|---|---|---|
| Faster R-CNN | 89.2% | 12 | 4.2GB |
| YOLOv5s | 90.1% | 35 | 2.1GB |
| 本系统 | 92.5% | 45 | 2.3GB |
6.3 实际应用案例
系统已在校园垃圾分类站试运行两周,统计结果:
- 平均识别准确率:91.3%
- 峰值处理能力:120人/小时
- 人工干预率:<5%
反馈改进:
- 增加语音提示功能
- 优化雨天环境下的识别鲁棒性
- 添加垃圾分类知识问答模块
这个项目从构思到实现历时4个月,期间经历了三次大的架构调整。最大的收获是认识到工程落地与理论研究的差异——在实际部署中,需要考虑的远不止算法精度,还有系统稳定性、用户体验、维护成本等诸多因素。建议后续开发者可以在以下方向继续探索:
- 多模态融合(加入重量、材质传感器)
- 增量学习(适应新类别)
- 边缘计算优化(Jetson平台深度适配)
