基于YOLOv5的跌倒检测系统实战:从数据集构建到PyQt界面部署
2026/9/8 10:44:50 网站建设 项目流程

简介:面向需要行人跌倒检测落地或学习YOLOv5的开发者,资源提供YOLOv5s和YOLOv5m两套训练好的权重,基于千余张跌倒样本训练,配合PyQt界面可直接检测图片、视频和调用摄像头,兼顾算法验证与桌面应用演示。包内共2000个文件,包含1472张jpg图像、1433个xml和1432个txt标注文件、34个py脚本,以及pt权重、yaml配置、ui界面等,压缩包约198.42MB,数据与代码分层存放,便于理解和二次开发。目前已有7863人学习下载。除模型和界面外,还附带PR曲线、loss曲线等训练分析结果,以及完整数据集和多种标注格式,便于复现训练、评估效果或扩展类别。整体适合目标检测入门者、智慧安防场景开发者以及相关毕业设计参考,能帮助快速搭建可运行的行人跌倒识别演示系统。 做了差不多两个月的跌倒检测项目,终于把整套链路跑通了——YOLOv5模型精度可用、训练好的权重在手、PyQt界面能同时接摄像头和视频文件、中途还自己整理了一份标注数据集。最直接的感受是:这个课题看着不难,实际落地时坑点全藏在数据集和界面工程里,模型反而不是最大的障碍。这篇文章把我从数据处理到界面部署的完整过程、调参心得、翻车记录都写出来,给打算做行人跌倒检测毕设或者项目开发的人一个能直接照着走的参考。

我会先讲清楚这个系统的整体结构,再按数据、训练、界面、优化四条线展开,每一条都会给出具体的操作步骤和实测数据。如果你是第一次接触YOLOv5,跟着走也能复现出一套可用的跌倒检测系统。

1. 为什么跌倒检测不是普通的YOLO目标检测任务

很多人一听“行人跌倒检测”,第一反应是“这不就是目标检测吗,把跌倒的人框出来就行”。如果真这么想,后面大概率会被检测效果狠狠打脸。跌倒检测和常规行人检测有本质区别:常规检测目标是人这个静态类别,而跌倒的本质是一个动态过程——人从站立状态在极短时间内变成躺卧或蜷缩状态,中间还可能有摔倒瞬间的快速位移和肢体遮挡。

这意味着单纯框出“人”没有意义,系统必须判断的是当前这个人是否处于“跌倒后”的异常姿态。所以在数据集构建上,不能只标注person,还要单独分出跌倒状态类别。我在实际项目中采用了双类别方案:person(正常行人)和fall(跌倒状态)。fall类覆盖跌倒着地后的各种姿态,包括侧躺、仰躺、趴卧、蜷缩等,这样模型学习到的不是“动作瞬间”,而是“跌倒后的空间形态特征”。

另一个问题是跌倒导致的形变远超普通检测任务。人站着的时候宽高比大概1:3,跌倒后变成接近1:1,某些视角下甚至出现严重的自遮挡。YOLOv5的anchor机制虽然能从数据中自适应学习,但如果数据集里fall类的标注框形状过于单一,模型泛化能力就会很差。这也是我强调“数据是核心”的原因——模型结构用YOLOv5s就够,瓶颈从来不在网络层数上。

整个系统结构拆开看其实就四块:数据集(标注好的YOLO格式数据)、训练好的模型权重(YOLOv5s为主,后续可以换m/l)、推理服务模块(加载模型、预处理、后处理、逻辑判断)、PyQt可视化界面(视频显示、检测框绘制、置信度调节、日志记录)。这四块独立开发、最后再缝合,千万不要一上来就想着写一个巨型脚本把训练和界面全塞进去。

2. 数据集构建:跌倒检测效果的上限在这里决定

数据直接决定模型的天花板。我见过不少人在公开数据集上训练完直接换场景测试,结果一塌糊涂,回头就骂模型不行。实际上不是模型的问题,是数据分布和目标场景差异太大。跌倒检测的数据集问题尤其突出,因为跌倒事件的收集成本高,公开数据集的场景普遍单一。

2.1 公开数据集实测对比

我先后测试了三类公开数据:

