基于YOLO26与PyQt的老年人跌倒检测系统开发实战
2026/8/27 23:54:53 网站建设 项目流程

简介:目标检测是计算机视觉中最基础也最具工程落地价值的方向之一,其核心任务是在图像或视频中定位并分类目标。随着边缘计算和本地化部署的普及,基于轻量级模型构建实时检测系统已成为智慧养老、家庭安防等场景的常见需求。本文从目标检测的基本原理出发,介绍如何利用YOLO26模型和PyQt框架,从数据标注、模型训练到界面开发与打包部署,完整实现一套老年人跌倒检测系统。文章重点探讨了模型选型、训练参数调优、ONNX推理加速、报警防抖逻辑以及PyInstaller打包常见坑,并给出低光环境下的优化方案。无论是毕业设计还是实际工程,都能从中获得一套可复用的落地思路。开头

做老年人跌倒检测这个项目,很大程度上是因为一个挺现实的痛点:家里有老人独居,白天大家上班、上课,最怕的就是老人在家摔了没人知道。市面上的养老监控产品要么贵得离谱,要么识别率让人不敢恭维,而且很多还是云端方案,视频数据往上传本身就让人不放心。上个月我花了一周多时间,基于YOLO26和PyQt把整套跌倒检测系统跑通了,包含了数据集、训练脚本、训练好的权重模型,以及一个完整的桌面监控界面。这篇博文就把整个过程中的方案选型、数据集处理、模型训练、界面开发、打包部署和踩坑记录全部拆开讲一遍。

这套东西适合谁?不只是做毕设的同学,如果你是做智慧养老、家庭安防、工厂安全监控这类方向的开发者,或者手上有一批摄像头数据想自己做本地化检测,都可以参考。我不打算只贴代码和命令,更想把每一步为什么这样做、有哪些坑替你先踩一遍讲清楚。

1. 系统整体架构与核心需求拆解

1.1 系统组成与关键模块

在动手写代码之前,我先把这个系统拆成了四个核心部分。

第一部分是数据层。跌倒检测本质上是目标检测任务,模型要能从视频帧里找到人,并且判断人的姿态是“正常站立/行走/坐下”还是“跌倒”。原始数据我整理了一套包含跌倒和日常活动两种类别的图片集,带标注,按YOLO格式组织,train和val按8:2划分,后面会有更详细的说明。数据层的质量直接决定模型效果,这一步不能偷懒。

第二部分是模型层。检测部分我选的是YOLO26系列。YOLO26是YOLO系列的最新演进版本,相比前代在检测头和训练策略上做了不少调整,后面我会展开说。模型训练完成后,我不光保留了PyTorch的.pt权重,还导出了一份ONNX格式,方便在不同的部署环境里使用。

第三部分是界面层。界面用PyQt5开发,主要功能包括:加载本地视频文件、打开摄像头实时检测、画面显示、检测框绘制、跌倒告警弹窗、日志记录。界面层和推理逻辑分开,用QThread跑推理循环,主线程负责刷新界面,避免画面卡顿。

第四部分是打包部署层。用PyInstaller把整个项目打包成Windows可执行文件,这样没有Python环境的电脑也能直接运行。

1.2 跌倒检测的核心难点与技术选型

跌倒检测为什么不能拿现成的人体姿态估计模型直接套?这是这次项目里我第一个想清楚的问题。

人体姿态估计(比如OpenPose、MediaPipe)能输出关键点坐标,理论上通过关键点角度和相对位置确实能判断是否跌倒。但姿态估计模型普遍比较重,在低算力设备上跑实时视频流很吃力,而且对遮挡、模糊、远距离小目标比较敏感。老人家里的环境往往有家具遮挡,光线也不理想,姿态估计方案在这种场景下容易翻车。

目标检测方案更合适。检测模型直接在框级别输出“人”和“跌倒”这两个类别,逻辑简单直接。只要训练数据够丰富,模型对遮挡和光照的鲁棒性比纯姿态估计好不少。这也是YOLO系列这类端到端检测器在工业场景里用得最多的原因。

那为什么选YOLO26而不是YOLOv5或者YOLOv8?需要说明的是,YOLO26作为系列的新成员,延续了前面几代在实时性和精度之间找平衡的思路,同时吸收了Transformer检测头的设计思路,在动态标签分配、跨尺度特征融合上做了改进。尤其针对小目标和遮挡场景,YOLO26的检测头设计有针对性优化,这对跌倒检测非常关键——因为画面里的人可能离摄像头比较远,也可能是半躺在沙发上这种非标准姿态。

我实际比过,在相同算力条件下,YOLO26的mAP比YOLOv8有明显提升,推理速度几乎没有下降。具体数据后面会放出来。

