1. 项目概述:基于YOLO的吸烟行为识别系统
这个项目实现了一个完整的端到端吸烟行为检测解决方案,包含从数据准备、模型训练到可视化应用的全流程。系统采用YOLOv8/YOLOv11作为核心检测算法,配合PyQt5构建用户友好的图形界面,特别适合作为计算机视觉方向的毕业设计选题。
项目亮点在于提供了1.4万张精细标注的吸烟行为数据集,这在同类研究中属于较丰富的训练资源。数据集覆盖了多种吸烟场景(室内/室外、单人/多人等)和不同拍摄角度,能有效提升模型的泛化能力。系统检测准确率在实际测试中达到89.7%,满足实时监控场景的需求。
提示:项目完整源码包含数据预处理脚本、模型训练代码和可视化界面实现,采用模块化设计方便二次开发。特别适合需要快速搭建目标检测原型系统的开发者。
2. 核心设计思路与技术选型
2.1 YOLO算法选型考量
选择YOLOv8而非YOLOv5主要基于三个技术优势:
- 更高效的骨干网络:采用CSPDarknet53替换了原来的CSPNet,在保持轻量化的同时提升了特征提取能力
- 更精确的检测头设计:使用Anchor-Free方式预测目标中心点,避免了预设anchor带来的超参数敏感问题
- 更灵活的训练配置:内置多种数据增强策略和损失函数,支持从命令行直接调整超参数
对于嵌入式部署场景,YOLOv11是更好的选择。它通过深度可分离卷积和通道剪枝技术,将模型体积压缩到YOLOv8的60%,在RK3588等边缘设备上能实现25FPS的实时检测。
2.2 PyQt5界面设计原则
可视化界面采用经典的MVC架构:
- Model层:封装YOLO检测逻辑,提供统一的预测接口
- View层:使用PyQt5的QGraphicsView实现视频流渲染,配合QLabel显示统计信息
- Controller层:处理按钮事件和线程调度,确保界面响应流畅
界面核心组件包括:
python复制class MainWindow(QMainWindow):
def __init__(self):
# 视频显示区域
self.video_label = QGraphicsView()
# 检测结果统计
self.stats_label = QLabel("检测计数: 0")
# 模型选择下拉框
self.model_combo = QComboBox()
self.model_combo.addItems(["YOLOv8s", "YOLOv11-tiny"])
# 控制按钮组
self.start_btn = QPushButton("开始检测")
3. 数据集构建与模型训练
3.1 吸烟行为数据集特点
提供的1.4万张标注数据包含以下关键特征:
- 标注格式:PASCAL VOC格式(同时提供YOLO格式转换脚本)
- 类别分布:手持香烟(62%)、吸烟动作(23%)、烟盒(15%)
- 场景覆盖:室内监控视角(40%)、室外公共场所(35%)、车载环境(25%)
- 数据增强:已应用Mosaic(30%)、MixUp(20%)、HSV调整(50%)
数据集标注示例:
code复制<annotation>
<object>
<name>smoking</name>
<bndbox>
<xmin>256</xmin>
<ymin>189</ymin>
<xmax>289</xmax>
<ymax>223</ymax>
</bndbox>
</object>
</annotation>
3.2 YOLOv8训练关键参数
训练命令示例:
bash复制yolo task=detect mode=train model=yolov8s.pt data=smoke.yaml \
epochs=100 imgsz=640 batch=16 optimizer=AdamW \
patience=10 lr0=0.001 augment=True
关键参数说明:
- 输入尺寸640×640:在精度和速度间取得平衡
- AdamW优化器:配合余弦退火学习率调度(从0.001衰减到0.0001)
- 数据增强:包括随机翻转(50%)、色彩抖动(30%)、模糊(10%)
- Early Stopping:连续10个epoch验证集mAP不提升则终止训练
训练过程监控指标:
| Epoch | mAP@0.5 | Precision | Recall | Loss |
|---|---|---|---|---|
| 20 | 0.782 | 0.85 | 0.71 | 1.23 |
| 50 | 0.843 | 0.89 | 0.79 | 0.87 |
| 100 | 0.897 | 0.92 | 0.86 | 0.65 |
4. 系统实现与核心代码
4.1 检测流水线设计
系统采用多线程架构避免界面卡顿:
- 视频采集线程:通过OpenCV的VideoCapture获取帧
- 推理线程:使用YOLO模型进行预测
- 渲染线程:将检测结果绘制到QGraphicsScene
核心检测逻辑:
python复制def detect_frame(self, frame):
# 预处理
img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = letterbox(img, new_shape=self.imgsz)[0]
# 推理
results = self.model(img, augment=False)
# 后处理
detections = []
for box in results[0].boxes:
x1, y1, x2, y2 = map(int, box.xyxy[0].tolist())
conf = float(box.conf[0])
cls = int(box.cls[0])
detections.append((x1, y1, x2-x1, y2-y1, conf, cls))
return detections
4.2 PyQt5界面交互实现
关键交互逻辑包括:
- 视频源选择:支持摄像头/RTSP/本地文件
python复制def select_source(self):
options = QFileDialog.Options()
filename, _ = QFileDialog.getOpenFileName(
self, "选择视频文件", "",
"Video Files (*.mp4 *.avi);;All Files (*)",
options=options)
if filename:
self.video_path = filename
- 实时统计显示:使用信号槽更新UI
python复制class DetectionThread(QThread):
update_signal = pyqtSignal(int, float) # 计数, FPS
def run(self):
while self.running:
# ...检测逻辑...
self.update_signal.emit(count, fps)
5. 部署优化与性能调优
5.1 模型轻量化策略
针对边缘设备的优化方案:
- 知识蒸馏:使用训练好的YOLOv8s作为教师模型指导YOLOv11训练
- 量化感知训练:在训练中模拟FP16精度,使模型适应低精度推理
- 通道剪枝:移除贡献度低的卷积通道(约减少30%参数量)
RK3588部署命令示例:
bash复制python export.py --weights best.pt --include onnx --simplify \
--dynamic --opset 12 --half
5.2 性能基准测试
不同硬件平台的推理速度对比:
| 设备 | 分辨率 | YOLOv8s(FPS) | YOLOv11-tiny(FPS) |
|---|---|---|---|
| RTX 3060 | 640×640 | 145 | 210 |
| Jetson Xavier NX | 640×640 | 38 | 62 |
| RK3588 | 640×640 | 17 | 25 |
| Raspberry Pi 4B | 320×320 | 3.2 | 5.8 |
注意:实际部署时建议使用TensorRT加速,可获得额外30-50%的性能提升。对于树莓派等低算力设备,建议将输入尺寸降至320×320并启用INT8量化。
6. 常见问题与解决方案
6.1 训练阶段问题排查
-
损失值震荡不收敛:
- 检查学习率是否过大(建议初始值1e-3到1e-4)
- 验证数据标注质量(使用labelImg工具复查样本)
- 尝试关闭Mosaic增强(设置augment=False)
-
过拟合现象:
- 增加数据增强强度(mixup=0.2, hsv_h=0.015)
- 添加Label Smoothing(设置label_smoothing=0.1)
- 提前停止训练(设置patience=15)
6.2 部署运行时问题
-
内存泄漏问题:
- 确保每次推理后释放Tensor缓存
python复制
torch.cuda.empty_cache()- 使用with语句管理视频流资源
python复制with VideoCapture(source) as cap: while True: ret, frame = cap.read() -
检测框闪烁问题:
- 实现简单的轨迹跟踪(基于IOU匹配)
python复制def track_detections(current, prev, iou_thresh=0.5): matches = [] for i, c in enumerate(current): for j, p in enumerate(prev): iou = calculate_iou(c, p) if iou > iou_thresh: matches.append((i,j)) return matches
在实际部署到监控场景时,建议设置ROI区域检测和时段过滤规则,可以降低误报率约40%。例如在办公室场景中,可以限定只有休息时间段在吸烟区出现的检测目标才会触发告警。
