去年秋天接了一个养老机构的视觉巡检项目,需求很直白:夜里老人起夜,在卫生间滑倒,护工往往要过二三十分钟才能发现。我就用 YOLOv8-Pose 搭了一套跌倒检测系统——普通 RGB 摄像头拍到人,模型实时输出 17 个骨骼关键点,再叠一层规则引擎判断“是不是突然倒下去、躺在地上起不来”,确认后立刻推送告警到值班室。整套系统不需要老人戴任何设备,不需要喊话,一个室内摄像头就能跑。这篇文章把项目从选型、数据、训练、推理到规则设计的完整链路拆开讲,适合正在做老人看护、安防巡检,或者准备用 YOLOv8-Pose 做姿态分析的读者参考。
1. 为什么专门做跌倒检测:YOLOv8-Pose 的选型逻辑
1.1 跌倒为什么不能靠普通目标检测解决
普通 YOLO 目标检测输出的只是“人在画面哪个位置”的矩形框,它回答不了“这个人是站着、坐着还是躺在地上”。跌倒检测的核心是判断人的姿态状态和姿态变化,这至少需要骨架级的空间信息——头部、肩部、髋部、脚踝这些关键点之间的相对关系,才能判断一个人是正常活动还是已经倒地不起。
YOLOv8-Pose 的优势在于它把两个任务合并到了同一个模型里:既输出目标检测框,也输出 17 个关键点坐标。这样部署时不用为“找人”和“看姿态”分别跑两套模型,摄像头画面推理一次,人和骨架信息同时拿到,延迟和算力开销都能压下来。这个特性对嵌入式设备特别重要,我后面会详细讲性能数据。
我一开始也试过更偷懒的方案——只用人体检测框的宽高比和中心点高度来区分站、坐、躺。实测下来误报率很高:人横躺在沙发上看书,检测框的宽高比和跌倒躺平非常接近,但显然不该触发告警。加上关键点之后,头部和脚踝的相对位置、躯干和地面的夹角都出来了,才真正能在“看起来像躺着”和“真的是跌倒后躺着”之间做出可靠区分。
1.2 候选方案对比,我不只看中了精度
做选型的时候,我把市面上能走通的几条技术路线都摆在一起对比过,不只是比精度,更比工程落地的现实条件。
| 方案 | 信息量 | 实时性 | 部署成本 | 主要问题 |
|---|---|---|---|---|
| 普通目标检测 + 几何规则 | 只有检测框 | 高 | 低 | 无法判断姿态,误报率高 |
| YOLOv8-Pose + 规则/时序模型 | 检测框 + 17 关键点 | 高 | 中 | 遮挡时关键点容易失效,需要调规则 |
| 3D 骨架 + 图卷积网络 | 3D 时空骨架 | 中 | 高 | 依赖深度相机或多视角,算力开销大 |
| 可穿戴设备 | 加速度/陀螺仪 | 高 | 低 | 需要老人长期佩戴,容易忘戴忘充电 |
3D 骨架方案的精度上限确实更高,但它要求深度相机或者至少两个视角做三角化,室内安装条件往往不满足,成本也上去好几倍。可穿戴设备是最直接的方案,但实际场景里老人愿意长期戴手环的比例很低,而且跌倒时往往手环不在身上。
一句话总结我的选型逻辑:如果目标是在普通摄像头、低成本设备上跑实时跌倒检测,YOLOv8-Pose 是当前工程性价比最高的起点,没有之一。
1.3 边缘部署优先,隐私和成本都要考虑
这套系统我优先放在边缘设备上跑,而不是把视频流全部传云端。原因很实际:室内场景对隐私敏感,视频画面出了本地方向就不太好控制;另外告警链路要求从老人倒地到通知家属只有几秒延迟,云端链路一旦网络抖动,这个延迟就不可控了。
我的整体架构是:摄像头画面只在本地的 AI 盒子或开发板上推理,关键点序列和判定结果留在本地,只有触发告警时才推出一段裁剪后的截图或者短视频。关于低功耗端侧怎么跑,第 7 节会有具体的帧率和功耗数据。
2. 先吃透 YOLOv8-Pose 的网络结构,才能用好关键点
2.1 Backbone-Neck-Head 三个组件各干了什么
用 YOLOv8-Pose 做项目,可以不用背论文,但至少要理解它为什么能稳定输出关键点。
首先是 Backbone,负责从原始图像里提取多尺度特征。YOLOv8-Pose 用的是带 C2f 模块的 CSPDarknet。C2f 模块可以理解成把输入特征图拆成两个分支,一个分支穿过多个 Bottleneck 结构,另一个分支直接跳过,最后再拼接融合。这样的好处是减少计算量的同时保证了梯度流动,让远处的小目标也能留下足够丰富的语义特征。
然后是 Neck,负责把不同尺度的特征融合。YOLOv8-Pose 用的是 PAN-FPN 结构,自顶向下传递语义信息,自底向上补充位置信息。多人姿态估计有个常见场景:画面里一个老人站在远处,另一个护工蹲在近处,目标尺度差异很大,PAN-FPN 的多尺度融合就是为这种场景准备的。
最后是 Head,也就是输出端。YOLOv8-Pose 的 Head 是解耦结构,目标分类、边框回归、关键点回归各走各的分支,最后输出 shape 为(batch, 4 + 1 + num_classes + 51)的特征图。这里的 51 就是 17 个关键点乘以 3(x 坐标、y 坐标、置信度)。理解了这个输出格式,后处理的时候才知道怎么把张量拆成可用的数据。
2.2 17 个关键点的坐标系,跌倒检测只用其中一部分
COCO 格式的 17 个关键点定义是:0 鼻子,1/2 左右眼,3/4 左右耳,5/6 左右肩,7/8 左右肘,9/10 左右腕,11/12 左右髋,13/14 左右膝,15/16 左右踝。
跌倒检测不需要全用,我主要取三类:头部(鼻子或耳朵)、髋部(左右髋的平均)、脚踝(左右踝取更可靠的一侧)。这三个点基本就能描述“站立—坠落—倒地”的完整过程。
这里有一个特别容易踩的坑:模型输出的关键点是归一化坐标,范围在 0 到 1 之间,需要乘回原图宽高才能得到像素坐标。如果直接在归一化坐标上算阈值,一旦摄像头分辨率变化,所有阈值都要重新标定。我惯用的做法是统一乘回原图尺寸,再用人的身高做内部归一化,后面第 6 节会具体讲。
2.3 预训练权重决定了你要花多少数据才能收敛
YOLOv8-Pose 官方提供了yolov8n-pose.pt、yolov8s-pose.pt、yolov8m-pose.pt等预训练权重,都在 COCO 数据集上训过。但这里有个隐蔽问题:COCO 里的人物姿态大多是站立、行走、坐姿,几乎没有“跌倒后躺在地上”的样本。我一开始直接拿预训练权重跑自建跌倒数据集,发现站立和走路时关键点很准,人一旦躺下,小腿和手臂的关键点经常错位。
原因不是模型坏了,而是预训练分布里很少见到“人横躺且身体折叠”的姿态。解决方法是带着预训练权重做微调,而不是从头训练。用yolov8n-pose.pt做起点,自己的跌倒数据准备一千张以上,微调几十个 epoch,躺姿下的关键点就能打准。这个经验可以推广到其它姿态项目:预训练模型解决“常见场景”,微调解决“项目里的特殊姿态”。
3. 跌倒在关键点数据上长什么样:特征与先验规则
3.1 先把“跌倒”定义成可计算的问题
在写规则之前,我先把“跌倒”翻译成关键点语言。一个可计算的跌倒定义是:人体中心点从高位快速下落到低位,躯干接近水平,且在一定时间内没有恢复站立。
拆解成三件事就是:
- 中心点 y 坐标发生突变(坠落)
- 头、髋、踝三个点几乎在同一水平线(触地)
- 这个水平姿态持续数秒(静止不动或只有微动)
这里的中心点我取左右髋关键点的平均值,因为髋部在跌倒过程中位移最明显,而且比腿部关键点稳定,遮挡概率低。头部取鼻子或耳朵,脚踝取左右踝中置信度更高的那一侧。
3.2 几何特征公式,这些就是规则层的输入
我整理了自己在项目里实际使用的特征,每个都有明确的计算方式:
- 髋部中心高度:
h_hip = (y_11 + y_12) / 2。站姿下约占图像高度的 50%~60%,躺姿下会被压到 10%~30%。 - 头踝垂直距离:
d_head_ankle = |y_0 - min(y_15, y_16)|。站立时这个值接近身高,躺平时接近 0。 - 躯干倾角:
angle = atan2(|y_shoulder_mid - y_hip_mid|, |x_shoulder_mid - x_hip_mid|)。躯干竖直时接近 90°,躺平时接近 0°。 - 人体框宽高比:
ratio = w / h。站立时 0.3~0.5,躺平时通常大于 1.0。 - 髋部垂直速度:
v_y = (h_hip(t) - h_hip(t-1)) / dt。单位是像素每秒,跌倒瞬间会出现极大的负值。
这些特征组合起来,单帧就能给出“当前是否处于跌倒后状态”的粗判断。注意,任何单帧特征都可能有歧义,所以时序规则才是主角。
3.3 为什么单帧判断必然误报:弯腰和跌倒的前半段很像
弯腰捡东西时,髋部中心也会下降,躯干倾角也会变大,宽高比也会变小——这些特征和跌倒的前半段几乎一模一样。但弯腰和跌倒有两个关键差异:一是下降速度慢得多,二是弯腰后很快会恢复站立。
所以规则层不能只问“当前帧像不像摔倒”,还要问“过去 0.5 秒有没有发生快速坠落”“接下来几秒有没有恢复”。这就是时序状态机比单帧分类器更适合做跌倒检测的根本原因:它把时间信息用起来了。
4. 数据准备:公开数据集怎么用、自建数据怎么标
4.1 公开数据集别直接用,先看视角和动作分布
业界常用的几个跌倒数据集我基本都跑过一遍,各有各的限制:
| 数据集 | 内容 | 主要限制 |
|---|---|---|
| UR Fall Detection | 30 段跌倒 + 40 段日常活动,侧视角为主 | 人物少、背景单一,直接训练容易过拟合 |
| Le2i Fall Detection | 室内多场景跌倒视频 | 标注粒度粗,部分视频分辨率偏低 |
| NTU RGB+D | 大规模动作识别,包含 3D 骨架 | 深度相机采集,关键点分布与 2D 姿态估计不一致 |
我的做法是:公开数据集用来做预训练和规则调试,自建数据做最终微调和验证。直接拿公开数据集训完就上线,在真实家庭环境基本会翻车——墙角、沙发、茶几、宠物的样子都会干扰模型的判断。
4.2 自建数据采集的三个动作类别,比例怎么定
自建数据我建议覆盖三类,样本比例控制在 6:3:1 左右:
- 正常活动(约 60%):站立、行走、坐下、起身、弯腰、蹲下、躺沙发、穿鞋。
- 跌倒动作(约 30%):向前扑倒、侧向摔倒、后退摔倒、慢慢滑倒。
- 干扰动作(约 10%):猫狗经过、搬东西、关门、扫地被绊。
这些动作至少要覆盖两个摄像头视角:侧视角和斜俯视角各采一遍。正上方俯视虽然监控效果好,但关键点遮挡太严重,模型很难学好。我自己的项目里还专门加入了“扶着墙慢慢滑倒”这种慢速跌倒样本,因为真实场景里老人跌倒很少像年轻人那样猛摔,慢速滑倒才是常态。
4.3 关键点遮挡时的标注策略,一个细节决定模型上限
跌倒后身体经常发生自遮挡——手臂压在身下、腿被身体挡住。标注的时候我遵循三条原则:能准确判定的关键点标出来并标记为可见;被遮挡但能合理推断位置的关键点也标,但标记为被遮挡;完全看不见的关键点宁可空着也不要硬猜。
硬标出来的错误关键点坐标会在训练时给模型错误的监督信号,推理阶段的表现就是关键点抖动、坐标飘移,规则层再怎么做后处理都救不回来。数据增强方面,随机旋转 ±15°、水平翻转、Mosaic、HSV 亮度扰动我都开了,其中水平翻转对摄像头安装在不同侧面的场景特别有用。
5. 模型训练和前后处理:从 checkpoint 到低延迟推理
5.1 基于 Ultralytics 的训练配置,直接可抄
我用的是 ultralytics 官方库,数据集配置文件长这样:
# fall-pose.yaml path: ./datasets/fall train: images/train val: images/val kpt_shape: [17, 3] nc: 1 names: ['person']训练命令:
yolo train data=fall-pose.yaml model=yolov8n-pose.pt epochs=150 imgsz=640 batch=16 device=0几个参数的经验:输入分辨率首选 640×640,足够捕捉关键点细节,又不会把帧率拖垮。预训练权重从 n 版起步,先跑通全流程再考虑上 s 或 m。epoch 数不用死磕 150,配合早停看验证集 mAP 不涨就停。
训练集里跌倒样本和正常样本的比例不要差太远。我最初跌倒样本只占 15% 左右,结果模型把大部分躺姿当背景,漏报很严重。后来把跌倒样本补到 30% 以上,漏报才降到可接受水平。
5.2 推理加速:导出 TensorRT Engine 是必做的一步
模型训练完,导出成 TensorRT engine 非常关键。命令很简单:
yolo export model=best.pt format=engine device=0 half=Truehalf=True表示 FP16 推理,速度翻倍的同时精度损失很小。我在几种设备上实测过推理耗时:
| 设备 | 推理耗时 | 对应帧率 |
|---|---|---|
| RTX 4090 (FP16) | 约 2 ms | 300+ FPS |
| Jetson Orin Nano 8GB (FP16) | 约 30~40 ms | 25~33 FPS |
| Jetson Nano (FP16) | 约 80~120 ms | 8~12 FPS |
如果目标设备功耗预算非常紧张,还可以量化到 INT8,帧率会再上一个台阶。但 INT8 量化需要准备校准数据集,不然关键点坐标容易偏,我建议先把 FP16 跑通再看要不要继续压。
5.3 关键点后处理:置信度过滤和多目标跟踪
模型输出的 17 个关键点,第一步就是按置信度过滤。低于 0.3 的关键点不要参与几何特征计算,否则躺倒时手臂关键点乱飘,会把躯干倾角算得乱七八糟。
多人场景下,需要给每个目标分配一个稳定 ID。我用的 ByteTrack,配置比 DeepSORT 简单,也不需要额外训练行人重识别模型。跟踪到稳定 ID 之后,特征计算和规则判断都绑定在同一个 ID 上,否则画面里多一个人时整个逻辑就乱了。
另外一定要设置一个 ROI 区域:只有落在室内有效区域的人物才参与判断,门窗外路过的人、窗外汽车里影影绰绰的人形,全部直接过滤。这一步对降低误报的作用比调模型阈值大得多。
6. 跌倒判定规则与误报抑制:系统好不好用全看这一层
6.1 两级判定流程:先打分,再走状态机
我的判定分两级。第一级是帧级打分,每一帧计算当前目标是否处于“疑似跌倒后状态”,输出一个 0 到 1 的异常得分。第二级是时序状态机,以帧级得分为输入,在时间窗口内判断是否发生了完整的“坠落—触地—静止”过程。
状态机定义四个状态:Standing(正常)、Falling(坠落中)、Down(倒地)、Confirmed(确认告警)。每帧更新一次状态,满足条件才会迁移。这里最关键的设计原则是:状态迁移必须同时有“进入条件”和“退出条件”。Down 状态不能因为一帧关键点抖动就退回 Standing,要连续多帧满足恢复条件才算恢复,否则告警会被反复触发,彻底失去可信度。
6.2 特征阈值表和确认窗口的参考配置
我的默认配置如下,读者需要根据自己摄像头的安装高度做微调:
| 特征 | 阈值 | 含义 |
|---|---|---|
| 坠落速度 | 髋部 y 在 0.4 秒内下降超过参考身高的 25% | 触发 Falling 状态 |
| 躯干倾角 | 与水平面夹角小于 30° | 疑似倒地 |
| 头踝垂直距离 | 小于参考身高的 20% | 身体接近水平 |
| 倒地保持时间 | 超过 3~5 秒 | 触发 Confirmed,可调 |
参考身高怎么来?我取目标首次出现后前 30 帧的鼻子到脚踝平均距离,作为该个体在画面中的站立身高基准。这样不管是身高 1.5 米的老人还是 1.8 米的护工,也不管摄像头离人远近,阈值都能保持一致性。
坠落速度阈值用相对身高的比例而不是绝对像素,是为了让规则不随摄像头安装位置变化。如果摄像头装得高,同样的物理位移在画面里像素差会变小,绝对像素阈值就会失效。
6.3 误报最多的三个场景,以及我做的针对性抑制
我统计过自己测试集里的误报来源,排名前三的是:
- 弯腰捡东西、系鞋带
- 坐在沙发上刷手机
- 宠物在镜头前跑来跑去
弯腰和坐下的共同问题是姿态特征很像跌倒后期,但缺少“快速坠落”这个前置条件。所以我把 Falling 状态的触发作为硬性前提:没有检测到快速坠落,后面状态永远不会进入 Confirmed。宠物干扰则通过目标大小过滤解决:当检测框面积大于画面一定比例时,才认为是需要看护的人物目标,猫狗这种小面积目标直接跳过。
漏报方面,最常见的是慢速滑倒——老人扶着墙或柜子慢慢滑下去,坠落速度达不到阈值。针对这个场景,我增加了一条补充规则:髋部高度连续 3 秒低于参考身高的 30%,且躯干倾角持续小于 30°,也触发告警。这条规则会引入一定误报,比如老人坐在地上穿鞋,但相比慢速滑倒漏报,我宁愿接受可调整的误报。
6.4 用 LSTM 做时序增强,规则主投票、模型辅助
规则层已经能覆盖大多数场景,但为了处理更复杂的轨迹,我还试过一个增强方案:把 17 个关键点的归一化坐标按时间序列输入一个两层 LSTM,窗口长度 16 帧,输出“跌倒/正常”二分类。训练数据从自建视频里按 16 帧滑窗切片,正样本以“坠落点”为中心取前后窗口,负样本随机取正常活动片段。
实测下来,LSTM 对“快速弯腰后起身”“捡东西”这类伪跌倒的区分比纯规则好,但对“老人坐在地上很久没有起身”这种静止状态会误判——因为 LSTM 学到的是运动模式,静止躺地和静止坐地看起来很像。所以最终方案是规则层为主、LSTM 为辅助投票:两者都判定跌倒时才告警。这样误报率进一步压低,代价是增加少量漏报,但对误报容忍度低的家庭场景来说,这个交换是值得的。
7. 端到端系统落地:一个边缘盒子上的完整实现
7.1 硬件选型,以及一种更省功耗的运行模式
硬件选择取决于对帧率和功耗的要求。如果只是室内单人看护,不需要 30 FPS 连续跑——跌倒检测本来就该是低频事件。我建议走“低功耗守候模式”:默认以 1~2 FPS 的周期做检测,一旦触发 Falling 状态,立刻切换到满帧率进行确认。
我用过的 Jetson Orin Nano 8GB 在 640×640 输入下跑 YOLOv8n-pose 的 FP16 engine,守候模式平均功耗约 5~8W,确认模式约 10~15W,整体热量完全可控。这个方案也适合接入超低功耗的端侧 AI 视觉模块,按“检测—确认—告警—休眠”的节奏循环,而不是让设备 7×24 小时满载跑模型。
7.2 数据链路参考:从摄像头到告警推送
完整链路如下:
摄像头(RTSP/RTMP)→ FFmpeg/GStreamer 解码抽帧 → 缩放至 640×640 → YOLOv8-Pose 推理,得到检测框和关键点 → 按目标 ID 计算几何特征 → 规则状态机判断 → 触发告警时推送通知并保存事件片段。
告警通道我接过企业微信机器人、钉钉机器人和本地声光报警器。Webhook 方式最省事,一个 HTTP 请求就能把“卫生间 23:41 发生跌倒事件”连同一张关键点叠加图发出去。保存事件片段时,建议只保存告警前 5 秒到告警后 10 秒的裁剪画面,既保留现场证据,又把存储压力压得很低。
7.3 实测数据,以及两个进场前就要确认的坑
我自己的测试集上,正常光照、单人、侧视角摄像头下,召回率约 97%,误报率约每 24 小时 1~2 次。从发生跌倒到告警推送的端到端延迟约 4~6 秒,其中包含了 5 秒确认时间。如果觉得延迟长,可以把倒地保持时间从 5 秒调到 3 秒,代价是误报会略微增加。
最后提醒两个容易踩的坑,它们比模型本身更容易影响项目成败。一是摄像头安装高度不要低于 1.5 米,太低会让俯视角度过大,关键点遮挡严重,跌倒检测基本失效;二是夜间光线差时,必须保证摄像头支持红外或补光,否则关键点置信度会大幅下降,规则层所有阈值都变得不可靠。
我在实际部署过程中的体会是:模型排错和规则调优所占的时间至少是训练时间的五倍,真正决定系统能不能长期稳定运行的,是规则里的每一个阈值是否针对现场环境标定过。先用 YOLOv8-Pose 把骨架子打出来,再把特征阈值一条条调准,这套思路比一开始就追最新的网络结构要靠谱得多。