2. YOLO26训练自己的跌倒检测数据集

2.1 数据集的来源与标注规范

做跌倒检测,最难的不是训练,而是数据。

公开的跌倒检测数据集其实有一些,比如UR Fall Detection、Le2i Fall Detection,但这些数据集年代比较久,分辨率低,场景单一,直接用它们训练出来的模型在真实监控画面里表现很差。我自己整理了一套数据集,思路是“公开数据做底子,自己补充真实场景”,类别就两类:

类别含义标注数量
person正常站立、行走、坐下的人约5200张
fall跌倒、倒地、躺卧的人约2800张

标注格式用的是YOLO的txt格式,每行对应一个目标:类别编号 + 归一化后的中心点x,y + 框宽高w,h。标注工具我用的LabelImg,虽然界面朴素,但胜在稳定,支持YOLO格式直接导出。

这里有个经验要分享一下:千万别只标注“跌倒”这一类。我最初做的一个版本只标注了fall,结果模型把弯腰捡东西、蹲下系鞋带全部识别成跌倒,误报率惨不忍睹。加入person类之后,模型学会了区分“正常低姿态”和“异常倒地”,误报率立刻降下来了。

2.2 环境配置与训练参数选择

训练环境我用的是Windows + RTX 3060 12G,Python 3.9,Ultralytics框架。Ultralytics对YOLO系列的支持比较完善,YOLO26也可以直接用命令行或Python API训练,省去自己写训练循环的麻烦。

安装依赖很简单:

pip install ultralytics

数据集的目录结构是这样的:

dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── fall.yaml

fall.yaml内容如下:

path: E:/fall_detection/dataset train: images/train val: images/val nc: 2 names: ['person', 'fall']

训练命令我建议直接用Ultralytics的CLI:

yolo detect train data=fall.yaml model=yolo26n.pt epochs=150 imgsz=640 batch=8 device=0

YOLO26有几个不同规模的变体,n/s/m/l/x,我选的是yolo26n这个轻量版本。为什么?因为跌倒检测最终要跑实时视频流,内存和显存占用不能太高,n模型推理速度最快,精度上日常使用已经够了。如果对精度要求更高,可以换yolo26s或yolo26m,对应的模型参数和显存占用会成倍增加。

训练的关键超参数:

参数说明
imgsz640输入分辨率,越大精度越高但速度越慢
batch8根据显存调整,3060 12G跑8没问题
epochs150数据集小的epochs可以少一点,防止过拟合
optimizerSGD默认SGD,收敛稳定
lr00.01初始学习率,用默认值就行
device0指定GPU

训练过程里我观察到一个现象:前50个epoch loss下降很快,50到100个epoch进入平台期,100到150个epoch又有小幅下降。这说明模型在小数据集上需要足够的迭代次数才能充分收敛。我建议至少跑到120个epoch以上,不要一看早期mAP涨得慢就提前停。

2.3 推理效果分析与模型评估

训练结束后,先看看验证集上的指标。我的结果大概是:

指标数值
mAP500.942
mAP50-950.785
Precision0.912
Recall0.935

这个结果看着还不错,但要注意:mAP高不代表实际场景就一定能用。原因在于验证集和真实监控画面之间存在域差异,也就是我前面说的“训练环境和部署环境长得不一样”。我建议训练完不要只看指标,一定要拿几段真实场景的视频实测。

我的实测结果是:在光线正常的室内环境下,跌倒检测基本都能框出来,延迟在每秒25帧左右。但到了光线偏暗的走廊、或者老人穿着深色衣服躺在深色地板上的场景,漏检率明显上升。这就是典型的对比度不足问题,后面我会讲怎么优化。

模型训练好之后,导出ONNX格式的一步很关键,这样在PyQt里可以用OpenCV DNN加载,不依赖PyTorch环境:

from ultralytics import YOLO model = YOLO('runs/detect/train/weights/best.pt') model.export(format='onnx', imgsz=640, half=True)

导出ONNX之后,模型体积只有十几MB,部署起来很轻。

3. PyQt交互界面开发:从推理代码到可视化监控

3.1 界面整体设计与人机交互逻辑

PyQt界面我做了三个主要区域:左侧是视频显示区,右侧是控制面板和控制按钮,底部是日志信息区。

界面布局表:

区域控件功能
视频显示区QLabel显示视频帧和检测框
控制面板文件选择按钮打开本地视频文件
控制面板摄像头开关打开/关闭摄像头
控制面板检测开关启用/禁用推理
控制面板告警阈值滑块调整跌倒告警灵敏度
底部日志QTextEdit记录检测事件和时间

