
1. 跌倒检测的难点不在检测在区分蹲下与摔倒1.1 场景需求的反推甲方真正要的不是框是报警判断做监控视觉项目久了会发现一个规律客户报的需求和实际要的东西经常是两回事。拿这套人员跌倒检测系统来说需求文档上写的是检测人员跌倒但到了现场沟通才发现普通行人检测器他们早就试过了也能检测到人却完全没办法区分一个人是摔倒了、蹲下了、还是单纯躺下睡觉。真正要解决的不是检测人而是判断行为状态。我这次做的项目主要覆盖养老机构和独居老人家庭两类场景。摄像头装在墙角离地2.5米左右斜向下俯视覆盖一个客厅或者双人病房。这类场景有几个共同特征室内家具多、遮挡频繁、光线不稳定黄昏和夜间尤其麻烦而且老人行动本来就慢很多起卧动作和跌倒的静态姿态长得非常像。比如蹲下捡东西如果镜头角度偏一点人在画面里的宽高比变化幅度其实比想象中大再比如从椅子上滑落坐地的过程前几帧和主动坐下的动作几乎无法区分。所以在设计算法之前必须先定义一个关键问题跌倒检测到底检测什么我的答案是检测一个状态变化过程而不是检测一个静态的人躺在地上的姿态。这个思路决定了后面所有技术选型的方向。1.2 单帧视觉上跌倒的本质是形态突变从画面特征来看一个能稳定站立的人检测框通常高度大于宽度宽高比大约在0.4到0.6之间而人倒地后检测框会变成宽度远大于高度宽高比可能直接翻到1.8甚至2.5以上同时检测框的中心高度会显著下移。这是最直接的静态特征。还有一个容易被忽略的特征是下落过程中的速度突变。人在非故意跌倒时从站立姿态到接触地面基本发生在0.5秒到1秒内头部和躯干在画面中的位移速度远超正常行走或者蹲下的速度。但速度特征必须靠多帧计算如果框架里没有时序概念单帧模型只能依赖形态特征和上下文信息兜底。此外跌倒样本里通常伴随一条隐含规律人在跌倒后往往会保持一段时间的静止或低幅度挣扎状态不会立刻站起来。这个特性在报警策略上特别有价值它允许我们用一个延迟触发机制来换取误报率的大幅下降。后面我在模型结构里专门设计了一个轻量级的时序投票模块就是基于这个观察。1.3 通用检测器在跌倒场景下的三个硬伤第一通用检测器输出的是人的框不区分行为状态哪怕分类头里有person这一个类别它也只是一个粗粒度语义标签根本没法回答这个人状态是否安全的问题。第二通用检测器的训练数据分布和跌倒场景差异太大。日常数据集里的行人大多是站立、行走、骑车等常规姿态跌倒样本占比极低模型对于横躺、蜷缩、形态扭曲的人体几乎没有先验。第三姿态估计方案在部分遮挡和俯视角度下非常脆弱。跌倒时人体会大面积接触地面膝盖、肘部、面部经常互相遮挡加上椅子和茶几遮挡关键点丢失情况严重姿态骨架残缺后整个行为判断逻辑基本就废了。所以最终的选型方向很明确以通用目标检测器为底座在框级特征上做针对性的分类叠加用检测框的宽高比、中心点位置、多帧变化趋势这些信息去拟合跌倒行为特征。这条路在工程上更稳也与接下来要说的模型选型逻辑一脉相承。2. 基线模型选型复盘从YOLO和姿态估计绕回Faster R-CNN的原因2.1 单阶段、双阶段和姿态方案的一次横向比较我在项目早期其实把三条技术路线都过了一遍单阶段检测器YOLO系速度确实快在边缘设备上轻松跑到实时帧率但在小目标和遮挡目标的定位精度上明显弱于双阶段方法。跌倒场景中经常出现半个身体被沙发挡住的情形这种样本在单阶段模型里很容易漏检。姿态估计方案前面说了俯视角度下关键点遮挡严重不好用。只在侧面视角、人体相对完整时才可靠不符合这个项目的安装约束。双阶段检测器Faster R-CNN系速度慢一些但RPN会先生成大量候选区域再做逐区域分类对遮挡、小目标、极端姿态的容错能力明显高而且分类头和回归头分离后期针对跌倒类别做优化时能改动的空间更大。跌倒检测属于典型的高代价事件漏检一次跌倒的后果远比多花几十毫秒推理严重得多。这个场景天然需要牺牲帧率换召回率所以双阶段方案一下子就变成最优解了。2.2 为什么用Faster R-CNN而不是另外几类双阶段模型Faster R-CNN的RPN模块把候选框生成和区域分类耦合进同一个网络共享权重、端到端训练这是它相比老式选择性搜索方案的最大优势。实际使用中RPN的召回率直接决定了最终模型对跌倒样本的敏感度所以我格外关注RPN的Anchor设计这一部分我在下一章会详细写。从硬件指标看原始Faster R-CNN配上ResNet-50和FPN在单张主流显卡上单帧推理大约40到60毫秒在边缘推理引擎优化后可以压到30毫秒上下。对于跌倒报警场景来说这个速度完全够用——人的跌倒过程至少有0.5秒以上预警延迟1秒之内都具备救助意义不需要像自动驾驶那样追求毫秒级响应。2.3 基线网络的结构配置我选的基线结构是ResNet-50作为骨干网络加上FPN后面接标准RPN和两层的检测头。原始模型的输出类别数是80我需要把它改成两个类别正常状态的person和跌倒状态的fall。初始权重用COCO预训练模型做迁移学习这一步很重要因为自己从头训练一个双阶段检测器数据量不够的话收敛速度极慢泛化能力也差。这里有一个细节要注意修改输出类别后最后的全连接层维度变了加载预训练权重时不能直接把整个head都load进来否则参数形状不匹配。我当时的处理是冻结骨干和RPN的权重只随机初始化最后的分类/回归层先跑10个epoch让新层收敛再全网络一起微调。这个做法比初始化就全量微调稳定得多也避免了一开始梯度震荡导致的loss不降问题。3. 三个核心改进Anchor重设计、多层特征融合与时序后处理3.1 基于K-means聚类重设计Anchor尺寸分布Faster R-CNN原版的Anchor是按9种比例在每层特征图上生成的默认比例通常覆盖了1:1、1:2、2:1这几类宽高比。用于通用目标检测时没有问题但跌倒场景的数据分布很不一样站立时人体框高大于宽跌倒后宽大于高而且由于俯视镜头的透视畸变离摄像头近的人比远处的人大很多同一个姿态在画面不同位置的尺度差异也非常明显。我把训练集所有跌倒目标框的坐标拿出来做了宽高统计结果宽高分布明显呈双峰结构一个峰是站立状态的纵向框高宽比大约1.6到2.2另一个峰是倒地状态的横向框宽高比大约1.8到3.0。直接用原版Anchor后一个峰的召回率会偏低因为RPN生成的候选框大多偏向纵向。改进方案是跑一次基于IoU距离的K-means聚类把训练集里所有人形框含正常和跌倒聚成9个簇用簇中心代表新的Anchor宽高比然后按尺寸大小分配到FPN的不同层。野外实测效果很直接因为候选框更贴合真实目标RPN阶段需要的候选框数量甚至可以适度下调减少了后面检测头的计算压力推理速度反而没有因为结构变复杂而明显下降。3.2 特征金字塔的基础上叠加了一条自下而上的路径原版FPN的top-down路径只做了从上往下的语义传递高层语义信息传给浅层。问题在于跌倒目标的检测需要两样东西同时在线浅层的高分辨率位置信息用来精确定位人的轮廓高层抽象的语义信息用来判断这个姿态是不是跌倒状态。但如果只靠FPN的top-down单向传递浅层特征里的细节纹理在逐层传递中被稀释掉了直接后果是检出框的贴合度差尤其对蜷缩、弓背这种边缘形态。我的做法是在标准FPN之外对称地加了一条bottom-up通路让浅层的位置细节也往深层聚合——形式上类似PANet的结构把浅层的强定位信息和深层的强语义信息做一个双向融合。检测头同时读取多个层级的输出最后融合后的特征做分类和回归。消融实验显示这条结构改进给mAP带来了约4到5个百分点的提升特别是对小体积的远端跌倒目标如摄像头斜对角位置的人检出率改善明显。3.3 时序投票模块用3帧判决替代单帧硬分类单帧的跌倒检测必然伴随噪声因为从视觉上下蹲瞬间和跌倒前倾瞬间的某一帧可能长得完全一样。解决这类问题的工业级手段不是把单帧分类器练得无限强而是引入帧间关联和时间连续性判断。我在模型后处理阶段加了一个非常轻量的模块核心逻辑只有三句话对相邻帧检测出的person框和fall框做IoU匹配匹配成功则视为同一个目标。连续3帧内同一目标的fall置信度稳定超过0.6才判定为一次真正的跌倒事件。报警触发后系统会等待1到2秒再做最终确认确认期间如果检测框消失人已经站起来则自动取消报警。这个设计不需要训练额外的时序网络完全基于检测框后处理实现CPU上也能跑成本几乎为零。它的价值是把误报率从一个不可用的水平压到了可接受的水平实测数据中加了时序模块后误报率下降了约70%而召回率几乎没有损失。代价是报警延迟增加了大约0.3到0.5秒在跌倒救助场景中完全在容忍范围内。4. 数据工程跌倒样本的采集、标注规范与难例挖掘4.1 公开数据集与自采样本的搭配策略跌倒检测不像行人检测那样有现成的海量数据公开可用的跌倒数据集规模都不大视角类型也比较单一。我从公开渠道收集了若干跌倒相关的视频片段作为基座数据大约覆盖了正面、侧面、斜俯视几个常用视角但数量和多样性都远远不足以支撑训练。所以自采数据成了重头戏。我当时的做法是找一个空房间布置成客厅环境用模拟人偶摆放各种跌倒后的静态姿势正躺、侧卧、蜷缩、半倒在沙发边再用志愿者模拟从站立到跌倒的动态过程。志愿者不用真的摔伤可以在接近地面时用手撑地放慢速度前半段的加速下坠形态和真实跌倒几乎一致后段的着地姿态由模拟人偶补拍两者在训练时按帧混合使用。最终数据规模大约是两万张含人的图像中跌倒正样本约6000张覆盖室内多角度混合了白天、黄昏、夜间开灯三种光照条件。如果项目预算允许建议再增加真实老年人跌倒的视频片段因为年轻志愿者的跌倒动作在速度和形态上和老人有明显差异。4.2 什么是跌倒标注规范与框体定义数据标注是这个项目里最容易被低估的环节。标注规范如果不提前定清楚后面训练出来的模型会在边界行为上表现得很混乱。我最终采用的规范是fall类别只标身体已经与地面或床面发生大面积接触或者身体主干轴线与地面夹角小于45度的状态。下蹲、半蹲、坐椅子、躺床休息即使看起来像跌倒也只标为person。跌倒发生的过渡帧即身体还在空中但已经明显失去平衡、倾斜角度很大的帧也归为fall但置信度标注为弱标签让模型知道这些帧是模糊地带。对于遮挡严重的跌倒目标只要完整检测框内包含超过一半的身体主干就正常标注只露出一条腿或一只手的碎片不标注。这个规范相比随意标注要严格得多但训练出的模型边界行为非常干净部署后蹲下误报跌倒的比例低了很多。标注时用的工具是开源标注工具直接导出成通用检测数据集格式为了统一类别ID我把person设为1、fall设为2训练时强制忽略官方背景类别。4.3 难例挖掘与样本均衡第一版模型跑起来之后误报最严重的不是背景杂物而是两类像跌倒但不是跌倒的目标蹲下捡东西的人以及从坐姿突然站起来的人站起来瞬间身体轴线的倾斜角度变化和跌倒前倾太像了。这些误报样本被专门收集出来单独打标后加入训练集让分类器重点学习这些难例的判别边界。另外一个非常容易踩的坑是时间相邻帧的样本重复度太高。直接从视频连续抽帧前后几帧的形态几乎一样模型会在重复样本上过拟合在真正的新场景上表现反而差。我的做法是每段视频每隔10帧抽取一帧作为训练样本并用关键帧状态的切换站立帧、起势帧、倒下帧、着地帧对样本做分层抽样保证每种状态都有覆盖。数据增强上也有一点要特别提醒垂直翻转不能用。把一张站立的人垂直翻转画面里就变成倒立的人姿态完全不符合物理常识水平翻转可以用能扩展跌倒方向左倒/右倒的多样性。此外还可以做随机亮度和对比度的抖动模拟不同时间的室内光照变化这对夜间场景的鲁棒性帮助尤其明显。5. 训练配置、评测指标与改进前后的实测对比5.1 超参设置与训练流程训练用了一张24GB显存的主流GPU深度学习框架用的是PyTorch检测模型基于常见的开源检测框架搭建。输入尺寸方面长边限制在1333像素短边限制在800像素在这个分辨率下跌倒目标的细节足够清晰同时不至于让推理速度掉出可用范围。优化器选SGDmomentum设为0.9初始学习率0.02批大小8。学习率采用带warmup的余弦退火策略前500步做warmup避免早期震荡总共训练80个epoch。骨干网络和FPN部分用COCO预训练权重初始化但新加的特征融合分支和修改后的分类头使用较低的初始学习率约0.002防止预训练权重被破坏。一轮完整的训练时间大约是18个小时。在这个训练配置下loss曲线通常在30个epoch左右开始明显下降50个epoch稳定后续epoch主要是边界样本的拟合。如果显存紧张优先缩小输入尺寸而不是减小batch因为小batch在BN层的统计估计上会更敏感。5.2 评测方法不要只看mAP盯住召回率和误报率通用目标检测社区习惯看mAP0.5和mAP0.5:0.95但跌倒检测项目必须额外关注两个指标跌倒召回率和每小时误报次数。前者关系到真实报警的灵敏度后者关系到整个系统在业务上能不能落地。我把测试集按场景切成了三类单一通畅场景、带家具遮挡场景、夜间光照场景。各模型版本在测试集上的表现对比如下模型版本mAP0.5跌倒召回率单帧推理耗时误报次数/小时原始Faster R-CNN基线0.7478.5%58ms2.4基线 Anchor重设计0.7984.2%55ms1.8基线 Anchor 特征融合0.8490.1%61ms1.1完整模型含时序模块0.8589.7%62ms0.4注意表格里最后一行加时序模块后召回率反而比上一行略低了一点因为个别倾斜程度处于模糊边界的样本在连续3帧判定中没通过。但从业务角度看这是完全合理的交换——少报一个模糊边界样本换来误报率降低六成以上报警系统的可用性大幅提升。5.3 典型失败案例和应对在测试集上我专门做了一次badcase分析把漏检和误报的样本全部摊开发现三处高发点第一跌倒发生的瞬间运动模糊。跌倒速度越快单帧画面里身体边缘的拖影越严重边界框回归就不稳定。这个问题的缓解方式是数据增强中叠加随机运动模糊让模型提前适应模糊的身体算跌倒。 第二老人坐在床边双腿垂地的姿态。从斜俯视视角看这种状态和半跌倒在宽高比上高度重叠。我的处理是在难例集中大量增加床边坐姿样本让分类头学会用人体中心高度和地面参照物的相对位置来区分两者。 第三有轮椅或助行器的场景。金属框架和人体在图像上产生大量交叉边缘检测框很容易被带歪。这是纯数据问题只能靠现场自采样本补充没有捷径。6. 部署阶段绕不开的量化加速、帧率分配与误报处置6.1 模型导出与推理加速的取舍训练完的PyTorch模型不能直接上边缘设备我们的处理流程是先导出成ONNX再用边缘推理引擎做转换和优化。这里有一个重要的经验FP16量化基本无损精度误差在0.5个百分点以内但推理速度能提升约40%INT8量化速度快一半但精度可能掉1到2个点对跌倒这种小目标检测来说掉点主要出现在远距离小目标上。所以我的建议是算力允许时优先用FP16只有在设备算力实在不够的情况下再用INT8而且INT8量化必须用专门的校准集来做校准集要覆盖各种光照和遮挡情况否则会导致某些场景下的召回率断崖式下跌。在项目中实测FP16模型在边缘设备上单帧推理约35毫秒INT8约22毫秒对单路视频来说都足以保证每秒25帧的实时链路。6.2 多路视频流的帧率分配策略这套系统实际要同时接8路摄像头如果每路都全帧率做检测边缘设备的算力直接打满跑不动。我的做法是把检测做成一个帧分级处理的流程第一级是轻量的运动检测每隔一帧计算画面差异只有画面存在显著变化的通道才送入检测模型。画面完全静止的通道比如老人长时间坐在同一个位置看书可以大幅降低检测频率节省计算资源。 第二级是当RPN阶段出现了fall类别的候选框时系统自动切换到该通道的优先处理模式把该路摄像头的检测频率提升到最高并进入时序确认逻辑。 第三级是检测出事件后把报警信息推送业务平台同时保存报警前后各10秒的视频片段用于人工复检和证据留存。这套策略下来8路视频同时在线时的平均推理资源占用大约只有满载的40%重要事件的响应速度反而更快了因为算力被动态调度到了真正需要关注的通道上。6.3 报警业务的兜底设计模型永远会有失误所以在业务层面必须留兜底。我在这套系统里做了两个机制一个是延迟确认。检测到疑似跌倒后系统进入确认状态不直接触发报警而是等待时序投票模块的结果。如果确认期间目标移动恢复正常比如其实只是蹲下又站起来了报警自动撤销。这个机制能挡住大部分瞬时误报代价是报警延迟约0.5秒。另一个是事件回看与人工复核。所有触发报警的事件都附带一段视频片段阈值调参时以这些历史样本为准做新一轮难例挖掘扩充训练集。换句话说这个系统具备一个持续进化的闭环现场出现的每一个误报和漏报都会沉淀成下一个版本模型的训练数据。最后说一个项目经理不会告诉你、但做这类项目早晚会碰上的实话整个项目的工期里训练模型只占一小部分真正消耗时间的其实是标注规范的反复打磨、现场场景的样本采集和部署后误报的持续调优。模型结构的改进能带来精度上限但数据质量才决定系统在真实环境里到底能不能用。希望这套从选型到改进再到部署的完整路径能帮你少走几步冤枉路。