ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于YOLO与PyQt的跌倒检测系统:从资源包到护理监控原型实战

基于YOLO与PyQt的跌倒检测系统:从资源包到护理监控原型实战 简介这份资源面向从事老年人护理与安全监控的开发者、学生及算法爱好者提供一套可直接落地的跌倒检测目标检测方案解决摔倒行为识别与实时预警问题。包内包含1428张已标注图像同时提供YOLO格式txt标签与VOC格式xml标签并划分好train、val、test三个子集附data.yaml文件可无缝接入yolov5至yolov26等主流算法训练。压缩包共约2000个文件以txt标注与说明、md文档、py脚本为主辅以cpp、js、html、yaml等工程文件整体约77.41MB兼顾数据集、训练好的模型与使用教程。资源还附带模型评价指标曲线图便于评估精度与收敛情况。目前已有36人学习下载读者可借此快速复现跌倒检测流程理解数据组织与模型评估思路并在此基础上迁移到护理看护、独居老人监护等实际场景。1. 跌倒检测系统落地从 yolo26-pyqt 资源包到可跑通的护理监控原型养老院夜班最怕什么不是老人起夜而是跌倒后半小时没人发现。我拆过不少所谓「智能看护」的包多数是拿个开源权重套个界面就发出来跑起来要么检测框乱飞要么 PyQt 界面直接卡死。这次拿到的yolo26-pyqt跌倒检测-老年人护理和安全监控系统数据集训练好的模型.zip算是少见的完整件数据集、训练好的模型、PyQt 桌面端推理界面三样都在目标很明确——让做毕设或做原型验证的人不用从标注开始直接跑通「视频输入→跌倒判定→界面告警」这条链路。它适合两类人一是需要快速出演示效果的嵌入式或上位机方向学生二是想拿现成 pipeline 改自己场景的初级算法工程师。不适合指望开箱即用上生产的人因为跌倒判定逻辑和误报抑制还得自己调。2. 拆包先看结构数据集、模型、PyQt 界面各管什么2.1 资源包里的三块拼图与各自边界拿到压缩包先别急着解压到桌面我一般会先看目录层级。这类资源通常分三块datasets/放图片和 YOLO 格式标签weights/或runs/放训练好的.pt权重根目录或ui/下放 PyQt 的.py和.ui文件。数据集这块要重点确认两点一是标注格式是不是 YOLO 的class x_center y_center w h归一化格式二是类别数是不是只有fall和person两类或者干脆只有fall一类。常见做法是只标跌倒姿态正常行走不标这样模型学的是「跌倒特征」而不是「人」。模型这块标题写的是 yolo26但实际权重文件大概率是 YOLOv8 或 YOLOv11 的.pt因为目前主流训练脚本和部署生态对这两个版本支持最稳。PyQt 界面负责的是把 OpenCV 读帧、模型推理、画框、告警文字串起来它本身不做检测只是个壳。提示解压后先看requirements.txt或README确认 torch 和 ultralytics 的版本。版本对不上权重加载直接报UnpicklingError。2.2 环境搭建Python、PyQt5 与 ultralytics 的版本咬合环境这块翻车最多。我习惯用 conda 建独立环境Python 选 3.9 或 3.10这两个版本对 PyQt5 和 torch 的兼容性最省心。PyQt5 用 pip 装PyQt55.15.9别装 6因为很多现成界面代码是from PyQt5.QtWidgets import ...装 6 会报模块找不到。ultralytics 装 8.x 系列它自带 YOLO 推理接口一行YOLO(best.pt)就能加载。torch 根据你有没有显卡选有 N 卡就装 CUDA 版没显卡就 CPU 版但 CPU 推理帧率会掉到个位数演示够用实时监控就吃力。conda create -n fall_detect python3.10 -y conda activate fall_detect pip install PyQt55.15.9 ultralytics opencv-python # 如果有 NVIDIA 显卡去 pytorch 官网复制对应 CUDA 版本的安装命令 # 例如pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118这段命令的逻辑是先隔离环境避免污染全局包再固定 PyQt5 大版本最后装 ultralytics 和 OpenCV。参数上唯一要改的是 torch 的 CUDA 版本号得跟你驱动支持的 CUDA 版本对齐nvidia-smi右上角能看到驱动支持的 CUDA 上限。装完跑一句python -c from ultralytics import YOLO; print(ok)不报错再往下走。2.3 数据集格式核对与类别映射数据集如果直接拿来重训得确认data.yaml里的nc和names跟标签文件对得上。我见过标签里写0代表跌倒但data.yaml里names: [person, fall]这样训练时模型会把跌倒当成人学mAP 看着不低实际推理全是错框。核对方法很简单随便打开一个.txt标签看每行第一个数字再去data.yaml里对。如果只有一类跌倒nc: 1names: [fall]。如果两类nc: 2顺序别搞反。import yaml, glob, os with open(datasets/data.yaml, r) as f: cfg yaml.safe_load(f) print(类别数:, cfg[nc], 类别名:, cfg[names]) label_files glob.glob(datasets/labels/train/*.txt) class_ids set() for lf in label_files[:50]: with open(lf) as f: for line in f: if line.strip(): class_ids.add(int(line.split()[0])) print(标签里出现的类别 id:, sorted(class_ids)) # 如果 class_ids 最大值 cfg[nc]说明映射错了必须改 data.yaml 或重标这段脚本先读data.yaml打印类别配置再抽样 50 个标签文件收集实际出现的类别 id。逻辑说明YOLO 要求类别 id 从 0 连续到 nc-1如果标签里出现 id2 但 nc2训练时直接报索引越界。参数上label_files[:50]是抽样数量数据集大可以不改小数据集全量扫也行。3. 推理链路跑通从权重加载到 PyQt 界面告警3.1 权重加载与单帧推理验证在碰 PyQt 之前先用命令行验证权重能不能正常推理。这一步是分水岭如果命令行都跑不出框界面里更不可能跑通。ultralytics 的推理接口很直白model.predict传图片路径或 numpy 数组都行。我一般会先拿数据集里一张跌倒图试看results[0].boxes里有没有框cls是不是跌倒类。from ultralytics import YOLO import cv2 model YOLO(weights/best.pt) # 替换成实际权重路径 img cv2.imread(datasets/images/val/fall_001.jpg) results model.predict(img, conf0.4, iou0.5, verboseFalse) for box in results[0].boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) xyxy box.xyxy[0].tolist() print(f类别:{cls_id} 置信度:{conf:.2f} 坐标:{xyxy}) # 如果这里一个框都没有先降 conf 到 0.2 再看再没有就是权重或图片路径问题逻辑说明conf0.4是置信度阈值低于这个值的框不输出iou0.5是 NMS 重叠阈值跌倒场景里人和跌倒框可能重叠iou 设太低会误删。参数怎么改如果漏检多conf 降到 0.25如果误报多conf 提到 0.5 以上。verboseFalse只是关掉 ultralytics 的日志刷屏不影响结果。3.2 PyQt 界面与 OpenCV 视频流的线程配合PyQt 界面卡死的根因几乎都是把推理放在主线程。主线程要刷新界面你让它去跑模型界面就假死。正确做法是开一个QThread子线程读视频帧、跑推理通过信号把带框的帧和告警文字发回主线程显示。资源包里的界面代码如果直接在按钮回调里写while True读摄像头那必须改。from PyQt5.QtCore import QThread, pyqtSignal import cv2 from ultralytics import YOLO class DetectThread(QThread): frame_signal pyqtSignal(object, str) # 发帧和告警文字 def __init__(self, model_path, video_path0): super().__init__() self.model YOLO(model_path) self.video_path video_path self.running True def run(self): cap cv2.VideoCapture(self.video_path) while self.running and cap.isOpened(): ret, frame cap.read() if not ret: break results self.model.predict(frame, conf0.4, verboseFalse) alert for box in results[0].boxes: x1, y1, x2, y2 map(int, box.xyxy[0].tolist()) cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), 2) if int(box.cls[0]) 0: # 假设 0 是跌倒类 alert 跌倒告警 self.frame_signal.emit(frame, alert) cap.release() def stop(self): self.running False self.wait()逻辑说明QThread子类里run是线程入口frame_signal是自定义信号参数是objectnumpy 帧和str告警文字。主线程里把这个信号连到更新QLabel的槽函数上。参数上video_path0表示默认摄像头传文件路径就读视频文件。self.running是退出标志窗口关闭时调stop()避免线程泄漏。这段代码直接抄进资源包的界面文件里替换原来的推理循环就行。3.3 跌倒判定逻辑从检测框到告警的中间层YOLO 只告诉你「框里像跌倒」但单帧检测容易误报——弯腰捡东西、坐下瞬间都可能被框成跌倒。我一般会加一个滑动窗口滤波连续 N 帧里超过 M 帧检测到跌倒才触发告警。这个 N 和 M 就是玄学参数N10、M6 是我在 25fps 视频上试出来的经验值太低会误报太高会漏报。资源包里如果没这层逻辑建议自己补上代码不长但效果立竿见影。from collections import deque class FallFilter: def __init__(self, window_size10, threshold6): self.window deque(maxlenwindow_size) self.threshold threshold def update(self, is_fall): self.window.append(1 if is_fall else 0) return sum(self.window) self.threshold # 每帧推理后调 filter.update(检测到跌倒)返回 True 才在界面上弹告警逻辑说明deque固定长度队列存最近 N 帧的跌倒状态sum统计其中跌倒帧数超过阈值才返回 True。参数上window_size对应时间窗口25fps 下 10 帧约 0.4 秒threshold是触发门槛调高更保守。这个滤波模型比单帧判定稳得多代价是告警延迟增加约 0.2 秒护理场景完全可接受。4. 避坑与排查权重、界面、数据集的高频翻车点4.1 权重加载报 UnpicklingError 或 KeyError现象YOLO(best.pt)直接抛异常提示UnpicklingError或KeyError: model。原因通常是权重是用更高版本 ultralytics 训练的或者权重文件下载不完整。解决先确认权重文件大小是否正常YOLOv8n 约 6MBYOLOv8s 约 22MB如果只有几 KB 就是下载断了。版本问题就升级 ultralytics 到最新或者找训练时用的版本。我一般会pip install ultralytics --upgrade再试八成能解决。4.2 PyQt 界面点开始按钮后无响应现象点「开始检测」按钮界面卡住视频框不刷新。原因几乎都是推理循环写在了主线程里或者cv2.waitKey跟 Qt 事件循环冲突。解决把推理逻辑挪到QThread子线程用信号槽更新界面别在子线程里碰任何 Qt 控件。另外cv2.imshow和 PyQt 不要混用要么全用 Qt 显示要么全用 OpenCV 窗口。4.3 摄像头读帧失败或帧率为零现象cap.isOpened()返回 False或者读几帧后ret变 False。原因可能是摄像头被其他程序占用或者VideoCapture索引不对。解决先换video_path传一个本地视频文件测试如果文件能读就是摄像头问题。Windows 下试试cv2.CAP_DSHOW后端cv2.VideoCapture(0, cv2.CAP_DSHOW)。Linux 下确认/dev/video0权限。4.4 数据集标签与 data.yaml 类别数不匹配现象训练时报IndexError: index 2 is out of bounds for dimension 0 with size 2。原因就是标签里的类别 id 超过了nc-1。解决用第 2.3 节的脚本扫一遍标签把超范围的 id 找出来要么改data.yaml的nc和names要么重新映射标签。别硬训训出来也是废权重。4.5 推理速度慢到无法实时现象CPU 上跑 YOLOv8s每帧要 300ms 以上视频卡成幻灯片。原因就是模型太大或没用 GPU。解决换 YOLOv8n 权重输入尺寸从 640 降到 416能快一倍多。有 N 卡就装 CUDA 版 torch推理时加device0。如果还慢把model.predict的halfTrue打开用 FP16 推理速度再提一截精度掉一点点。5. 进阶调优把演示级系统推到可用级的三个技巧第一个技巧是自定义置信度与 IoU 的联动调参。很多人只调conf不动iou结果跌倒框和人体框重叠时被 NMS 误删。我的习惯是跌倒场景把iou提到 0.6让重叠框多留一会儿再靠滑动窗口滤波去误报。具体做法是在model.predict里同时传conf0.35, iou0.6然后观察告警频率误报多就升conf漏报多就降confiou一般不动。第二个技巧是输入分辨率与帧采样率的权衡。PyQt 界面如果直接读 1080p 摄像头每帧 resize 到 640 也要耗时间。我一般会在cap.read()之后立刻cv2.resize到 640×640 再送模型显示的时候再放大回界面尺寸。另外没必要每帧都推理可以隔帧推理中间帧复用上一帧的框视觉上几乎看不出差别CPU 占用直接减半。参数演示级取值可用级取值影响conf0.40.35降低漏检可能增误报iou0.50.6保留重叠框配合滤波输入尺寸640416提速约 40%小目标略降推理间隔每帧隔帧CPU 减半告警延迟 40ms滤波窗口无10 帧 / 6 帧误报大降延迟 0.2s第三个技巧是告警日志与截图留存。护理场景里光弹个文字告警不够得把触发时刻的帧存下来方便回溯。我一般会在FallFilter返回 True 的那一帧用cv2.imwrite存到alerts/目录文件名带时间戳。这样跑一晚上第二天翻一眼截图就知道有没有误报比盯着界面看靠谱得多。import cv2, time, os os.makedirs(alerts, exist_okTrue) if fall_filter.update(is_fall): ts time.strftime(%Y%m%d_%H%M%S) cv2.imwrite(falerts/fall_{ts}.jpg, frame) # 同时把告警文字发到界面逻辑说明fall_filter.update返回 True 才存图避免每帧都写磁盘。time.strftime生成可读时间戳方便按时间检索。参数上存图格式用 jpg 省空间质量默认 95 够用。这个习惯是我从一次误报排查里养成的——当时界面闪了一下告警就没了没截图根本不知道是真人跌倒还是窗帘飘动。从那以后我每次部署这类检测系统都强制走一遍「告警即存图」的流程后悔药不如留证据。希望帮到你。本文还有配套的精品资源点击获取
返回列表