数据集内容特点实际表现适合程度
UR Fall Detection深度相机+红外,30帧视频,40多个跌倒序列场景局限,单一室内背景,深度图对YOLO训练帮助有限中等,可作辅助
Le2i Fall Detection普通RGB视频,多视角室内视角变体多,但分辨率偏低,需要自己抽帧较适合做补充
自建数据集监控视角+手机拍摄,多种室内外场景最贴近实际部署场景强烈建议

我的建议是直接用“公开数据抽帧+自建数据补充”的混合策略。Le2i的RGB视频按每5帧抽一次,得到大约6000帧有效图片;再用手机和普通摄像头在不同室内场景(办公室、走廊、宿舍)补拍约2000帧。这里要特别注意:补拍时不要固定机位和角度,最好能模拟真实监控的顶视角、侧视角,甚至远端小目标视角。跌倒检测最终要部署到监控场景,训练数据里没有监控视角,测试时效果就一定打折。

2.2 标注规范和两类样本的平衡

标注用的是YOLO标准格式,每张图对应一个同名txt文件,每行记录一个目标:class_id x_center y_center width height,其中坐标全部归一化到0~1之间。我用LabelImg完成标注,设置自动保存,导出YOLO格式即可。

标注时有两个教训值得单独说:

第一,person类不要和fall类混淆。一个人从站立到跌落的中间过渡帧很难界定,我的处理方法是:只有身体躯干明显倾斜、关节角度显示为倒地状态时才标fall;仅仅蹲坐或弯腰不算。训练集中把站立、行走、坐姿都归为person,这样模型学习到的fall特征会更纯。

第二,平衡正负样本比例。跌倒检测项目中fall类天然比person类少得多,初始标注完fall框约占8%。后来我做了两件事缓解:一是重复采样,对仅含fall的图片做多副本增强(随机旋转+翻转+亮度抖动);二是在训练时给fall类提高loss权重,在数据配置文件的类权重组里适当上调。经过这两个处理后,fall占比提高到15%左右,模型对跌倒实例的召回率提升明显。

2.3 增强策略:模拟真实监控环境

原图直训效果一般,我增加了这样一组增强管线:Mosaic增强(YOLOv5默认开启)、随机水平翻转、±30度旋转、HSV色域扰动(h=0.015, s=0.7, v=0.4)、随机仿射变换。这套策略比较关键的是Mosaic,它把四张图拼在一起训练,等于扩大了batch多样性,尤其对fall这种形态复杂的目标帮助很大。

另外,因为我最终要部署到监控视频场景,特意给部分数据加了模糊模拟夜间亮度降低。方法很简单:对图像做高斯模糊(kernel=5),或者将亮度整体下调40%再训练一小部分epoch,这个trick不算正规,但对实际部署在低画质监控下的效果很有帮助。

3. 模型训练与调参:YOLOv5s是跌倒检测的首选基线

3.1 网络结构理解与模型选型

YOLOv5整个网络分三块:骨干CSPDarknet负责提取特征,颈部PANet负责多尺度特征融合,头部Detect输出三个尺寸的预测框(大、中、小目标)。很多教程把PANet讲得很玄乎,你只需要知道一个结论:它让模型在不同尺度上都有感知能力,这对跌倒检测尤其重要——因为部署场景里人可能很近(大目标),也可能在画面远端(小目标),多尺度能力不够就很容易漏检。

模型选型上我一开始用的YOLOv5m,理由是觉得模型大一点更保险,后来发现性价比并不高。在7500张混合数据集上训练100轮,YOLOv5m比YOLOv5s的mAP只高了0.9个百分点,但推理速度慢了近乎一半。最终我选择把YOLOv5s作为主模型,在RTX 3060上推理一张图稳定在12ms左右,在纯CPU上约180ms,同时满足实时性和硬件兼容性。如果你的目标是嵌入式设备,可以考虑YOLOv5n,精度会再掉一些但速度更快。

3.2 训练超参数实测记录

训练用的关键配置如下(完整命令可以对照YOLOv5官方仓库的train.py):

python train.py --data fall.yaml --weights yolov5s.pt \ --img 640 --batch-size 16 --epochs 120 --device 0 \ --hyp data/hyps/hyp.scratch-low.yaml

