基于YOLOv8的吸烟行为识别系统:从算法原理到工程实践

基于YOLOv8的吸烟行为识别系统:从算法原理到工程实践
在实际的公共安全监控和智能安防场景中特定行为的自动识别检测系统正发挥着越来越重要的作用。基于深度学习的吸烟行为识别系统能够有效辅助公共场所的禁烟管理通过实时视频分析自动检测吸烟行为减少人工巡检成本。本文将详细介绍如何基于YOLOv8算法构建一个完整的吸烟识别检测系统涵盖从环境配置、数据集准备、模型训练到UI界面集成的全流程实现。1. 理解YOLOv8在行为识别中的核心优势YOLOv8作为YOLO系列的最新版本在目标检测的准确性和速度平衡上达到了新的高度。对于吸烟识别这种需要实时性的应用场景YOLOv8的Anchor-free设计和改进的损失函数使其在小目标检测和复杂背景下的表现尤为出色。1.1 YOLOv8架构的核心改进YOLOv8采用CSPDarknet53作为骨干网络结合PANet进行多尺度特征融合在保持检测速度的同时显著提升了小目标检测能力。与早期版本相比YOLOv8的主要改进包括Anchor-free设计摒弃了预设anchor框简化了训练流程减少了超参数调优的复杂性DFL损失函数使用Distribution Focal Loss更好地处理类别不平衡问题SPPF模块增强多尺度特征提取能力提升不同尺度目标的检测效果1.2 吸烟识别任务的技术挑战吸烟行为识别相比普通目标检测面临更多挑战吸烟动作的多样性和短暂性香烟目标较小容易与类似形状物体混淆复杂背景下的干扰因素较多需要区分手持香烟、吸烟动作等不同状态2. 环境配置与依赖安装构建完整的吸烟识别系统需要准备相应的开发环境和依赖库。2.1 Python环境配置推荐使用Python 3.8-3.10版本过新或过旧的版本可能导致依赖兼容性问题。# 创建虚拟环境 conda create -n smoking_detection python3.9 conda activate smoking_detection # 安装核心依赖 pip install torch1.13.1cu117 torchvision0.14.1cu117 -f https://download.pytorch.org/whl/torch_stable.html pip install ultralytics8.0.0 pip install opencv-python4.7.0.72 pip install PySide66.4.22.2 项目结构规划合理的项目结构有助于代码管理和后续维护smoking_detection/ ├── datasets/ # 数据集目录 │ └── smoking/ # 吸烟检测数据集 │ ├── images/ # 图像文件 │ │ ├── train/ # 训练集 │ │ ├── val/ # 验证集 │ │ └── test/ # 测试集 │ └── labels/ # 标注文件 │ ├── train/ │ ├── val/ │ └── test/ ├── weights/ # 模型权重文件 │ ├── yolov8n.pt # 预训练权重 │ └── best.pt # 训练得到的最佳权重 ├── utils/ # 工具函数 │ ├── data_loader.py # 数据加载器 │ ├── visualization.py # 可视化工具 │ └── metrics.py # 评估指标 ├── models/ # 模型定义 │ └── yolov8_detector.py # YOLOv8检测器封装 ├── ui/ # 界面相关 │ ├── main_window.py # 主窗口 │ └── login_dialog.py # 登录对话框 ├── config/ # 配置文件 │ └── default.yaml # 默认配置 └── train.py # 训练脚本3. 吸烟检测数据集准备与处理高质量的数据集是模型性能的基础吸烟检测数据集需要包含多样化的吸烟场景和动作。3.1 数据集收集与标注吸烟检测数据集应包含以下特征不同光照条件下的吸烟场景各种角度和距离的吸烟动作多人同时出现的复杂场景手持香烟、点烟、吸烟等不同状态使用LabelImg或CVAT等工具进行标注标注格式采用YOLO格式# YOLO标注格式示例 class_id x_center y_center width height 0 0.455 0.323 0.125 0.0893.2 数据集配置文件创建数据集配置文件smoking.yaml# smoking.yaml path: /path/to/smoking_detection/datasets/smoking train: images/train val: images/val test: images/test nc: 2 # 类别数量 names: [hand_with_cigarette, smoking_action] # 类别名称 # 可选的数据增强配置 augmentations: hsv_h: 0.015 hsv_s: 0.7 hsv_v: 0.4 degrees: 0.0 translate: 0.1 scale: 0.5 shear: 0.0 perspective: 0.0 flipud: 0.0 fliplr: 0.53.3 数据预处理与增强针对吸烟检测任务的特点设计专门的数据增强策略import albumentations as A from albumentations.pytorch import ToTensorV2 def get_train_transforms(image_size640): return A.Compose([ A.RandomResizedCrop(image_size, image_size, scale(0.8, 1.0)), A.HorizontalFlip(p0.5), A.RandomBrightnessContrast(p0.2), A.HueSaturationValue(p0.2), A.GaussianBlur(blur_limit3, p0.1), A.CoarseDropout(max_holes8, max_height32, max_width32, p0.2), A.Normalize(mean[0, 0, 0], std[1, 1, 1]), ToTensorV2() ], bbox_paramsA.BboxParams(formatyolo, label_fields[class_labels])) def get_val_transforms(image_size640): return A.Compose([ A.Resize(image_size, image_size), A.Normalize(mean[0, 0, 0], std[1, 1, 1]), ToTensorV2() ], bbox_paramsA.BboxParams(formatyolo, label_fields[class_labels]))4. YOLOv8模型训练与优化基于准备好的数据集进行模型训练并针对吸烟检测任务进行优化。4.1 模型训练配置创建训练脚本train.pyfrom ultralytics import YOLO import yaml import os def train_smoking_detector(): # 加载预训练模型 model YOLO(yolov8n.pt) # 训练配置 training_config { data: datasets/smoking/smoking.yaml, epochs: 100, imgsz: 640, batch: 16, workers: 4, device: 0, # 使用GPU训练 patience: 10, # 早停耐心值 save: True, exist_ok: True, pretrained: True, optimizer: auto, verbose: True, seed: 42, deterministic: True, single_cls: False, rect: False, cos_lr: True, # 使用余弦学习率调度 close_mosaic: 10, # 最后10个epoch关闭mosaic增强 resume: False } # 开始训练 results model.train(**training_config) # 验证模型性能 metrics model.val() print(fmAP50-95: {metrics.box.map:.4f}) print(fmAP50: {metrics.box.map50:.4f}) print(fmAP75: {metrics.box.map75:.4f}) return model, results if __name__ __main__: model, results train_smoking_detector()4.2 训练过程监控训练过程中需要关注的关键指标import matplotlib.pyplot as plt def plot_training_results(results_path): 绘制训练结果曲线 results {} # 从训练日志中加载结果数据 fig, axes plt.subplots(2, 2, figsize(15, 10)) # 损失函数曲线 axes[0, 0].plot(results[train/box_loss], labelTrain Box Loss) axes[0, 0].plot(results[val/box_loss], labelVal Box Loss) axes[0, 0].set_title(Box Loss) axes[0, 0].legend() # 准确率曲线 axes[0, 1].plot(results[metrics/precision], labelPrecision) axes[0, 1].plot(results[metrics/recall], labelRecall) axes[0, 1].set_title(Precision Recall) axes[0, 1].legend() # mAP曲线 axes[1, 0].plot(results[metrics/mAP_0.5], labelmAP0.5) axes[1, 0].plot(results[metrics/mAP_0.5:0.95], labelmAP0.5:0.95) axes[1, 0].set_title(mAP Metrics) axes[1, 0].legend() # 学习率曲线 axes[1, 1].plot(results[lr/pg0], labelLearning Rate) axes[1, 1].set_title(Learning Rate) axes[1, 1].legend() plt.tight_layout() plt.savefig(training_results.png, dpi300, bbox_inchestight) plt.show()4.3 模型性能优化策略针对吸烟检测任务的特殊需求可以采用以下优化策略def optimize_model_for_smoking_detection(model_path): 针对吸烟检测优化模型 model YOLO(model_path) # 导出为不同格式以优化推理速度 model.export(formatonnx, simplifyTrue, dynamicFalse) model.export(formatengine, halfTrue) # TensorRT加速 # 模型剪枝和量化可选 # 需要额外的模型优化工具 return model # 超参数搜索优化 def hyperparameter_tuning(): 超参数自动搜索 param_grid { lr0: [0.01, 0.001, 0.0001], lrf: [0.01, 0.1, 0.2], momentum: [0.9, 0.95, 0.98], weight_decay: [0.0001, 0.0005, 0.001], warmup_epochs: [1, 3, 5], warmup_momentum: [0.5, 0.8, 0.9] } # 使用optuna或类似的超参数优化库 # 进行自动超参数搜索5. 吸烟检测系统UI界面开发基于PySide6开发用户友好的图形界面集成检测功能和结果展示。5.1 主界面设计from PySide6.QtWidgets import (QMainWindow, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QComboBox, QSlider, QGroupBox, QFileDialog, QMessageBox) from PySide6.QtCore import Qt, QTimer, Signal from PySide6.QtGui import QImage, QPixmap, QPalette, QColor import cv2 import numpy as np class SmokingDetectionUI(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle(吸烟行为检测系统) self.setGeometry(100, 100, 1200, 800) # 初始化模型和摄像头 self.model None self.cap None self.timer QTimer() self.is_detecting False self.init_ui() self.load_model() def init_ui(self): 初始化用户界面 central_widget QWidget() self.setCentralWidget(central_widget) main_layout QHBoxLayout() central_widget.setLayout(main_layout) # 左侧控制面板 control_panel self.create_control_panel() main_layout.addWidget(control_panel, 1) # 右侧视频显示区域 video_panel self.create_video_panel() main_layout.addWidget(video_panel, 3) def create_control_panel(self): 创建控制面板 panel QGroupBox(检测控制) layout QVBoxLayout() # 模型选择 model_layout QHBoxLayout() model_layout.addWidget(QLabel(检测模型:)) self.model_combo QComboBox() self.model_combo.addItems([YOLOv8n, YOLOv8s, YOLOv8m, YOLOv8l]) model_layout.addWidget(self.model_combo) layout.addLayout(model_layout) # 置信度阈值控制 conf_layout QVBoxLayout() conf_layout.addWidget(QLabel(置信度阈值:)) self.conf_slider QSlider(Qt.Horizontal) self.conf_slider.setRange(10, 90) self.conf_slider.setValue(50) self.conf_label QLabel(0.5) conf_layout.addWidget(self.conf_slider) conf_layout.addWidget(self.conf_label) layout.addLayout(conf_layout) # 功能按钮 self.camera_btn QPushButton(开启摄像头) self.video_btn QPushButton(打开视频文件) self.image_btn QPushButton(打开图片文件) self.stop_btn QPushButton(停止检测) layout.addWidget(self.camera_btn) layout.addWidget(self.video_btn) layout.addWidget(self.image_btn) layout.addWidget(self.stop_btn) # 统计信息 stats_group QGroupBox(检测统计) stats_layout QVBoxLayout() self.smoking_count_label QLabel(吸烟行为检测: 0) self.total_detection_label QLabel(总检测次数: 0) stats_layout.addWidget(self.smoking_count_label) stats_layout.addWidget(self.total_detection_label) stats_group.setLayout(stats_layout) layout.addWidget(stats_group) panel.setLayout(layout) return panel def create_video_panel(self): 创建视频显示面板 panel QGroupBox(实时检测画面) layout QVBoxLayout() self.video_label QLabel() self.video_label.setAlignment(Qt.AlignCenter) self.video_label.setMinimumSize(640, 480) self.video_label.setStyleSheet(border: 1px solid gray;) layout.addWidget(self.video_label) panel.setLayout(layout) return panel5.2 检测功能实现def load_model(self): 加载YOLOv8模型 try: from ultralytics import YOLO model_name self.model_combo.currentText().lower() self.model YOLO(fweights/{model_name}.pt) QMessageBox.information(self, 成功, 模型加载成功) except Exception as e: QMessageBox.critical(self, 错误, f模型加载失败: {str(e)}) def start_camera_detection(self): 开始摄像头检测 self.cap cv2.VideoCapture(0) if not self.cap.isOpened(): QMessageBox.warning(self, 警告, 无法打开摄像头) return self.is_detecting True self.timer.timeout.connect(self.update_frame) self.timer.start(30) # 30ms更新一帧 def update_frame(self): 更新视频帧并进行检测 ret, frame self.cap.read() if not ret: return # 进行目标检测 results self.model(frame, confself.conf_slider.value()/100) # 绘制检测结果 annotated_frame results[0].plot() # 更新统计信息 self.update_statistics(results[0]) # 显示处理后的帧 self.display_image(annotated_frame) def display_image(self, image): 在QLabel中显示图像 image cv2.cvtColor(image, cv2.COLOR_BGR2RGB) h, w, ch image.shape bytes_per_line ch * w qt_image QImage(image.data, w, h, bytes_per_line, QImage.Format_RGB888) pixmap QPixmap.fromImage(qt_image) self.video_label.setPixmap(pixmap.scaled( self.video_label.width(), self.video_label.height(), Qt.KeepAspectRatio )) def update_statistics(self, results): 更新检测统计信息 smoking_count len([box for box in results.boxes if box.cls 1]) # 假设类别1是吸烟动作 total_count len(results.boxes) if results.boxes is not None else 0 self.smoking_count_label.setText(f吸烟行为检测: {smoking_count}) self.total_detection_label.setText(f总检测次数: {total_count})6. 系统集成与功能测试将各个模块整合成完整的系统并进行全面的功能测试。6.1 系统配置管理创建配置文件管理类import yaml from dataclasses import dataclass from typing import Dict, Any dataclass class SystemConfig: model_path: str weights/best.pt camera_index: int 0 detection_confidence: float 0.5 output_path: str output save_detections: bool True alert_enabled: bool True alert_threshold: int 1 classmethod def load_from_yaml(cls, filepath: str): with open(filepath, r) as f: data yaml.safe_load(f) return cls(**data) def save_to_yaml(self, filepath: str): with open(filepath, w) as f: yaml.safe_dump(self.__dict__, f) class ConfigManager: def __init__(self, config_pathconfig/system.yaml): self.config_path config_path self.config self.load_config() def load_config(self): try: return SystemConfig.load_from_yaml(self.config_path) except FileNotFoundError: # 创建默认配置 default_config SystemConfig() default_config.save_to_yaml(self.config_path) return default_config def update_config(self, **kwargs): for key, value in kwargs.items(): if hasattr(self.config, key): setattr(self.config, key, value) self.config.save_to_yaml(self.config_path)6.2 系统主程序入口import sys import logging from PySide6.QtWidgets import QApplication def setup_logging(): 配置日志系统 logging.basicConfig( levellogging.INFO, format%(asctime)s - %(name)s - %(levelname)s - %(message)s, handlers[ logging.FileHandler(smoking_detection.log), logging.StreamHandler(sys.stdout) ] ) def main(): 主程序入口 setup_logging() # 检查必要的文件和目录 required_dirs [weights, output, logs] for dir_name in required_dirs: os.makedirs(dir_name, exist_okTrue) # 创建Qt应用 app QApplication(sys.argv) app.setApplicationName(吸烟行为检测系统) app.setApplicationVersion(1.0.0) # 创建主窗口 from ui.main_window import SmokingDetectionUI window SmokingDetectionUI() window.show() # 运行应用 try: sys.exit(app.exec()) except Exception as e: logging.error(f应用程序异常退出: {e}) QMessageBox.critical(None, 错误, f应用程序异常: {e}) if __name__ __main__: main()7. 性能优化与生产环境部署将开发完成的系统优化后部署到生产环境。7.1 推理性能优化import time from contextlib import contextmanager class PerformanceOptimizer: def __init__(self, model): self.model model self.inference_times [] contextmanager def track_inference_time(self): start_time time.time() yield end_time time.time() self.inference_times.append(end_time - start_time) def get_performance_stats(self): if not self.inference_times: return None times np.array(self.inference_times) return { mean_inference_time: np.mean(times), std_inference_time: np.std(times), fps: 1 / np.mean(times), total_inferences: len(times) } def optimize_for_production(self): 生产环境优化 # 模型量化 self.model self.model.quantize() # 启用半精度推理 self.model self.model.half() # 预热模型 self.warmup_model() return self.model def warmup_model(self, warmup_iters100): 模型预热 dummy_input np.random.randn(1, 3, 640, 640).astype(np.float32) for _ in range(warmup_iters): _ self.model(dummy_input)7.2 生产环境配置检查清单部署前需要检查的项目检查项目要求检查方法模型文件完整性权重文件存在且可加载尝试加载模型并验证输出依赖版本兼容性所有依赖版本匹配使用requirements.txt验证硬件资源充足GPU内存≥4GB系统内存≥8GB检查nvidia-smi和free -h磁盘空间剩余空间≥10GBdf -h检查磁盘使用情况摄像头权限应用程序有摄像头访问权限测试摄像头能否正常打开网络连接需要时可访问外部服务ping测试关键域名日志配置日志文件可写入尝试创建日志文件输出目录权限可保存检测结果尝试在输出目录创建文件7.3 系统监控与维护创建系统监控脚本import psutil import GPUtil from datetime import datetime class SystemMonitor: def __init__(self, log_interval60): self.log_interval log_interval self.monitoring False def start_monitoring(self): self.monitoring True self.monitor_loop() def stop_monitoring(self): self.monitoring False def get_system_stats(self): 获取系统统计信息 # CPU使用率 cpu_percent psutil.cpu_percent(interval1) # 内存使用 memory psutil.virtual_memory() # GPU使用率如果可用 gpus GPUtil.getGPUs() gpu_info [] for gpu in gpus: gpu_info.append({ name: gpu.name, load: gpu.load * 100, memory_used: gpu.memoryUsed, memory_total: gpu.memoryTotal }) # 磁盘使用 disk psutil.disk_usage(/) return { timestamp: datetime.now(), cpu_percent: cpu_percent, memory_percent: memory.percent, memory_used_gb: memory.used / (1024**3), memory_total_gb: memory.total / (1024**3), gpu_info: gpu_info, disk_percent: disk.percent, disk_free_gb: disk.free / (1024**3) } def monitor_loop(self): 监控循环 while self.monitoring: stats self.get_system_stats() self.log_stats(stats) time.sleep(self.log_interval) def log_stats(self, stats): 记录统计信息 log_message fSystem Stats - CPU: {stats[cpu_percent]}% | Memory: {stats[memory_percent]}% if stats[gpu_info]: gpu_loads [f{gpu[name]}: {gpu[load]:.1f}% for gpu in stats[gpu_info]] log_message f | GPU: {, .join(gpu_loads)} logging.info(log_message) # 检查资源使用是否过高 if stats[cpu_percent] 90 or stats[memory_percent] 90: logging.warning(系统资源使用过高可能需要优化)8. 常见问题排查与解决方案在实际部署和使用过程中可能遇到的问题及解决方法。8.1 模型加载与推理问题问题现象可能原因解决方案模型加载失败权重文件损坏或路径错误检查文件完整性重新下载权重文件推理速度过慢未使用GPU或模型过大确认CUDA可用尝试使用较小模型内存占用过高批处理大小过大减小batch size使用梯度累积检测结果不准确训练数据不足或质量差增加训练数据改进数据增强8.2 界面与交互问题class ProblemSolver: staticmethod def handle_camera_issues(): 处理摄像头相关问题 solutions { 摄像头无法打开: [ 检查摄像头连接是否正常, 确认没有其他程序占用摄像头, 尝试不同的摄像头索引, 检查系统摄像头权限设置 ], 画面卡顿或延迟: [ 降低检测帧率, 减小输入图像分辨率, 使用更轻量的模型, 检查系统资源使用情况 ], 检测框显示异常: [ 检查OpenCV版本兼容性, 验证图像通道顺序(BGR/RGB), 检查坐标转换逻辑, 更新图形驱动 ] } return solutions staticmethod def performance_troubleshooting(): 性能问题排查指南 checklist [ 确认使用GPU进行推理torch.cuda.is_available(), 检查模型是否处于评估模式model.eval(), 验证输入图像尺寸是否符合模型要求, 检查是否有内存泄漏监控内存使用趋势, 尝试使用TorchScript或ONNX优化模型 ] return checklist8.3 数据与训练问题训练过程中的常见问题及解决方法def analyze_training_issues(metrics_log): 分析训练过程问题 issues [] # 检查损失曲线 if metrics_log[train_loss][-1] metrics_log[train_loss][0]: issues.append(训练损失没有下降可能学习率过高或数据有问题) if metrics_log[val_loss][-1] metrics_log[train_loss][-1] * 1.5: issues.append(验证损失明显高于训练损失可能存在过拟合) # 检查准确率指标 if metrics_log[precision][-1] 0.5: issues.append(精确率过低可能需要调整置信度阈值或改进数据质量) if metrics_log[recall][-1] 0.5: issues.append(召回率过低模型可能漏检较多目标) return issues def training_solutions(issues): 针对训练问题的解决方案 solutions { 过拟合: [ 增加数据增强强度, 添加正则化Dropout、权重衰减, 早停Early Stopping, 使用更简单的模型架构 ], 欠拟合: [ 增加训练轮数, 提高模型复杂度, 减小正则化强度, 改进特征工程 ], 梯度爆炸: [ 梯度裁剪Gradient Clipping, 减小学习率, 使用梯度累积, 检查数据预处理 ] } recommended_solutions [] for issue in issues: if issue in solutions: recommended_solutions.extend(solutions[issue]) return list(set(recommended_solutions)) # 去重本文详细介绍了基于YOLOv8的吸烟识别检测系统的完整实现流程从环境配置、数据准备、模型训练到系统集成和部署优化。实际项目中还需要根据具体场景调整参数和优化策略特别是要考虑不同监控环境下的光照条件、摄像头角度等因素对检测效果的影响。建议在正式部署前进行充分的测试和验证确保系统在实际环境中的稳定性和准确性。