☰
YOLOv5打电话行为检测实战:从数据集标注到PyQt界面部署
2026/10/11 20:42:51 网站建设 项目流程

简介:本资源面向计算机视觉入门与进阶开发者,提供一套完整的YOLOv5打电话行为检测方案,可用于课堂演示、安防场景原型验证或毕业设计参考。包内包含训练好的打电话识别权重与配套数据集,标注同时提供txt和xml两种格式并分目录存放,方便直接训练或迁移到其他检测任务。资源共165个文件,涵盖34个Python源码、32个编译文件、27个YAML配置、26张JPG样本图、4个pt权重、4个UI界面文件以及mp4演示视频等,压缩包约433.91MB,目录结构清晰,便于按模块查阅。项目基于PyTorch框架实现,并配有PyQt可视化界面,支持图片、视频与摄像头三种输入方式,可直观查看检测效果。目前已有604人学习下载,适合希望快速跑通打电话行为识别流程、理解数据标注与模型推理衔接的读者参考借鉴。

1. 从一通没接到的电话说起:这套 YOLOv5 打电话行为检测资源到底能干什么

去年帮一个做工地安全监管的朋友看现场视频,甲方要求识别工人有没有在作业时打电话。我第一反应是拿现成的开源权重跑一遍,结果 COCO 预训练模型里根本没有「打电话」这个类,人、手机、手三个框各检各的,逻辑拼起来误报率高得离谱。后来自己标数据、训模型、写界面,前后折腾了小两周。今天拆的这套资源,就是把这个过程打包好了:YOLOv5 打电话行为检测的完整工程,带训练好的权重、标注好的数据集,还有一个 PyQt 写的可视化界面。它解决的不是「YOLO 怎么用」这种入门问题,而是「我手上有一堆监控画面,想快速跑通打电话行为识别,不想从零标数据」这个具体诉求。适合做安防、工地、考场、加油站这类场景的算法落地同学,也适合想拿一个完整闭环项目练手的学生。资源里模型、数据、界面三件套齐全,拿到手就能推理,想改类别也能接着训。

2. 拆开这个压缩包:目录结构、权重格式与数据集标注规范

2.1 工程目录长什么样,每个文件夹负责什么

拿到资源先别急着跑detect.py,花五分钟把目录结构看清楚,后面排错能省一半时间。这类 YOLOv5 行为检测工程,常见做法是沿用 ultralytics 那套目录约定,再额外挂一个 PyQt 的界面目录。典型结构大致是这样:

phone_detection/ ├── data/ # 数据集配置与标注 │ ├── images/ │ │ ├── train/ # 训练集图片 │ │ └── val/ # 验证集图片 │ ├── labels/ │ │ ├── train/ # 训练集标签(YOLO txt 格式) │ │ └── val/ │ └── phone.yaml # 数据集描述文件 ├── models/ # 网络结构定义 │ └── yolov5s.yaml ├── weights/ │ └── best.pt # 训练好的权重 ├── utils/ # 通用工具(NMS、绘图、指标) ├── runs/ # 训练/推理输出 ├── detect.py # 命令行推理入口 ├── train.py # 训练入口 ├── requirements.txt └── ui/ # PyQt 界面 ├── main.py └── mainwindow.ui

data/是数据侧的全部家当,phone.yaml决定模型去哪找图、去哪找标签、类别名是什么。weights/best.pt是训练收敛后保存的最优权重,.pt是 PyTorch 的序列化格式,里面既存了网络参数也存了类别信息。ui/是独立的一块,通过调用detect.py里的推理函数或者直接加载模型来出结果。理解这个分层,你就知道改类别该动phone.yaml,换模型该动weights/,调界面该动ui/,互不干扰。

2.2 数据集标注格式:YOLO txt 的五个数字怎么读

这套资源的数据集是 YOLO 格式,每张图对应一个同名.txt,每行代表一个目标框,格式是class_id x_center y_center width height,后四个都是归一化到 0~1 的相对值。举个例子,一张 640×480 的图里有个打电话的人,框在左上角,标签文件里可能长这样:

0 0.312500 0.416667 0.187500 0.333333

第一个0是类别索引,对应phone.yaml里names列表的第 0 项,比如['phone_call']。后面四个数分别乘以图宽图高,就还原成像素坐标:中心点 x=200、y=200,宽 120、高 160。这里最容易翻车的是归一化基准搞错——有人拿标注工具的绝对坐标直接除以 1000,结果框全飘了。正确做法是除以图片真实的宽和高,标注工具导出时一般会自动算好,但如果你自己写脚本转换,务必确认这一点。

提示:验证标签是否规范,最快的办法是拿utils/general.py里的可视化函数把框画回原图,肉眼扫一遍,比看数字靠谱。

2.3 权重文件与类别映射:为什么换了数据集必须改 yaml