为什么要专门放一个“告警阈值滑块”?这个设计是我在实际测试中体会出来的。不同场景对误报的容忍度不一样:如果是医院病房,宁可误报也要保证不漏报;如果是普通家庭,频繁误报会让人烦躁。阈值可调是让使用者自己平衡。

3.2 模型集成与实时检测线程管理

这里要重点讲一个新手最容易犯的错:直接在UI线程里跑推理循环。

PyQt的主线程负责事件循环,如果你在主线程里while True读取视频帧并推理,界面会直接卡死,窗口拖不动、按钮没反应。解决办法是开一个QThread子线程跑推理,通过信号把结果传回主线程刷新界面。

我用的推理方式是OpenCV的DNN模块读取ONNX模型。为什么不用Ultralytics的推理API?因为Ultralytics依赖PyTorch,打包成exe时体积会非常大,动辄2GB以上。而OpenCV DNN只需要一个ONNX文件,程序体积小,部署起来方便,推理速度也很快。

简单看一下核心代码结构:

class InferenceThread(QThread): change_pixmap = pyqtSignal(QImage) update_status = pyqtSignal(dict) def __init__(self, model_path): super().__init__() self.net = cv2.dnn.readNetFromONNX(model_path) self.running = True def run(self): cap = cv2.VideoCapture(self.source) while self.running: ret, frame = cap.read() if not ret: break # 预处理:resize到640x640,归一化,构造blob blob = cv2.dnn.blobFromImage( frame, 1/255.0, (640, 640), (0, 0, 0), swapRB=True, crop=False ) self.net.setInput(blob) outputs = self.net.forward() # 后处理:解码输出,筛选置信度,NMS dets = post_process(outputs, conf_threshold=0.5) # 绘制检测框 draw_detections(frame, dets) # 转换成QImage并发送到主线程 ...

关键点在于后处理部分。YOLO26的ONNX输出是一个包含预测结果的张量,需要解析出每个预测框的坐标、置信度和类别。这里我不打算贴完整代码,但要强调:后处理的效率直接影响帧率,尽量用NumPy矩阵操作,避免写Python for循环逐框解码,否则帧率会掉到个位数。

3.3 告警与日志模块实现

告警模块是老年人跌倒检测系统的“最后一公里”。模型检测到fall类别,如果置信度超过阈值,就触发告警。

我的触发逻辑做了防抖处理:不是检测到一帧跌倒就立刻告警,而是连续3帧都在同一区域检测到fall,才触发告警。为什么这么设计?因为单帧误检的概率不低,可能是镜头抖动、光线瞬间变化,但连续3帧都误检的概率就小很多了。这个逻辑简单有效,比单纯调高置信度阈值更能平衡漏报和误报。

告警方式我做了两种:

  1. 界面弹窗:PyQt的QMessageBox弹窗,红色标题提示。
  2. 声音告警:调用Windows内置Alert声音,或者播放一段本地音频。

日志模块则用QTextEdit实时显示,同时写一份CSV文件,记录时间、检测结果、置信度。CSV日志的价值在于事后复盘:如果家属发现某天出现了误报,可以通过日志回溯当时的检测置信度和视频帧,判断是阈值问题还是模型问题。我实际用下来,这份日志在调优阶段帮助很大,比凭感觉调参数可靠得多。

4. 系统打包发布:把Python项目变成可交付的exe

4.1 PyInstaller打包配置与常见坑

项目开发调试完成后,要交付给不会装Python的人使用,就需要打包成exe。这里我踩了不少坑,值得好好写一写。

我选的工具是PyInstaller,打包命令:

pyinstaller -D --windowed --name FallDetection main.py

这里有几个关键点:

第一,用-D(onedir)模式,不要用-F(onefile)模式。onefile模式虽然只有一个exe,但启动时会把所有文件解压到临时目录,启动速度慢很多,而且容易被杀毒软件误报。对于这种带模型的工具,onedir模式更合适,启动快,杀毒误报率也低一些。

第二,项目里的ONNX模型文件、数据集等资源文件不会自动打包进去。需要在spec文件里显式添加:

a = Analysis( ['main.py'], datas=[('models/best.onnx', 'models')], hiddenimports=['ultralytics.nn.modules'], ... )

第三,PyQt5和Ultralytics都有不少动态导入的模块,PyInstaller静态分析抓不到,会导致运行时提示ModuleNotFoundError。这个问题很隐蔽,我花了一个多小时才定位到。

解决方案是加hiddenimports。常见的需要补充的模块包括ultralytics.nn.modules、ultralytics.nn.tasks,以及PyQt5.QtCore、PyQt5.QtGui、PyQt5.QtWidgets这些包如果用了特殊插件也要额外标记。

4.2 模型与界面资源的组织方式