几个关键参数的选值理由:

  • img=640:默认值,对监控场景下中等大小的行人目标足够。不要盲目用1280,显存占用翻四倍,训练时间大幅拉长,而小目标增益有限。
  • batch-size=16:12GB显存刚好卡在临界点,如果显存不足就降到8,但注意同步调低学习率,否则收敛不稳定。
  • epochs=120:实测前40轮mAP快速上升,70轮开始平台期,100轮后基本稳定,120轮属于求稳。
  • optimizer: 默认SGD即可,初始lr=0.01,momentum=0.937,warmup_epochs=3.0,这些都是YOLOv5长期打磨过的稳健值,不需要动。

3.3 训练结果分析

训练收敛后的关键指标:mAP@0.5= 92.7%,mAP@0.5:0.95= 68.3%,fall类的召回率88.4%。这里要提醒一点,mAP高不代表部署效果一定好,因为跌倒检测的失败模式集中在“漏检”而不是“误检”,而mAP各类均衡加权后无法直接反映这一点。看结果一定要单独拉出fall类的混淆矩阵,确认normal person被误判为fall的比例控制在2%以内。如果误判偏高,最常见的处理是提升置信度阈值到0.45甚至0.5,并给fall类在nms阶段设置更高的conf_thres

训练时我还做了一次实验:只使用5000张公开数据训练,fall类召回率掉到72%。这说明之前提到的那2000张自采数据贡献很大。如果条件允许,一定要自己针对目标场景采集数据,这是提升精度的最直接办法。

4. PyQt界面搭建:检测模型到可交付系统的最后一公里

模型再好,没有一个能操作的可视化界面,交不了差也展示不了效果。我这里用PyQt5把检测系统封装成一个桌面应用,支持两种输入源:本地视频文件和摄像头实时画面。整体界面分为三块区域:左侧视频显示区、右侧控制面板、底部日志记录区。控制面板提供开始/暂停/停止按钮、置信度阈值滑块、检测类别选择下拉框。

4.1 多线程框架:界面卡顿的根源问题

初次写PyQt检测程序最容易犯的错误是:把推理逻辑直接写在主线程里,结果画面一运行,拖动窗口就和幻灯片一样卡。原因是YOLOv5在CPU或GPU上的推理是阻塞操作,主线程被占用后无法处理界面事件。

解决办法是把推理进程放到独立线程,通过信号与槽机制和主线程通信。我用的是QThread,推理线程的run函数里做循环读取视频帧、执行模型推理、绘制检测框,然后把渲染好的QImage通过信号发回主线程,主线程只负责把图片显示到QLabel上。伪代码逻辑是:

class DetectThread(QThread): frame_ready = pyqtSignal(QImage) def run(self): while self.running: ok, frame = self.capture.read() if not ok: break results = self.model(frame, conf=self.conf_thres) rendered = self.draw_boxes(frame, results) self.frame_ready.emit(self.cv2_to_qimage(rendered))

关键在第4步cv2_to_qimage的颜色空间转换。OpenCV默认BGR格式,Qt的QImage需要RGB,直接转换会导致画面一片蓝红颠倒。正确方式是先用cv2.cvtColor(img, cv2.COLOR_BGR2RGB),再用QImage(rgb_data, w, h, QImage.Format_RGB888)构造。这个细节耽误了我两个多小时,写在这里帮大家避坑。

4.2 检测框绘制和置信度调节

绘制检测框不要用OpenCV的画图函数,尽量在PyQt的painter里实现,否则帧率会掉。我这里保留了YOLOv5的plot结果,但后续改成了自定义绘制:根据类别区分颜色(person为绿色、fall为红色),框顶部叠加类别名和置信度数值。置信度阈值滑块直接绑定推理线程中的conf_thres,实时生效,这样展示时能直观演示不同阈值对误检/漏检的影响,答辩或演示效果很好。

4.3 视频流处理细节

视频文件的帧读取频率控制要注意,用time.sleep()控制间隔,或者用cv2.CAP_PROP_FPS接收原始帧率。摄像头场景在部分笔记本上会报权限问题,界面上的“摄像头”按钮要处理异常分支,检测不到摄像头时给出日志提示,不要直接崩溃。底部日志区用一个只读的QPlainTextEdit,记录每次检测的类别、置信度、时间戳,这个对于事后分析很有用。

