简介本资源面向计算机视觉入门与进阶开发者、安防场景算法实践者提供一套完整的YOLOv8行人跌倒检测方案解决从数据准备到界面部署的全流程问题。包内包含基于一千多张行人跌倒图像训练好的检测权重目标类别为fall并附PR曲线、loss曲线等训练过程记录便于评估模型表现。资源共约2000个文件以txt标签、jpg样本图、py源码、pyc缓存、yaml配置为主另有pt权重、ui界面文件、mp4演示视频及pdf说明文档压缩包约134.81MB目录按数据集、代码、界面等模块划分清晰。PyQt界面支持图片、视频与摄像头三种检测方式数据集同时提供txt和xml两种标注格式分别存放于独立文件夹方便直接用于训练或格式转换。目前已有744人学习下载适合希望快速复现跌倒检测项目、理解YOLOv8训练与推理流程、并借助可视化界面完成演示的读者参考。1. 从一次养老院走廊的误报说起YOLOv8行人跌倒检测到底在做什么去年帮一个做智慧养老的朋友调系统他们用普通摄像头做跌倒报警结果老人蹲下系鞋带、弯腰捡东西后台一天弹几十条告警护工直接把通知关了。问题不在摄像头在于只用了「人体框高宽比突变」这种规则判断没有真正识别「跌倒」这个动作的时空特征。后来换成 YOLOv8 做人体检测再叠加姿态和时序逻辑误报率才压下来。这套「YOLOv8行人跌倒检测训练好的模型pyqt界面数据集」的组合本质是把检测、判定、可视化三件事串成一条能落地的链路YOLOv8 负责在每一帧里稳定框出人跌倒判定负责区分「躺下」和「摔倒」PyQt 界面负责让非技术护工也能看懂和操作。它适合两类人一类是想拿现成模型快速搭演示或毕设的开发者另一类是想把跌倒检测接进自己监控系统的工程人员。下面我按「数据怎么准备、模型怎么训、界面怎么接、坑在哪」的顺序把这条链路拆开讲清楚。2. 数据集与标注跌倒检测的成败八成在数据这一层2.1 跌倒检测数据集和通用行人数据集差在哪很多人第一反应是拿 COCO 或 VOC 里的人物框直接训结果模型只学会「框人」根本不知道什么叫跌倒。跌倒检测的数据集必须包含三类关键样本正常站立行走、蹲坐弯腰等易混淆动作、真实跌倒含躺地、侧摔、后仰。常见做法是自建用固定摄像头在走廊、卧室、卫生间门口各录一段再抽帧标注。公开数据集里像 UR Fall Detection、Le2i 这类偏学术场景和国内养老院差异大直接拿来训往往过拟合。我一般建议公开数据集做预训练底子自建 20005000 张做微调比例大概 1:2。标注用 LabelImg 或 Labelme 都行YOLOv8 要的是 YOLO 格式的 txt。每张图一个同名 txt每行类别 x_center y_center w h坐标全部归一化到 01。类别建议只设两类person和fall。别把「蹲下」单独设一类否则类别不平衡会更严重蹲下交给后处理逻辑去过滤。2.2 把标注数据整理成 YOLOv8 能吃的目录结构YOLOv8 对目录结构有固定要求整理错了训练直接报找不到标签。标准结构如下fall_dataset/ ├── images/ │ ├── train/ # 训练图片 │ └── val/ # 验证图片 ├── labels/ │ ├── train/ # 对应训练标签 txt │ └── val/ # 对应验证标签 txt └── data.yaml # 数据集配置文件data.yaml内容path: /home/user/fall_dataset # 数据集根目录绝对路径最稳 train: images/train val: images/val nc: 2 # 类别数 names: [person, fall] # 类别名顺序必须和标注时一致这里有个血泪经验names的顺序必须和标注时类别 id 对应标fall时如果 id 写成 1names 里fall就得排第二。顺序错位模型会把跌倒当人训练 loss 看着降实际全错。整理完跑一句校验确认图片和标签数量一致import os img_dir fall_dataset/images/train lbl_dir fall_dataset/labels/train imgs {os.path.splitext(f)[0] for f in os.listdir(img_dir)} lbls {os.path.splitext(f)[0] for f in os.listdir(lbl_dir)} print(无标签的图片:, imgs - lbls) # 应为空 print(无图片的标签:, lbls - imgs) # 应为空参数说明imgs - lbls是漏标的图片lbls - imgs是删图后残留的标签两者都必须为空才能开训。这一步花两分钟能省后面几小时的排查。2.3 数据增强里哪些能用哪些会帮倒忙YOLOv8 默认开启 mosaic、HSV 抖动、随机翻转。跌倒检测里水平翻转可以用垂直翻转千万别开——人倒过来在物理上不成立模型会学到错误特征。mosaic 四图拼接对小目标有帮助但跌倒样本本身占画面比例大mosaic 反而可能把两个跌倒拼成一张造成标签混乱。我一般把mosaic关掉或调低到 0.3fliplr保持 0.5scale控制在 0.5 以内避免人体被缩得太小。这些在训练命令里通过参数覆盖即可不用改源码。3. 训练 YOLOv8 跌倒检测模型参数怎么设、曲线怎么看3.1 环境配置与最小训练命令环境用 Python 3.93.10PyTorch 按显卡选版本。CPU 也能跑只是慢ubuntu20.04上装 CPU 版做验证没问题正式训还是建议有张 8G 以上显存的卡。装 ultralyticspip install ultralytics8.0.200 yolo checks # 检查环境和依赖最小训练命令yolo detect train \ datafall_dataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/fall \ nameexp1参数说明modelyolov8n.pt是官方预训练权重n 最轻量跌倒检测场景够用显存紧张就选它imgsz640是输入尺寸摄像头分辨率高可以提到 960但显存翻倍batch16按显存调8G 卡跑 640 一般能到 16lr00.01初始学习率微调自建小数据集可以降到 0.001patience20是早停20 轮没提升就停省时间。训练完权重在runs/fall/exp1/weights/best.pt。3.2 损失曲线和 mAP 曲线到底该看哪条训练完runs/fall/exp1/下会有results.png包含 box_loss、cls_loss、mAP50、mAP50-95。看曲线有三个判断点box_loss 和 cls_loss 应平稳下降如果 cls_loss 震荡大多半是学习率偏高或类别不平衡mAP50 到 0.85 以上基本可用跌倒检测因为样本少能到 0.8 就不错如果训练集 mAP 高、验证集低是过拟合加数据或加dropout。想自己画曲线读results.csvimport pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/fall/exp1/results.csv) df.columns df.columns.str.strip() # 列名常带空格必须清理 plt.plot(df[epoch], df[metrics/mAP50(B)], labelmAP50) plt.plot(df[epoch], df[train/box_loss], labelbox_loss) plt.legend(); plt.xlabel(epoch); plt.savefig(curve.png)参数说明columns.str.strip()这行别省ultralytics 导出的 csv 列名前后有空格不清理会 KeyError这是很多人画不出曲线的直接原因。3.3 推理验证先确认模型真的能分「跌倒」和「蹲下」训完别急着接界面先用命令行验证几张图yolo detect predict \ modelruns/fall/exp1/weights/best.pt \ sourcetest_imgs/ \ conf0.4 \ saveTrueconf0.4是置信度阈值跌倒检测宁可稍低也别漏报但太低会误报0.4 是常见起点。重点看两类图蹲下弯腰的有没有被误判成 fall真实躺地的有没有被漏掉。如果蹲下误报多说明数据里负样本不够回去补如果躺地漏报看是不是跌倒样本姿态太单一补侧摔、后仰样本。这一步是接界面前最后一道关别跳过。4. PyQt 界面接入把模型变成护工能用的工具4.1 界面最小功能集与线程模型PyQt 界面别一上来做花哨的最小可用集就四块视频显示区、开始/停止按钮、报警日志区、置信度滑块。核心难点是推理不能跑在主线程否则界面卡死。常见做法是 QThread 开子线程跑 YOLOv8 推理通过信号把结果发回主线程刷新。下面是一个可复用的推理线程骨架from PyQt5.QtCore import QThread, pyqtSignal from ultralytics import YOLO import cv2 class DetectThread(QThread): frame_signal pyqtSignal(object) # 发带框的帧 alarm_signal pyqtSignal(str) # 发报警文本 def __init__(self, model_path, source0, conf0.4): super().__init__() self.model YOLO(model_path) self.source source self.conf conf 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 results self.model(frame, confself.conf, verboseFalse) for r in results: for box in r.boxes: cls_id int(box.cls[0]) name self.model.names[cls_id] if name fall: self.alarm_signal.emit(检测到跌倒请立即查看) annotated results[0].plot() # 画框 self.frame_signal.emit(annotated) cap.release() def stop(self): self.running False self.wait()逻辑说明frame_signal传 numpy 图像给主线程显示alarm_signal传报警字符串。results[0].plot()是 ultralytics 自带的画框方法省得自己写。参数conf从界面滑块读source0是本地摄像头也可以传视频路径。注意verboseFalse关掉每帧日志否则控制台刷屏拖慢速度。4.2 主窗口怎么把信号接起来主窗口负责显示和交互关键是把子线程信号连到槽函数from PyQt5.QtWidgets import QMainWindow, QLabel, QPushButton, QVBoxLayout, QWidget from PyQt5.QtGui import QImage, QPixmap import cv2 class MainWindow(QMainWindow): def __init__(self): super().__init__() self.label QLabel(视频区) self.btn QPushButton(开始检测) self.btn.clicked.connect(self.toggle) layout QVBoxLayout() layout.addWidget(self.label) layout.addWidget(self.btn) container QWidget(); container.setLayout(layout) self.setCentralWidget(container) self.thread None def toggle(self): if self.thread is None: self.thread DetectThread(runs/fall/exp1/weights/best.pt, conf0.4) self.thread.frame_signal.connect(self.show_frame) self.thread.alarm_signal.connect(self.show_alarm) self.thread.start() self.btn.setText(停止) else: self.thread.stop() self.thread None self.btn.setText(开始检测) def show_frame(self, frame): rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, _ rgb.shape img QImage(rgb.data, w, h, w * 3, QImage.Format_RGB888) self.label.setPixmap(QPixmap.fromImage(img).scaled(self.label.size())) def show_alarm(self, text): print(报警:, text) # 实际可换成日志区追加参数说明QImage构造里的w * 3是每行字节数RGB 三通道写错会花屏。scaled保持比例显示。show_alarm里换成往 QTextEdit 追加文本即可。这套骨架跑通后再加报警声音、日志落盘、多路摄像头都不难。4.3 界面和模型解耦换模型不用改界面把模型路径、置信度、类别名抽成配置界面只读配置。这样以后换yolov8s.pt或换自训权重只改配置文件。常见做法是写个config.yaml界面启动时读。别把路径硬编码在代码里否则部署到另一台机器全是错。5. 避坑与排查跌倒检测落地时最容易翻车的五件事5.1 现象模型把蹲下、弯腰全报成跌倒原因训练集里负样本蹲、坐、弯腰太少模型只学到「人体框变矮变宽」就等于跌倒。解决补 5001000 张易混淆动作图标成person重新微调同时在推理后加逻辑连续 N 帧判定为 fall 才报警单帧不报。5.2 现象训练 loss 正常下降但验证 mAP 一直是 0原因data.yaml里names顺序和标注类别 id 错位或者val路径写错导致验证集为空。解决跑 2.2 的校验脚本确认图片标签配对再打印data.yaml核对 names 顺序路径用绝对路径。5.3 现象PyQt 界面点开始后卡死无响应原因推理跑在主线程或者子线程里直接操作了界面控件。解决推理必须放 QThread界面刷新只能通过信号槽在主线程做子线程里禁止直接调setPixmap。5.4 现象CPU 上跑推理只有 23 帧界面像幻灯片原因yolov8n在 CPU 上 640 输入也就这个水平。解决降imgsz到 416或换yolov8n的 OpenVINO/ONNX 导出加速实在要实时得上 GPU 或边缘加速棒。别指望 CPU 跑 1080p 实时。5.5 现象换一台机器部署报找不到模型或类别错乱原因模型路径硬编码、names从模型里读但和界面写死的类别对不上。解决模型路径走配置类别名统一从model.names读界面不写死。部署前在目标机器跑一遍yolo detect predict确认模型能加载。6. 让跌倒检测更稳的一个技巧用连续帧投票压掉单帧误报单帧检测再准也架不住光照突变、遮挡、运动模糊。我一般会在 PyQt 线程里加一个滑动窗口投票维护最近 10 帧的判定结果fall 出现超过 6 帧才触发报警同时要求人体框中心在窗口内持续下移。这样蹲下这种短暂动作会被自然过滤真实跌倒因为持续躺地会稳定命中。实现上用一个collections.deque(maxlen10)存每帧是否 fall报警前统计比例from collections import deque class FallVoter: def __init__(self, window10, threshold0.6): self.buf deque(maxlenwindow) self.threshold threshold def update(self, is_fall): self.buf.append(1 if is_fall else 0) if len(self.buf) self.buf.maxlen: return False return sum(self.buf) / len(self.buf) self.threshold参数说明window10对应约 0.30.5 秒按帧率threshold0.6表示 10 帧里 6 帧判定跌倒才报警。窗口太长会延迟报警太短压不住误报10 和 0.6 是我在 25fps 摄像头下试出来的平衡点。验证方法很简单录一段「蹲下捡东西再站起」和一段「真实侧摔」分别跑投票逻辑看误报和漏报。我自己的习惯是每换一个场景先跑这两段回归再上线。这套投票逻辑不复杂但它是把 demo 变成能用的系统之间最关键的一步。希望帮到你。本文还有配套的精品资源点击获取