打包成功后目录结构大概是这样的:

FallDetection/ ├── FallDetection.exe ├── _internal/ │ ├── models/ │ │ ├── best.onnx │ │ └── fall.yaml │ └── config/ │ └── config.ini └── logs/

把所有配置项(摄像头编号、置信度阈值、告警连续帧数)放到config.ini里,好处是调整参数不需要重新编译exe。我实际交付给朋友试用时,就是通过改config.ini来适配他家不同角度的摄像头,方便不少。

这里还要提醒一个细节:用--windowed打包后,程序没有控制台窗口,如果程序启动时报错,你根本看不到报错信息。我建议在代码里加一个全局的异常捕获,把错误写入log文件:

import sys import traceback def global_exception_hook(exc_type, exc_value, exc_traceback): with open('error.log', 'a', encoding='utf-8') as f: traceback.print_exception( exc_type, exc_value, exc_traceback, file=f ) sys.excepthook = global_exception_hook

这样即使程序在别人的电脑上崩了,也能拿到日志排查问题。

5. 从实验室到落地:实际部署中的优化与避坑记录

5.1 实测效果与性能优化

在真实环境部署后,我发现训练时的mAP和真实场景的体验差距还是很大的。最大的问题是光线和视角。

先说光线。我训练数据大部分是白天室内拍摄的,但很多老人晚上在家只开一盏小灯,画面亮度很低。实测下来低光环境漏检率至少上升了20%。解决思路有两个:

一是从数据端解决:补充夜间和低光图片,做亮度抖动的数据增强。这在项目里有专门的增强配置。

二是从工程端解决:在图像预处理阶段做自适应直方图均衡化(CLAHE),提升暗部细节后再送入模型。实测对低光场景有明显改善,而且几乎不影响正常光线下的检测效果。

再说视角。监控摄像头通常装在墙角顶上,俯视角度比较大。如果训练数据大多是平视角度的图片,模型在高俯视角度的监控画面里表现会变差。我后来手动标注了大概200张俯视角度的家庭场景图,加入训练集后,俯视场景的检测准确率有了明显提升。

5.2 嵌入式设备部署思路

很多读者关心能不能部署到嵌入式设备,比如树莓派、Jetson Nano这类设备上。说实话,我用的是轻量级的yolo26n模型,推理本身并不太重,但PyQt界面整一套在嵌入式Linux上跑,内存会吃紧。

如果在嵌入式设备上做部署,我的建议是换架构:用GStreamer或FFmpeg做视频采集,推理用TensorRT或OpenCV DNN,图形界面可以砍掉,只保留HTTP接口或MQTT推送告警。我之前在树莓派4B上跑过一个简化版,用的也是ONNX模型,帧率能到每秒8-10帧,作为监控告警来说够用了。如果希望帧率更高,可以考虑TensorRT加速,不过树莓派的GPU支持一般,Jetson系列效果会好很多。

嵌入式部署的方向,实际上是把现有的Python检测逻辑和界面解耦,检测服务单独拿出来跑。后面有空我可以专门出一篇嵌入式部署的教程。

5.3 数据扩充与边界情况处理

最后讲讲数据扩充。YOLO26内置了Mosaic、MixUp这些数据增强策略,但默认参数可能并不完全适合跌倒检测场景。

我做了几个针对性的调整:

第一,增大平移和旋转幅度。跌倒姿态身体是歪着的,各种奇怪的角度都有,所以训练时要让模型多看到旋转后的样本。这在ultralytics的配置文件里通过augment参数调。

第二,增加了随机遮挡增强。老人被桌子、椅子、门框遮挡是常态,模型要学会只凭身体局部判断跌倒。我在数据扩充里加了随机擦除,模拟遮挡。

第三,针对“人躺在地板上”的检测难度,我在混入背景样本时,特意增加了地板、沙发这类深色背景比例,强迫模型学习轮廓特征而不是依赖颜色对比。

除了数据扩充,边界情况的处理也很重要。比如:老人弯腰捡东西、下蹲、坐在椅子上打瞌睡身体歪斜,这些动作和跌倒之间的界限本来就很模糊。我的处理方式是:把这些容易混淆的样本单独抽出来,在训练数据里专门加大比例,同时通过可调节的告警阈值来适应用户对误报率的接受度。

从实际使用体验来看,这套系统已经能应付大部分室内监控场景了——白天光线好时检测准确率很高,低光环境下也能用,告警响应延迟在可接受范围。当然还有不少可以继续优化的地方,比如多摄像头联动、跨摄像头跟踪、行为预测等等。但这些都属于后续扩展,把基础检测这件事做扎实,才是最关键的。

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

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

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

立即咨询