best.pt里固化了训练时的类别数量和名称。如果你拿这套权重去跑一个只有「打电话」一类的场景,没问题;但如果你想加「抽烟」这个新类,光改phone.yaml不够,还得重新训或者做微调,因为检测头的输出维度是按类别数定死的。常见做法是:先确认phone.yaml的nc(类别数)和names与权重一致,再决定是直接推理还是接着训。用下面这段代码可以快速读出权重里的类别信息,避免瞎猜:

import torch # 加载权重,map_location 保证在无 GPU 的机器上也能读 ckpt = torch.load('weights/best.pt', map_location='cpu') # 不同版本 YOLOv5 保存结构略有差异,做兼容处理 model = ckpt['model'] if 'model' in ckpt else ckpt names = model.names if hasattr(model, 'names') else ckpt.get('names') print('类别数:', len(names)) print('类别名:', names)

map_location='cpu'是为了在没有 CUDA 的机器上也能加载,不然会报找不到设备的错。ckpt里通常有model、ema、optimizer等键,推理只关心model或ema。打印出来的names如果和你phone.yaml里写的不一致,那推理结果的类别名就会张冠李戴,这是新手最常踩的坑之一。

3. 把模型跑起来:从单图推理到 PyQt 界面联调的完整链路

3.1 环境依赖与最小可跑配置

先解决环境。这套工程依赖 PyTorch、OpenCV、PyQt5 这几样,requirements.txt里一般会列全。我一般习惯用 conda 建个干净环境,避免和系统里的包打架:

conda create -n phone_det python=3.8 -y conda activate phone_det # 按自己机器的 CUDA 版本装 torch,没有 GPU 就装 CPU 版 pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu pip install -r requirements.txt

Python 3.8 是这类工程的稳妥选择,太新的版本有时会和旧版 PyQt5 冲突。--index-url那行按你实际环境换,有 GPU 就装对应 CUDA 版本的 torch。装完先跑一句python -c "import torch; print(torch.__version__)"确认没报错,再往下走。requirements 里如果有版本号锁死,别随手升级,YOLOv5 各版本 API 差异不小,升一个包可能连带一串报错。

3.2 命令行推理:detect.py 的参数怎么设

环境通了,先用命令行验证模型能不能出结果,别一上来就开界面,界面报错你分不清是模型问题还是 UI 问题。典型调用:

python detect.py \ --weights weights/best.pt \ --source data/images/val \ --img-size 640 \ --conf-thres 0.4 \ --iou-thres 0.45 \ --device cpu \ --save-txt

--weights指向训练好的权重;--source可以是单张图、文件夹、视频甚至摄像头编号0;--img-size 640是推理分辨率,要和训练时一致,否则精度会掉;--conf-thres 0.4是置信度阈值,低于它的框直接丢,打电话这种场景建议从 0.4 起调,太低误报多,太高漏检;--iou-thres 0.45控制 NMS 合并重叠框的力度;--device cpu没 GPU 时显式指定,不然会尝试调 CUDA 报错;--save-txt把结果存成标签格式,方便你回头核对。跑完去runs/detect/exp/看输出图,框画得对不对一眼就知道。

3.3 PyQt 界面怎么和推理后端对接

界面这块是很多人卡住的地方。PyQt 主线程负责刷新 UI,推理是耗时操作,如果直接在按钮回调里跑detect,界面会卡死甚至无响应。常见做法是把推理丢到QThread里,通过信号槽把结果传回主线程更新画面。核心逻辑大概这样:

from PyQt5.QtCore import QThread, pyqtSignal import cv2 import torch class DetectThread(QThread): # 定义信号,传回带框的图像 frame_ready = pyqtSignal(object) def __init__(self, model, source): super().__init__() self.model = model self.source = source self.running = True def run(self): cap = cv2.VideoCapture(self.source) while self.running and cap.isOpened(): ret, frame = cap.read() if not ret: break # 推理,实际调用工程里的 detect 函数 results = self.model(frame, size=640) annotated = results.render()[0] # 画框后的图 self.frame_ready.emit(annotated) # 发信号给主线程 cap.release() def stop(self): self.running = False

QThread子类里重写run,把读帧和推理放进去,pyqtSignal定义跨线程通信的信号。frame_ready.emit(annotated)把画好框的图发出去,主线程接到信号后setPixmap到 QLabel 上。self.running是个开关,窗口关闭时调stop()让循环退出,不然线程挂着进程退不掉。这里的关键是:所有 UI 操作只能在主线程做,子线程只管算和发信号,这是 Qt 的铁律,违反了就是随机崩溃。

注意:如果界面里要同时显示原图和结果图,别在子线程里直接操作控件,老老实实发信号。

3.4 用滑动窗口滤波压一压抖动

视频推理有个玄学问题:同一辆车、同一个人,相邻帧的框会轻微跳动,置信度也忽高忽低,界面上看着像在抽搐。常见做法是加一层滑动窗口滤波,对连续 N 帧的检测结果做平滑。思路很简单,维护一个固定长度的队列,存最近几帧的框,输出时取均值或中位数:

from collections import deque import numpy as np class BoxSmoother: def __init__(self, window=5): self.window = window self.history = deque(maxlen=window) def update(self, box): # box 格式 [x1, y1, x2, y2] self.history.append(box) if len(self.history) < self.window: return box arr = np.array(self.history) # 取中位数,比均值更抗离群点 return np.median(arr, axis=0).astype(int)

window=5表示用最近 5 帧平滑,太大响应会迟滞,太小压不住抖动,5 到 7 是常用区间。用中位数而不是均值,是因为偶尔一帧检测飘了,均值会被带偏,中位数更稳。这个滤波只对同一目标的轨迹做,多目标场景要先做简单的 IOU 匹配再分别平滑,不然框会串。加了这层之后,界面上的框明显稳当,甲方看着也舒服。

4. 避坑与排查:这套资源落地时最容易翻车的五个地方

4.1 现象:推理结果全是同一个类,或者类别名显示成数字

原因:phone.yaml里的names和权重里的类别顺序对不上,或者根本没配names,代码回退成索引显示。解决:用 2.3 那段脚本读出权重里的names,逐字对照phone.yaml改一致。顺序错了比数量错了更隐蔽,因为不报错,只是结果全错。

4.2 现象:PyQt 界面点开始后卡死,窗口拖不动

原因:推理跑在主线程,阻塞了 Qt 的事件循环。解决:按 3.3 的方式把推理放进QThread,用信号槽回传结果。如果已经用了线程还卡,检查是不是在子线程里直接调了QLabel.setText之类的 UI 方法,那是跨线程操作控件,必须改成发信号。

4.3 现象:训练 loss 不降,或者降了但验证集精度上不去

原因:学习率、batch size 和数据集规模不匹配,或者标注里有大量空标签、错标。解决:先拿几十张图过一遍可视化,确认标注没问题;学习率从 0.01 起试,batch size 按显存给,小数据集别用太大 batch。YOLOv5 的超参数在data/hyp.scratch.yaml里,改之前先备份。

4.4 现象:换到新场景,误报率飙升,把低头看手机全判成打电话

原因:训练集场景太单一,模型学到了背景捷径,比如「手靠近耳朵」这个特征在训练集里总伴随打电话,换场景就失效。解决:补标新场景的负样本,尤其是「看手机但没打电话」这类难例,重新微调。别指望一个数据集打天下,行为检测对场景敏感度很高。

4.5 现象:CPU 上推理慢到没法用,界面一帧要好几秒

原因:--img-size设太大,或者没做模型轻量化。解决:推理分辨率降到 416 甚至 320 试精度损失,或者换 yolov5s 这种小模型。如果非要 CPU 实时,考虑导出 ONNX 再用 onnxruntime 跑,通常比原生 PyTorch 快一截。GPU 部署的话,确认--device 0且 CUDA 可用。

5. 进阶:把打电话检测接到自己的业务流里,以及怎么验证它真的靠谱

资源跑通只是起点,真正落地要解决「怎么接进现有系统」和「怎么证明它稳定」。先说接入。这套工程的推理函数是纯 Python 的,最省事的做法是把它包成一个 HTTP 服务,用 FastAPI 起一个接口,业务系统传图片或视频帧过来,返回 JSON 结果。这样前端、后端、算法解耦,换模型不影响调用方。核心就是把detect里的预处理、推理、后处理抽成一个函数,输入 numpy 数组,输出框列表和类别,外面套一层路由即可。

再说验证。行为检测最怕的是「演示时好好的,上线就翻车」。我一般会做三件事:第一,准备一个独立的测试集,跟训练集不同来源、不同光照、不同角度,跑一遍看 mAP 和误报率,别只看训练曲线;第二,做长时间稳定性测试,让界面或服务连续跑几个小时,观察内存有没有缓慢上涨、帧率有没有衰减,PyQt 长期运行内存泄漏是常见问题,多半是信号槽没断开或者图像对象没释放;第三,针对业务定义明确的验收指标,比如「打电话识别准确率不低于 90%,误报每小时不超过 2 次」,拿这个去卡,而不是拿「看起来还行」去交差。

参数上还有几个可以抠的点。置信度阈值不要全局一刀切,可以按场景调,工地这种远距离小目标,阈值适当降到 0.35;考场这种近距离,可以提到 0.5 压误报。NMS 的 IOU 阈值在人群密集场景要调低,避免把相邻两个人的框合并成一个。如果发现模型对某些角度特别不敏感,别急着换模型,先看训练集里这类样本够不够,行为检测的瓶颈往往在数据分布,不在网络结构。

最后说个我自己的习惯。每次拿到一个新的行为检测权重,我不会直接信它的精度报告,而是先拿一段自己拍的、带各种干扰的真实视频跑一遍,人工数一遍漏检和误报,心里有个底再决定用不用。这套资源的价值在于它把数据、模型、界面都给你备齐了,省掉的是从零搭建的时间,但省不掉你对业务场景的理解和验证。从那以后我每次部署行为检测模型,都强制走一遍独立测试集加长稳测试,宁可上线前多花半天,也不想上线后被追着改。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询