
简介本资源是一套完整的YOLOv5打电话行为检测实战项目面向计算机视觉初学者与安防智能分析开发者解决日常监控场景中手机使用行为的自动识别问题。资源共165个文件包含34个核心Python脚本含训练、推理、PyQt界面逻辑、27个配置用YAML文件、26张标注图像及8张可视化结果图、4个预训练.pt模型权重、4个.ui界面设计文件以及Docker部署相关文件和训练日志等整体压缩包大小为433.91MB。已有600人学习下载适合作为行为识别入门实践案例。用户可直接运行PyQt图形界面支持图片、视频及实时摄像头检测数据集提供txtYOLO格式与xmlPASCAL VOC格式双标注便于多框架迁移配套CSV结果统计与TensorBoard日志文件有助于理解模型输出与训练过程。1. 项目概述从零到一构建一个打电话行为检测系统最近在做一个安防相关的项目客户提了个挺有意思的需求能不能在监控视频里自动识别出谁在打电话比如在加油站、仓库、考场这些禁止使用手机的场所系统能实时报警。这需求听起来很具体但真要落地涉及的东西可不少。核心就是目标检测不仅要找到人还得精准判断他手里有没有手机、手机是不是贴在耳朵边——这个典型的“打电话”姿态。市面上现成的通用检测模型比如COCO数据集上训练的YOLO能识别人和手机但很难直接判断“正在打电话”这个行为。因为“打电话”是一个更高级的、由多个目标人、手机及其空间关系手机靠近头部组合而成的行为。所以这个项目本质上是一个自定义目标的YOLO模型训练任务我们需要一个标注了“打电话的人”这个特定类别的数据集。我选择了YOLOv5作为核心检测框架。原因很简单它生态成熟、文档丰富、社区活跃从训练到部署的路径非常清晰对于快速原型开发和落地特别友好。整个项目的技术栈很明确用YOLOv5训练一个“打电话”检测模型然后利用PyQt搭建一个本地图形界面GUI方便非技术人员上传视频或调用摄像头进行实时检测和结果展示。最终我会把训练好的模型、整理好的数据集和完整的PyQt界面代码打包形成一个开箱即用的解决方案。这篇文章我就把自己从数据准备、模型训练、到界面封装的全过程包括踩过的坑和总结的经验详细记录下来。无论你是想了解YOLOv5实战还是需要解决类似的行为检测问题希望这份“流水账”都能给你提供直接的参考。2. 核心思路与方案选型为什么是YOLOv5PyQt接到“打电话检测”这个任务首先得拆解。它不是一个分类问题判断整张图有没有打电话而是一个目标检测问题需要在图中定位出“正在打电话的个体”。更进一步这是一个细粒度行为检测问题其判断依赖于对“人”和“手机”两个对象及其相对位置的联合分析。最直接的思路是训练一个端到端的检测模型直接输出“calling_person”这个类别的边界框。这就要求我们的数据集里标注框不是单独框出人和手机而是框住整个正在打电话的人通常手机区域也在框内。这种方案简单粗暴模型会自己学习“手机贴耳”这个视觉特征。另一种思路是分两步走先检测“人”和“手机”再通过后处理逻辑如计算手机框与头部关键点的距离判断是否在打电话。后者更灵活但流程复杂实时性可能受影响。考虑到项目的首要目标是准确性和简洁性我选择了端到端的单类别检测方案。框架选择上YOLOv5是当下的热门。相比更早的版本v5在易用性上做到了极致清晰的代码结构、完善的训练脚本、丰富的可视化工具TensorBoard、WB集成。更重要的是其提供的预训练模型如yolov5s.pt在COCO等大型数据集上训练过通过迁移学习我们能用在相对较小的自定义数据集上快速获得不错的精度极大减少了训练时间和数据需求。虽然YOLOv8、v10等更新版本已经发布但v5的稳定性和社区资源如各种部署教程、问题解答对于项目快速落地至关重要。为什么用PyQt做界面因为我们的用户可能是安保人员或管理人员他们不可能去操作命令行。一个可视化的窗口程序能让他们选择视频文件、开启摄像头、查看实时检测结果框和标签、以及处理报警日志。PyQt是Python下非常成熟的GUI框架功能强大界面美观且能很好地与OpenCV用于视频处理和PyTorchYOLOv5后端集成。最终我们可以用PyInstaller将整个Python项目打包成独立的.exe文件在没有Python环境的Windows电脑上也能直接运行这大大提升了交付的便利性。所以最终的技术链路确定为标注“打电话”数据集 - 使用YOLOv5框架进行迁移学习训练 - 导出最佳模型权重 - 使用PyQt5开发集成检测功能的桌面应用 - 打包成可执行文件。3. 数据集准备寻找与制造“打电话”的样本任何监督学习项目的基石都是数据。对于“打电话行为检测”公开数据集中直接可用的非常少。我们需要自己动手丰衣足食。3.1 数据来源与收集策略我的数据主要来自以下几个渠道公开数据集筛选从一些包含“人”和“手机”类别的数据集中手动筛选例如COCO、Open Images。但其中明确标注为“打电话”姿态的图片极少需要大量人工甄别效率不高。网络爬取使用搜索引擎以“person on phone call”、“mobile phone call”、“打电话”等关键词爬取相关图片。这里必须严格遵守版权和隐私法规仅用于个人研究学习且最终项目不包含任何有明确肖像权的个人图片。爬取后需进行严格的去重和清洗。模拟拍摄与视频抽帧这是高质量数据的主要来源。我请同事在不同场景办公室、走廊、室外、不同角度正面、侧面、背面、不同光照条件下模拟打电话的动作进行拍摄。同时也从一些无版权或已获授权的影视剧片段、监控演示视频中抽帧。这种方式获得的数据场景多样且标注质量最高。最终我积累了大约1500张有效图片。对于YOLOv5这样的模型在迁移学习的基础上这个量级的数据足以训练出一个在特定场景下表现良好的模型。3.2 数据标注用Roboflow与LabelImg定义“打电话”数据标注是关键环节。我采用端到端方案所以只标注一个类别calling。标注框需要完整框住正在打电话的人确保手机区域尤其是手部持握和贴近耳朵的部分被包含在内。注意标注的边界框质量直接影响模型性能。框得太紧可能漏掉部分特征如抬起的手臂框得太松会引入过多背景噪声。一个原则是框体紧贴目标外缘但确保整个“打电话姿态”的身体轮廓和手机都在框内。工具方面LabelImg和Roboflow是常见选择。LabelImg是本地工具简单直接。Roboflow是在线平台功能更强大支持团队协作、数据增强、版本管理和一键导出为YOLO格式。我选择了Roboflow因为它能显著提升数据管理的效率。标注完成后每张图片会生成一个同名的.txt文件这就是YOLO格式的标签。文件内容如下0 0.512 0.634 0.325 0.488每一行代表一个目标。格式为class_id x_center y_center width height。坐标是归一化后的除以图片宽高取值0-1。这里的class_id为0对应我们唯一的类别calling。3.3 数据增强与数据集划分为了提升模型的鲁棒性防止过拟合数据增强必不可少。Roboflow提供了丰富的增强选项我在项目中主要应用了以下几种基础增强随机水平翻转左右手打电话都要适应、小幅度的旋转±15°和剪切。色彩空间增强调整亮度、对比度、饱和度和色调模拟不同光照和摄像头条件。噪声与模糊添加高斯噪声、运动模糊增强模型对低质量监控画面的适应性。实操心得增强幅度不宜过大。过度的旋转或剪切可能导致“打电话”的姿态特征被破坏让模型学习到错误的信息。例如垂直翻转会让手机跑到头部下方这不符合现实。数据集按经典比例划分训练集Train: 验证集Val: 测试集Test 70% : 20% : 10%。划分时要确保数据分布一致比如不同场景、不同时间段的图片在三个集合中都有所体现避免测试集全是某种特定场景导致评估失真。最后通过Roboflow将数据集导出为“YOLOv5 PyTorch”格式你会得到一个包含data.yaml配置文件的文件夹结构如下dataset/ ├── train/ │ ├── images/ # 训练图片 │ └── labels/ # 训练标签 ├── val/ │ ├── images/ # 验证图片 │ └── labels/ # 验证标签 └── data.yaml # 数据集配置文件data.yaml文件内容示例# 数据集路径相对于train.py的位置 train: ../dataset/train/images val: ../dataset/val/images # 类别数量 nc: 1 # 类别名称列表 names: [calling] # 可选下载地址/说明这个文件是后续训练时指定数据源的关键。4. YOLOv5模型训练全流程解析有了高质量的数据集接下来就是训练模型。YOLOv5的官方仓库让这个过程变得相当标准化。4.1 环境搭建与依赖安装首先从GitHub克隆YOLOv5官方仓库并创建独立的Python环境推荐使用Conda或venv。git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt # 安装所有依赖requirements.txt包含了PyTorch、TorchVision、OpenCV-Python、Pandas等核心库。请根据你的CUDA版本安装对应的PyTorch以启用GPU加速。4.2 训练配置与参数调优训练的核心命令是train.py。我们需要准备一个自定义的模型配置文件和一个数据配置文件即上文的data.yaml。模型配置在yolov5/models/目录下选择基础模型架构。YOLOv5提供了s小、m中、l大、x超大等版本。权衡精度和速度我选择了yolov5s.yaml并将其复制为yolov5s_calling.yaml。修改其中的nc类别数为1。# 参数来自 yolov5s.yaml nc: 1 # 将原来的80改为1表示我们只有1个类别启动训练使用以下命令开始训练。关键参数解释如下python train.py \ --img 640 \ # 训练图片尺寸保持640平衡速度与精度 --batch 16 \ # 批次大小根据GPU显存调整11G显存可用16 --epochs 100 \ # 训练轮数通常100-300轮 --data ../dataset/data.yaml \ # 指向我们的数据配置文件 --cfg models/yolov5s_calling.yaml \ # 指向我们的模型配置文件 --weights yolov5s.pt \ # 加载预训练权重这是迁移学习的关键 --name calling_exp1 \ # 本次实验的名称用于区分不同训练 --cache \ # 缓存图片到内存或磁盘加速训练 --device 0 # 使用GPU 0如果是CPU则用 --device cpu--weights yolov5s.pt这是迁移学习的核心。它加载了在COCO上预训练的权重模型已经具备了强大的通用特征提取能力。我们在此基础上针对“打电话”这个特定任务进行微调比从零训练快得多效果也好得多。--img 640YOLOv5训练时会将图片统一缩放到这个尺寸。更大的尺寸如1280可能提升对小目标的检测精度但会显著增加计算量和内存消耗。--batch在GPU显存允许的情况下尽可能设大可以提高训练稳定性和速度。如果出现“CUDA out of memory”错误需要减小batch或--img尺寸。4.3 训练过程监控与评估训练开始后YOLOv5会在runs/train/calling_exp1/目录下生成大量有用的文件和日志weights/best.pt训练过程中在验证集上表现最好的模型权重。weights/last.pt最后一轮的模型权重。results.png关键指标曲线图包括损失box_loss, obj_loss, cls_loss和精度指标Precision, Recall, mAP0.5, mAP0.5:0.95。需要重点关注以下几个指标损失Lossbox_loss边界框回归损失、obj_loss目标置信度损失、cls_loss分类损失。训练过程中这些损失应稳步下降并最终趋于平缓。精度Precision和召回率RecallPrecision查准率指模型预测为正的样本中真正为正的比例Recall查全率指所有正样本中被模型预测出来的比例。我们希望两者都高。mAPmean Average Precision这是目标检测的核心评估指标。mAP0.5指在IoU交并比阈值为0.5时的平均精度。mAP0.5:0.95是在多个IoU阈值0.5到0.95步长0.05下的平均mAP更严格。一个训练良好的模型mAP0.5通常能达到0.9以上。如果发现指标不佳如mAP很低、损失不下降可能的原因有数据集质量差标注错误、样本太少、类别不平衡、学习率设置不当、模型容量不足或过拟合等。需要根据具体情况进行排查。4.4 模型测试与验证训练完成后使用detect.py脚本在测试集或新图片上验证模型效果python detect.py \ --weights runs/train/calling_exp1/weights/best.pt \ --source ../dataset/test/images \ # 可以是图片、视频、摄像头0 --img 640 \ --conf 0.25 \ # 置信度阈值高于此值才显示 --save-txt \ # 保存检测结果的标签文件 --save-conf # 在标签文件中保存置信度通过观察检测结果可以直观判断模型是否学会了“打电话”的特征。重点关注误检把没打电话的人框出来和漏检没检测到打电话的人的情况这些样本可以反过来补充到数据集中进行重新训练迭代优化模型。5. PyQt5图形界面开发与功能集成模型训练好了但它是“黑盒”的命令行程序。为了让最终用户能用起来必须有一个友好的界面。PyQt5完美胜任这个任务。5.1 界面布局设计与功能规划使用Qt Designer进行可视化拖拽设计然后通过pyuic5工具将.ui文件转换为.py文件。核心界面组件包括主显示区域一个QLabel控件用于实时显示视频帧和检测结果画上边界框和标签。控制面板文件选择按钮打开本地视频文件。摄像头开关按钮启用/禁用本地摄像头。模型加载按钮选择训练好的.pt权重文件。参数调节滑块实时调整置信度阈值Confidence Threshold和非极大值抑制阈值NMS IoU Threshold。这是提升交互性的关键用户可以根据场景调整检测的严格程度。开始/停止检测按钮。报警记录文本框当检测到打电话行为时记录时间戳并可以发出声音提示。状态栏显示当前FPS、检测到的目标数量等信息。5.2 核心逻辑将YOLOv5检测引擎嵌入PyQt界面的核心在于将YOLOv5的检测逻辑整合到PyQt的事件循环中同时保证界面的流畅响应。这里的关键是使用多线程。主线程UI线程负责处理用户交互和界面更新。工作线程检测线程负责运行耗时的模型推理。如果检测逻辑阻塞了UI线程界面就会卡死。具体实现步骤模型加载在界面初始化时或通过“加载模型”按钮使用PyTorch加载best.pt权重。import torch model torch.hub.load(ultralytics/yolov5, custom, pathbest.pt, devicecpu) # 或 cuda model.conf 0.25 # 默认置信度阈值 model.iou 0.45 # 默认NMS IoU阈值视频流处理使用OpenCVcv2捕获摄像头或读取视频文件。import cv2 cap cv2.VideoCapture(0) # 打开摄像头或传入视频文件路径检测与绘制在工作线程中循环读取视频帧送入模型推理得到结果。while self.running: # 检测线程运行标志 ret, frame cap.read() if not ret: break # YOLOv5推理 results model(frame, size640) # 解析结果results.pandas().xyxy[0] 包含框坐标、置信度、类别名 detections results.pandas().xyxy[0] # 在frame上绘制边界框和标签 for _, det in detections.iterrows(): x1, y1, x2, y2, conf, cls int(det[xmin]), ... cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) label f{det[name]} {conf:.2f} cv2.putText(frame, label, (x1, y1-10), ...) # 将处理后的帧BGR转换为Qt可显示的RGB格式 rgb_image cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 发送信号给主线程更新UI上的QLabel self.update_signal.emit(rgb_image)线程间通信使用PyQt的Signal和Slot机制。工作线程完成一帧处理后通过自定义信号将图像数据发送给主线程主线程的槽函数接收并更新界面显示。这样UI就不会被阻塞。参数实时调节将置信度和NMS阈值的滑块QSlider的valueChanged信号连接到模型参数的设置函数实现实时调整。self.conf_slider.valueChanged.connect(lambda v: setattr(model, conf, v/100.0))5.3 界面美化与交互优化基础的检测功能实现后还需要打磨用户体验实时性能显示在界面角落显示当前帧率FPS让用户了解系统负载。报警机制当检测到calling类别时除了在界面框出还可以在后台的QTextEdit控件中追加一条带时间戳的日志并可以调用QSound播放一个简短的警告音。结果导出添加按钮支持将当前帧或一段视频的检测结果带框图片保存到本地。线程安全退出确保点击关闭按钮时检测线程能安全退出释放摄像头资源。6. 项目打包与部署从代码到可执行文件开发完成后我们需要将整个Python项目包括依赖库、模型文件、界面代码打包成一个独立的可执行文件.exe方便在没有Python环境的电脑上部署。6.1 使用PyInstaller进行打包PyInstaller是Python项目打包的利器。首先安装它pip install pyinstaller。为我们的主界面文件例如main_window.py创建一个打包规范。最直接的方式是使用命令行pyinstaller -F -w -i icon.ico main_window.py-F打包成单个exe文件所有依赖都集成进去便于分发。-w运行时不显示命令行控制台窗口对于GUI程序。-i icon.ico为生成的exe文件设置自定义图标。然而直接打包往往因为YOLOv5、PyTorch等库的动态链接和隐式导入而失败。更可靠的方法是编写一个.spec文件。6.2 编写PyInstaller Spec文件解决依赖问题创建一个pack.spec文件手动指定隐藏的导入和资源文件# -*- mode: python ; coding: utf-8 -*- a Analysis( [main_window.py], pathex[], binaries[], datas[], # 需要额外添加数据文件如模型、图标 hiddenimports[ torch, torchvision, cv2, PIL, numpy, pandas, yaml, ultralytics.yolov5, # 关键确保yolov5的模块被包含 # 根据错误提示添加其他缺失的模块 ], hookspath[], hooksconfig{}, runtime_hooks[], excludes[], noarchiveFalse, ) pyz PYZ(a.pure) exe EXE( pyz, a.scripts, a.binaries, a.datas, [], namePhoneCallDetector, debugFalse, bootloader_ignore_signalsFalse, stripFalse, upxTrue, upx_exclude[], runtime_tmpdirNone, consoleFalse, # 对应 -w iconicon.ico, # 对应 -i disable_windowed_tracebackFalse, argv_emulationFalse, target_archNone, codesign_identityNone, entitlements_fileNone, ) coll COLLECT(...) # 如果是单文件模式(-F)则没有COLLECT部分关键步骤在datas中将模型文件best.pt、数据集配置文件data.yaml如果需要等资源文件打包进去。格式为[(source_path/best.pt, .)]表示将源文件复制到exe的同级目录。hiddenimports必须包含ultralytics.yolov5这是PyInstaller自动分析时常会漏掉的。然后使用spec文件打包pyinstaller pack.spec6.3 打包后的测试与问题排查打包成功后会在dist目录下生成PhoneCallDetector.exe。在一台没有Python和项目依赖的全新Windows电脑上进行测试是必须的。常见问题及解决方案错误缺少DLL或libiomp5md.dll通常是因为PyTorch的某些动态库没有被正确打包。尝试将Anaconda或Python环境下的相关DLL文件手动复制到exe同级目录或在spec文件的binaries部分添加。错误模型文件找不到这是因为代码中使用了相对路径。在打包版本中需要使用sys._MEIPASSPyInstaller创建的临时解压目录或绝对路径来定位资源文件。一个通用的方法是import sys, os def resource_path(relative_path): 获取资源的绝对路径。在开发环境和PyInstaller打包后都有效 if hasattr(sys, _MEIPASS): return os.path.join(sys._MEIPASS, relative_path) return os.path.join(os.path.abspath(.), relative_path) model_path resource_path(best.pt)程序启动慢单文件exe启动时需要解压所有资源到临时目录会慢一些。如果不介意文件多可以使用-D生成目录模式打包启动速度会快很多。经过反复测试和调整spec文件最终可以生成一个稳定运行的可执行程序。将exe文件、必要的配置文件如data.yaml和说明文档打包就可以交付给最终用户了。7. 常见问题与实战避坑指南在整个项目开发过程中我遇到了不少典型问题。这里总结一下希望能帮你少走弯路。7.1 模型训练相关问题1训练损失Loss不下降mAP一直为0或很低。可能原因与排查数据问题这是最常见的原因。检查数据集data.yaml中的路径是否正确打开几张训练图片和对应的标签文件确认标注框是否准确、格式是否正确归一化坐标类别ID从0开始。学习率过大过大的学习率可能导致训练震荡无法收敛。尝试使用YOLOv5默认的学习率或使用--hyp参数指定一个更小的学习率配置文件。模型与数据不匹配确认模型配置文件.yaml中的类别数nc是否与数据配置文件中的一致。预训练权重未加载确保--weights参数指向了正确的预训练模型文件如yolov5s.pt。从零开始训练--weights 需要大量数据和更长的时间。解决步骤首先用detect.py快速验证一下模型在训练集上的表现python detect.py --weights yolov5s.pt --source path/to/train/images --save-txt。如果预训练模型在训练集上都检测不出任何东西比如人那很可能是数据路径或格式问题。问题2模型过拟合训练集mAP很高验证集/测试集mAP很低。可能原因数据量太少或训练集和验证集数据分布差异太大例如训练集全是白天验证集全是黑夜。解决方案增加数据收集更多样化的数据特别是覆盖各种难点场景遮挡、光照差、侧脸、背影。加强数据增强在Roboflow或代码中启用更多样化的增强如Mosaic、MixUp、随机遮挡但要注意增强的合理性。使用正则化YOLOv5默认已经包含了一些正则化手段。可以尝试减小模型容量换用yolov5s而不是yolov5l或轻微增加--dropout率如果模型支持。早停Early Stopping监控验证集mAP当其在连续多个epoch不再提升时手动停止训练并加载best.pt。7.2 PyQt界面与集成相关问题3界面运行一段时间后卡死或无响应。根本原因UI线程被阻塞。最常见的是将耗时的检测代码直接写在按钮点击事件或主循环中。解决方案必须使用多线程。将视频捕获和模型推理放在一个独立的QThread子类中。通过pyqtSignal将处理后的图像帧发送回主线程更新UI。务必处理好线程的启动和退出避免资源泄漏。问题4打包后的exe文件运行时提示找不到模型文件或其它资源。原因代码中使用了相对路径如./best.pt但打包后文件的相对位置发生了变化。解决方案使用前面提到的resource_path()函数来获取资源的绝对路径。确保在spec文件的datas部分正确列出了所有需要打包的额外文件模型、图标、配置文件等。问题5检测速度慢FPS很低。性能瓶颈分析模型推理这是主要瓶颈。尝试使用更小的模型如yolov5n或减小推理尺寸--img 320。如果使用CPU速度会慢很多有条件务必使用GPUCUDA。图像预处理/后处理确保在GPU上进行张量运算。利用YOLOv5结果解析的向量化操作避免在Python循环中进行逐框处理。界面刷新高分辨率图像频繁转换和刷新会消耗资源。可以适当降低显示帧率例如每处理3帧图像只更新1次UI。优化建议对于实时视频流可以设置一个帧缓冲队列检测线程从队列取帧避免因模型处理速度跟不上摄像头采集速度而导致队列堆积和延迟越来越高。7.3 业务逻辑与效果优化问题6误检率高把“手放在耳边”或“拿着手机看”也识别成打电话。原因数据集中“打电话”的负样本类似姿势但不是打电话不足模型没有学会区分这些细微差别。解决方案数据驱动的优化。将这些误检的截图作为“负样本”加入到数据集中并标注为背景或者在YOLO格式中不进行标注但确保它们出现在训练集中。重新训练模型让它学习到这些是“非打电话”的样本。这是提升模型精度的最有效方法之一。问题7对于小目标或远处目标检测效果差。原因默认的输入尺寸640x640下远处的人或手机可能只占几个像素特征不明显。解决方案增加输入分辨率训练和推理时使用更大的--img参数如1280。这会显著增加计算量需要更强的GPU。修改模型结构YOLOv5的Neck和Head部分有针对不同尺度目标的检测层。可以微调模型加强对小目标的关注但这需要较深的模型知识。数据增强使用更多包含小目标的图片并在增强时避免过度缩小目标。这个项目从需求分析到最终交付涉及了AI项目落地的完整链条数据工程、模型训练、软件开发和产品打包。每一个环节都有其挑战和乐趣。最深的体会是数据质量决定模型上限工程化能力决定项目下限。一个在测试集上mAP高达95%的模型如果因为界面卡顿、打包失败或部署复杂而无法让用户用起来那它的价值就是零。因此在追求模型精度的同时一定要花同等甚至更多的精力在用户体验和工程鲁棒性上。本文还有配套的精品资源点击获取