5. 实测效果与踩坑记录:误检、漏检和线程问题的现场解决

5.1 误检重灾区:刚入睡的姿势被当成跌倒

整个项目过程中我最头疼的误检场景是:画面里有人直接躺在地毯上休息、或者办公椅下瘫坐下去,模型会频繁将其判为fall。这是一类典型的“姿态歧义”问题,单纯靠目标检测图像信息很难彻底解决。针对这个问题,我当时用了一个工程化技巧:连续帧投票机制——只有当fall检测结果连续出现3帧(约0.5秒)以上,才触发跌倒事件报警;单帧误检不予触发。在实时视频流检测里,这个阈值能过滤掉大量偶发误检,代价是增加约0.5秒的判定延迟,实测是值得的。

5.2 漏检问题:小目标和暗光场景

监控场景里人离摄像头较远时,目标只有几十个像素,YOLOv5s在这类小目标上的表现下滑严重。我的做法是提高输入分辨率到768,同时注意增大batch size对应的显存占用;再用第2.3节提到的降亮度增强多训练了50个epoch。小目标召回率从70%提升到83%,这个方向比换更重的模型更有效。另外,很多人忽略的预处理细节是:模型推理前标准化时,YOLOv5内部会做letterbox填充(把长边缩放到640并补灰边),如果直接用网络图片或事故视频来测试,一定要用YOLOv5官方Dataloader的逻辑做等比例缩放,不然检测框坐标会偏移。

5.3 PyQt线程崩溃和内存泄漏

多线程框架下遇到过一次比较隐蔽的崩溃:推理线程还在运行时界面窗口被关闭,程序直接异常退出。根因是子线程持有摄像头对象的引用,但主线程销毁父窗口后,QThread的run循环仍然在访问已释放的资源。解决办法是在窗口关闭事件里,先停止线程、再释放资源。具体在重写的closeEvent中设置running=False,用thread.wait()等待线程结束,再执行capture.release()。内存泄漏方面,注意QImage的构造尽量复用缓存,不要在循环里反复new大对象,否则长时间运行后内存会持续涨高,长时间演示时会很难看。

5.4 训练集和测试集重叠导致的虚高精度

最后提醒一个容易误导人的坑:如果从视频数据中抽帧,一定要先按视频序列划分训练/验证集,而不是随机打乱所有帧。我最初随机划分时验证集的mAP高达97%,但换到真实场景视频后效果并没想象中好。原因很简单——同一个视频的相邻帧几乎一样,随机划分导致验证集中的图片和训练集中的图片高度相似,评估结果虚高。按视频分组划分后,mAP回落到92.7%,这才是一个可参考的真实水平。

6. 项目运行全流程精简指引

给想直接复现的人一个最小操作路径。参照我上面的配置,依次执行:

  1. 准备数据集:Le2i抽帧 + 自采集视频抽帧,按第2章的方法标注;
  2. 按7:2:1划分训练/验证/测试集,注意处理跌倒的时候确保不同视频序列不交叉;
  3. 修改fall.yaml数据配置文件,指向数据集目录和类别名;
  4. 执行训练命令,训练完成后把runs/train/exp/weights/best.pt拿出来投入使用;
  5. 在PyQt工程中设置模型权重路径、阈值参数、数据源;
  6. 运行主程序,选择视频或摄像头进行检测。

这套流程从零到可用,在有GPU的机器上大约需要一周(包含数据标注时间),纯CPU训练建议直接租个云GPU或者加大内存等待时间。

我个人的经验是:跌倒检测项目能不能成,60%的精力要放在数据上,20%在部署工程上,真正花在模型结构上的时间反而很少。YOLOv5已经是一个非常成熟的基础设施,关键是把它用对场景——先想清楚自己的部署环境,再决定数据集怎么建,模型训练时尽量用默认参数起步、小步调参,最后通过界面化输出把整个系统打磨成可演示、可交付的状态。后续如果想把精度再往上抬,可以从两个方向继续扩展:一是引入时序信息(比如用YOLOv5提取的检测框序列接一个LSTM或者时序卷积,判断连续帧的轨迹特征),二是做关键点检测辅助判定姿态角度。这些都是在这个项目基础上自然生长的延伸路线,各位可以根据自己的应用场景选择突破点。

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

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

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

立即咨询