基于YOLO26与PyQt的老年人跌倒检测系统开发实战
发布时间:2026/8/27 23:54:57 作者:尧图编辑部 阅读量:1,286

简介目标检测是计算机视觉中最基础也最具工程落地价值的方向之一其核心任务是在图像或视频中定位并分类目标。随着边缘计算和本地化部署的普及基于轻量级模型构建实时检测系统已成为智慧养老、家庭安防等场景的常见需求。本文从目标检测的基本原理出发介绍如何利用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 12GPython 3.9Ultralytics框架。Ultralytics对YOLO系列的支持比较完善YOLO26也可以直接用命令行或Python API训练省去自己写训练循环的麻烦。安装依赖很简单pip install ultralytics数据集的目录结构是这样的dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── fall.yamlfall.yaml内容如下path: E:/fall_detection/dataset train: images/train val: images/val nc: 2 names: [person, fall]训练命令我建议直接用Ultralytics的CLIyolo detect train datafall.yaml modelyolo26n.pt epochs150 imgsz640 batch8 device0YOLO26有几个不同规模的变体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.942mAP50-950.785Precision0.912Recall0.935这个结果看着还不错但要注意mAP高不代表实际场景就一定能用。原因在于验证集和真实监控画面之间存在域差异也就是我前面说的“训练环境和部署环境长得不一样”。我建议训练完不要只看指标一定要拿几段真实场景的视频实测。我的实测结果是在光线正常的室内环境下跌倒检测基本都能框出来延迟在每秒25帧左右。但到了光线偏暗的走廊、或者老人穿着深色衣服躺在深色地板上的场景漏检率明显上升。这就是典型的对比度不足问题后面我会讲怎么优化。模型训练好之后导出ONNX格式的一步很关键这样在PyQt里可以用OpenCV DNN加载不依赖PyTorch环境from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) model.export(formatonnx, imgsz640, halfTrue)导出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), swapRBTrue, cropFalse ) self.net.setInput(blob) outputs self.net.forward() # 后处理解码输出筛选置信度NMS dets post_process(outputs, conf_threshold0.5) # 绘制检测框 draw_detections(frame, dets) # 转换成QImage并发送到主线程 ...关键点在于后处理部分。YOLO26的ONNX输出是一个包含预测结果的张量需要解析出每个预测框的坐标、置信度和类别。这里我不打算贴完整代码但要强调后处理的效率直接影响帧率尽量用NumPy矩阵操作避免写Python for循环逐框解码否则帧率会掉到个位数。3.3 告警与日志模块实现告警模块是老年人跌倒检测系统的“最后一公里”。模型检测到fall类别如果置信度超过阈值就触发告警。我的触发逻辑做了防抖处理不是检测到一帧跌倒就立刻告警而是连续3帧都在同一区域检测到fall才触发告警。为什么这么设计因为单帧误检的概率不低可能是镜头抖动、光线瞬间变化但连续3帧都误检的概率就小很多了。这个逻辑简单有效比单纯调高置信度阈值更能平衡漏报和误报。告警方式我做了两种界面弹窗PyQt的QMessageBox弹窗红色标题提示。声音告警调用Windows内置Alert声音或者播放一段本地音频。日志模块则用QTextEdit实时显示同时写一份CSV文件记录时间、检测结果、置信度。CSV日志的价值在于事后复盘如果家属发现某天出现了误报可以通过日志回溯当时的检测置信度和视频帧判断是阈值问题还是模型问题。我实际用下来这份日志在调优阶段帮助很大比凭感觉调参数可靠得多。4. 系统打包发布把Python项目变成可交付的exe4.1 PyInstaller打包配置与常见坑项目开发调试完成后要交付给不会装Python的人使用就需要打包成exe。这里我踩了不少坑值得好好写一写。我选的工具是PyInstaller打包命令pyinstaller -D --windowed --name FallDetection main.py这里有几个关键点第一用-Donedir模式不要用-Fonefile模式。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, encodingutf-8) as f: traceback.print_exception( exc_type, exc_value, exc_traceback, filef ) 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参数调。第二增加了随机遮挡增强。老人被桌子、椅子、门框遮挡是常态模型要学会只凭身体局部判断跌倒。我在数据扩充里加了随机擦除模拟遮挡。第三针对“人躺在地板上”的检测难度我在混入背景样本时特意增加了地板、沙发这类深色背景比例强迫模型学习轮廓特征而不是依赖颜色对比。除了数据扩充边界情况的处理也很重要。比如老人弯腰捡东西、下蹲、坐在椅子上打瞌睡身体歪斜这些动作和跌倒之间的界限本来就很模糊。我的处理方式是把这些容易混淆的样本单独抽出来在训练数据里专门加大比例同时通过可调节的告警阈值来适应用户对误报率的接受度。从实际使用体验来看这套系统已经能应付大部分室内监控场景了——白天光线好时检测准确率很高低光环境下也能用告警响应延迟在可接受范围。当然还有不少可以继续优化的地方比如多摄像头联动、跨摄像头跟踪、行为预测等等。但这些都属于后续扩展把基础检测这件事做扎实才是最关键的。本文还有配套的精品资源点击获取