☰
基于YOLO26的摔倒智能检测系统设计与工程实战
2026/10/22 8:22:37 网站建设 项目流程

先交代一下背景。上个月有个做安防集成的朋友找我,说他们接了一个养老机构的夜间值守需求,十几个摄像头对着走廊和活动室,值班员一个人盯不过来,老人摔倒没人能第一时间发现。他问能不能用一个基于 YOLO26 的摔倒智能检测系统,把“人摔了”这个事件自动识别出来,同时要一份中英文双版的说明文档,方便他们后续对接海外项目。我花了两周把整套东西搭了起来,从数据准备、模型选型到摔倒判定逻辑、告警推送,再到中英文界面切换,全部跑通。这篇文章就把整个系统的设计思路、核心代码和我在实操里踩过的坑一次性讲清楚,给准备做类似项目的人一个可以直接参照的完整方案。

这个项目适合谁看?三类人:一是做计算机视觉毕设或者课程项目的学生,YOLO系列本身就是 CV 入门最常用的检测底座,摔倒检测又是一个非常典型的“检测+行为判定”复合任务,做完整个脉络就通了;二是做养老、康养、安防信息化的工程师,需要一个能落地而非停留在 Demo 的报警系统;三是想在边缘设备上部署检测服务的开发者,这里面涉及的模型导出、量化、延迟优化同样通用。

1. 这个项目到底在解决什么问题

1.1 摔倒检测的难点不在“检测”,在“判断”

很多人一听“摔倒检测”就觉得核心是训练一个模型识别摔倒动作,这个理解不完全对。目标检测模型能告诉你“这里有人”“这里有个物体”,但摔倒这件事牵扯到连续帧里的姿态变化、空间关系、时间尺度,单一帧的检测结果根本不足以支撑判断。

拿实际场景举例:一个老人蹲下捡东西,单帧画面里人形变矮、变宽,检测框的宽高比和摔倒时非常接近;又比如老人坐在轮椅上打盹,身体歪向一侧,单帧看起来也像摔倒。如果只靠检测模型分类,这两种情况都会触发大量误报。真正的难点在于如何把连续若干帧的检测结果组织起来,用一套可靠的规则或者时序逻辑区分“真的摔了”“正在坐下”“蹲下”“躺下休息”这些高度相似的视觉状态。

所以这个项目的检测底座虽然叫 YOLO26,但它只是整个系统的感知前端,真正的负责“摔倒”判断的逻辑在检测框的后处理层。理解这一点,你就抓住了整个系统的关键。

1.2 为什么要拿 YOLO26 当底座

先解释一下选型。目前开源社区里 YOLO 系列是目标检测领域迭代最频繁、生态最完整的模型家族之一,从早期版本一路发展到 YOLO26,到这一代在多尺度特征融合、可变形卷积、训练策略和推理效率上都相对成熟。我在选型时做了几组对照实验:同样一批自采数据,用上一代的小体量模型和 YOLO26 的小体量版本分别训练,YOLO26 在自建验证集上的检测精度和召回都有提升,尤其在“远距离小尺寸人体”这个糟糕场景上表现更稳。

选 YOLO26 还有三个现实理由。第一,它的工程生态完善,PyTorch 权重导出 ONNX、TensorRT、OpenVINO 都有现成路径,后面要压推理速度很顺手。第二,它内置的模型体量从轻量到高精度分了好几个档位,我可以在开发期用高精度模型保证效果,部署期换轻量模型跑边缘设备。第三,中英文双版这种需求本质上只是工程层的东西,不需要换模型,同一个推理底座可以同时支撑两套语言逻辑,整套架构不用推倒重来。

1.3 中英文双版到底是什么意思

这里要澄清一下“中英文双版”在我这个项目里的定义。它不是说写两套代码,而是同一套工程,通过配置文件和语言字典,在中文界面、英文界面之间一键切换。告警内容、前端展示、日志输出的文案全部走语言包,模型权重、推理逻辑、检测结果完全共用。

这样做的原因很实际。我朋友那边对接的养老机构有部分外籍护理人员,值班界面如果只出中文,对方使用门槛很高;而海外项目交付时,源码里到处是中文注释和硬编码文案也很难看。用语言层隔离之后,交付的时候只需要把 i18n 目录下的语言文件替换或新增,就能快速出对应语言的版本,不需要动任何业务代码。

2. 整体技术方案与数据准备

2.1 系统流水线设计:检测、跟踪、判定、告警

整个系统的数据处理流程是四段式:目标检测 -> 目标跟踪 -> 摔倒判定 -> 告警输出。用一张简单的流水线说明就是:摄像头或视频文件逐帧输入,YOLO26 在每帧上跑出人体检测框,然后把检测框交给目标跟踪器,跟踪器负责给同一个人的框分配稳定的 ID,接着摔倒判定模块读取每个 ID 的历史坐标序列,判断是否满足摔倒的时空特征,最后满足条件就在画面上打标,并向外推送告警消息。

目标跟踪这一层非常关键,很多人做摔倒检测会忽略它。如果每帧单独看检测框,你无法知道这一帧的框和上一帧的框是不是同一个人,摔倒判定就无从谈起。我用的跟踪器是基于运动和行为特征匹配的轻量方案,CPU 上也能跑,不依赖额外的重识别模型,保证整套系统在普通办公电脑上就能流畅演示。

2.2 数据集与标注:别只靠公开数据

公开的跌倒检测数据集我调研过好几个,它们有一个共性问题:拍摄视角大多集中在侧视角、正面视角,光照情况单一,场景干净。但真实养老机构里摄像头通常装在走廊天花板或墙壁高处,是俯视视角,而且夜间灯光昏暗,还有轮椅、助行器、绿植遮挡。直接用公开数据集训练出来的模型,在真实场景里的表现会明显缩水。

我的做法是混合式数据构建。基础部分使用公开的跌倒样本,但控制占比不超过一半;另一半通过自采和合成的方式补充。自采就是找朋友帮忙,在办公室、走廊、会议室模拟正常行走、弯腰、蹲下、坐下和摔倒动作,用普通手机从高角度录制;合成部分是把公开视频做透视变换、亮度扰动、加噪声,模拟俯视和夜间效果。最终得到一个包含正常站立、行走、蹲下、坐下、平躺、摔倒共六类行为的视频片段库,然后逐帧抽取关键帧,只标注 person 一种类别。

这里有一个值得强调的标注经验:做摔倒检测,不建议直接训练一个“摔倒”类别。摔倒姿态和蹲下、躺下在像素层面高度相似,标注一致性很难保证,类别内部差异又大,模型容易学混乱。更稳妥的策略是只检测“人”,把“是否摔倒”交给后级的时序判定逻辑去处理。这个思路一开始可能觉得绕,但它大大降低了训练难度,也提高了系统在不同场景下的泛化能力。

2.3 摔倒判定的核心逻辑与代码实现

摔倒判定的设计我用的是“几何特征 + 时序稳定性”方案。核心提取三个特征:人体检测框的宽高比、检测框中心点的垂直位置变化、检测框高度与宽度在连续帧里的变化趋势。

人在正常站立时,检测框的高度明显大于宽度,宽高比小于 1;摔倒或躺下后,宽度反超高度,宽高比会明显大于 1。这是一个非常直观的信号。但只靠宽高比不够,因为弯腰、蹲下也会有接近的框形。所以我加了两条约束:第一条是“姿态异常持续帧数”,要求宽高比倒置的状态在连续 N 帧中保持,避免弯腰捡东西这种瞬时状态触发报警;第二条是“中心点位移特征”,摔倒通常伴随人体中心点的高度快速下降,或者中心点位置在短时间内发生剧烈移动。综合这两类信号之后,误报率能压到比较合理的水平。

下面给出一段核心判定逻辑的关键实现,代码结构按工程实际情况简化过,但主干完全一致:

# fall_judger.py # 依赖:tracker 输出的 person_id 对应的历史检测框队列 FALL_RATIO_THRESHOLD = 1.2 # 宽高比阈值,框宽/框高大于该值视为姿态异常 REQUIRED_FRAMES = 8 # 姿态异常需要持续满足的帧数 CENTER_DROP_RATIO = 0.35 # 中心点高度相对历史均值下降比例 CONFIRM_FRAMES = 4 # 从姿态异常到确认摔倒需要的连续帧数 class FallJudger: def __init__(self): self.history = {} # person_id -> deque of (center_y, height, width, frame_id) def update(self, person_id, bbox, frame_id): x1, y1, x2, y2 = bbox h = y2 - y1 w = x2 - x1 center_y = (y1 + y2) / 2 if person_id not in self.history: self.history[person_id] = deque(maxlen=32) self.history[person_id].append((center_y, h, w, frame_id)) return self._judge(person_id) def _judge(self, person_id): seq = list(self.history[person_id]) if len(seq) < REQUIRED_FRAMES: return False, 0 recent = seq[-REQUIRED_FRAMES:] # 条件1:近几帧宽高比持续异常 posture_abnormal = all(w / max(h, 1e-6) > FALL_RATIO_THRESHOLD for _, h, w, _ in recent) # 条件2:中心点高度相比更早的均值有明显下降 earlier = seq[:-REQUIRED_FRAMES] if not earlier: return False, 0 baseline_center_y = sum(item[0] for item in earlier) / len(earlier) recent_center_y = sum(item[0] for item in recent) / len(recent) center_dropped = (recent_center_y - baseline_center_y) > \ CENTER_DROP_RATIO * baseline_center_y if posture_abnormal and center_dropped: return True, len(seq) return False, 0

再解释一下这里面的经验取值。FALL_RATIO_THRESHOLD取 1.2,而不是 1.0,是为了留出安全余量;正常站立时人体框宽高比通常在 0.4 到 0.8 之间,取 1.2 已经能排除大部分正常姿态。REQUIRED_FRAMES和帧率相关,我演示时用的视频是 25 帧每秒,8 帧大约相当于要求异常姿态持续 0.3 秒以上。CENTER_DROP_RATIO取 0.35,意思是最近几帧的人体中心点高度,要比之前一段时间内的平均中心点低 35% 以上。这几个参数对不同摄像头安装高度、不同焦距是敏感的,安装位置变了之后一定要重新标定。

3. 中英文双版工程实现与关键代码

3.1 项目结构与模块划分

工程代码的目录组织直接影响维护成本。我按照“检测、跟踪、判定、展示、语言”五个职责拆分了模块,目录结构如下:

fall_detect_yolo26/ ├── configs/ │ ├── config.yaml # 全局配置:模型路径、置信度、判定参数 │ └── i18n.yaml # 中英文字典配置 ├── detector/ │ ├── yolo_detector.py # YOLO26 推理封装,输入帧,输出人体框 │ └── export_onnx.py # PyTorch 权重转 ONNX 的脚本 ├── tracker/ │ └── light_tracker.py # 轻量多目标跟踪,分配并维护 person_id ├── judger/ │ └── fall_judger.py # 摔倒判定逻辑 ├── ui/ │ ├── main_window.py # 桌面端/视频端展示与推流 │ └── overlay.py # 画面绘制,中英文标签渲染 ├── api/ │ ├── web_api.py # 告警推送 Webhook 封装 │ └── message_builder.py # 告警消息模板 └── run.py # 程序入口

这个结构的好处是每一层都能独立测试。比如在开发时我经常先单测fall_judger.py,用人工构造的检测框序列喂进去,看判定逻辑是否按预期触发,完全不需要启动摄像头和模型。

3.2 语言切换是怎么实现的

语言切换的核心不是翻译界面上的几个按钮,而是把所有面向用户输出的内容抽象成“键值对”。告警消息、画面上叠加显示的标签、终端提示、日志内容都走同一个字典读取接口。切换语言时,只需要改配置文件中的language字段。

看一下具体的实现思路:

# configs/i18n.py LANG_PACK = { "zh": { "app_title": "摔倒智能检测系统", "status_normal": "正常", "status_fall": "摔倒预警", "alert_message": "检测到摔倒事件,请立即前往查看", "fps_info": "帧率", }, "en": { "app_title": "Fall Detection System", "status_normal": "Normal", "status_fall": "Fall Alert", "alert_message": "Fall detected, please check immediately", "fps_info": "FPS", }, } class I18n: def __init__(self, lang="zh"): self.lang = lang self.pack = LANG_PACK.get(lang, LANG_PACK["zh"]) def t(self, key): return self.pack.get(key, key)

实际告警推送时,message_builder.py会根据当前语言配置把alert_message渲染成对应语言的内容,再通过 Webhook 推到企业微信、钉钉或者邮件网关。整个过程不干扰检测主循环,即使语言切换,检测状态也不中断。

3.3 推理引擎导出与加速

开发调试阶段可以直接用 PyTorch 推理,但演示稳定性差,显存占用高,而且换到没有 GPU 的电脑就寸步难行。所以我做了一步模型导出,把 YOLO26 的权重转为 ONNX 格式,让推理可以在 CPU 上运行,也方便后续用 TensorRT 进一步加速。

导出过程的几个关键点:输入尺寸我固定为 640x640,既保证人体检测效果,又不会让计算量失控;动态 batch 维度开启,方便后续接多路摄像头;模型的输出层我保留了原始的检测输出形式,在外部代码里做非极大值抑制,而不是把 NMS 也塞进 ONNX 图里,这样在换不同部署后端时更灵活。

python detector/export_onnx.py \ --weights weights/yolo26.pt \ --output weights/yolo26.onnx \ --imgsz 640 \ --batch-size 1 \ --dynamic-batch

转完之后用 ONNX Runtime 做 CPU 推理,在演示机上实测单帧延迟从 PyTorch 的 80 毫秒左右下降到 45 毫秒左右,对应的帧率从 12 帧提高到 20 帧以上。对于摔倒检测这种不用每帧都严格处理的场景,20 帧已经够用。

4. 实操部署与效果演示

4.1 环境安装与运行步骤

这套系统的依赖不算复杂,核心是三块:目标检测推理环境、跟踪和判定的轻量计算库、界面展示用的 GUI 库。我建议使用虚拟环境管理依赖,避免和系统全局 Python 环境互相污染。

安装依赖时最容易出问题的是 OpenCV 和 PyTorch 的版本组合。我的建议是:PyTorch 用 2.x 的稳定版,OpenCV 用opencv-python最新的 4.x 版,在 Python 3.10 环境下测试兼容性最佳。如果先装了 OpenCV 再装 PyTorch,有时会把 numpy 版本覆盖掉,导致运行时报警告甚至直接崩溃,顺序上建议先装 PyTorch,再装 OpenCV 和其他依赖。

运行入口是run.py,启动参数支持视频文件和摄像头两种输入源:

# 视频文件推理(用于演示和测试) python run.py --source demo_video.mp4 --lang zh --conf 0.5 # 摄像头实时推理(用于现场部署) python run.py --source 0 --lang en --conf 0.4

启动后系统会实时显示检测画面,正常姿态的人框为绿色,触发摔倒预后的框变为红色,同时画面左上角显示当前帧率和语言状态。如果配置了 Webhook,告警信息会自动推送到指定接收端。

4.2 关键参数怎么调

这里列一份我在反复测试中得出的参数参考表。YOLO26 推理时的置信度阈值对系统行为影响很大,阈值设高了漏检,设低了误检。摔倒判定模块的三个参数同样关键,如果把宽高比阈值从 1.2 降到 0.9,系统就会把大量弯腰、坐下动作当成摔倒;如果把持续帧数从 8 帧提高到 20 帧,真实摔倒后报警会延迟接近一秒,这在紧急场景里不可接受。参数表如下:

参数项推荐值设置倾向影响
检测置信度 conf0.4场景遮挡多则调低低则多误检,高则漏检
NMS IoU 阈值0.5人员密集则调低过高一框多报,过低丢框
宽高比阈值1.2摄像头越高越保守过小会导致蹲下误判
姿态异常持续帧数8视频帧率越高则调大过小导致瞬时动作误报
中心点下降比例0.35安装角度越斜则调大过小容易把坐下判成摔倒
告警冷却时间5 秒场景越敏感则调短控制同一事件重复告警次数

摄像头安装高度和角度一变,参数必须重新标定。我自己的做法是录一段包含正常行走、蹲下、坐下的 5 分钟视频,然后调参数让系统在这段视频上零误报,再换一段包含摔倒动作的视频,确认能及时触发报警。

4.3 演示录像与性能指标怎么测

演示效果不能只靠口头说,要拿出一组能说明问题的数据。我最常展示的指标有四个:检测帧率(FPS)、端到端延迟、检测召回率、误报频率。检测帧率就是系统处理视频流的实时速度;端到端延迟指从摔倒发生到系统画面变红、推送告警之间的时间差;召回率指在测试视频里,系统成功报出的摔倒次数占总真实摔倒次数的比例;误报频率则统计单位时间内把正常行为当成摔倒的次数。

演示录像我用了三段素材:一段是在办公室模拟的摔倒场景,一段是在走廊俯视角监控画面,还有一段是夜间的低光照模拟。结果在配置为中等档位的电脑上,视频输入的检测帧率稳定在 18 到 25 帧之间,端到端延迟大约在 1.2 到 2 秒,这里的延迟主要来自姿态异常需要持续确认的帧数要求。摔倒召回率在三段演示视频上达到了 100%,但这里必须说明测试视频数量有限,且动作是模拟的,这个指标只能说明系统链路是通的,真实效果必须靠现场数据长期验证。误报频率在正常行走、弯腰、坐下的测试片段中控制在一小时内一次以下,后续还有优化空间。

另外录制演示视频时,画面里一定要叠加足够的可视化信息,包括检测框、跟踪 ID、判定状态、帧率。这样做有两个作用:一是让观看者直观理解系统每一步在做什么;二是避免“播放一段录好的视频循环”带来的“效果造假”嫌疑,直接展示代码实时处理的结果更有说服力。

5. 常见问题与避坑清单

5.1 误报多、漏检多是哪里出了问题

误报和漏检是摔倒检测系统里最常见的两类问题,但它们的原因截然不同。误报多,十有八九是摔倒判定参数过于敏感,而不是检测模型出了问题。弯腰捡东西、蹲下系鞋带、坐姿偏斜都可能在单帧里表现出类似摔倒的宽高比,系统的持续帧数约束和中心点下降约束就是用来排除这些情况的。如果误报集中在某一种正常行为上,最好的办法是把这段行为录下来,回放时观察这些帧的检测框是什么形态,再针对性调整阈值。

漏检则要分两层看。第一层是模型没有检测出人,这种情况通常发生在远距离小目标、强逆光、严重遮挡时,解决办法是提高输入分辨率、开启多尺度推理,或者换更大体量的模型;第二层是人检测出来了,但摔倒判定没有触发,这种情况通常是参数约束过严,比如中心点下降比例设得太大,真实的摔倒位移没有达到触发阈值。

5.2 边缘设备推理慢怎么办

如果目标设备是边缘盒子或者工控机,推理速度会是绕不开的问题。我先说结论:优先做模型量化,再考虑换轻量模型,最后才是砍输入分辨率。量化是指把模型的浮点权重从 32 位压缩到 16 位甚至 8 位整数,推理速度提升明显。YOLO26 的导出路径支持 FP16 和 INT8 量化,INT8 需要准备一份校准数据集,否则精度损失可能比较明显。

还有一个现实经验:不要一上来就追求高帧率。摔倒检测对帧率的要求远低于动作识别,10 到 15 帧就能满足需求,真正重要的是延迟不能太高,也就是说从摔倒发生到告警推送之间的时间,不能因为排队处理积压帧而变得过长。如果发现处理速度跟不上输入帧率,与其压缩分辨率,不如主动丢帧,也就是每两帧处理一帧或每三帧处理一帧,这样能控制延迟在一个稳定区间内。

5.3 长期运行的稳定性问题

连续跑一周以上的部署场景下,稳定性往往比效果更棘手。我遇到过三个典型问题。第一个是检测框 ID 频繁跳变,跟踪器分不清同一个人的前后帧,导致摔倒判定所需的连续坐标序列被切断。解决办法是给跟踪器加一个短时记忆缓冲,允许 ID 在几帧内丢失后还能恢复,而不是立即生成新 ID。第二个是长时间运行后内存持续上涨,排查后发现是每帧的检测结果和历史队列在累积后没有被合理释放。这个问题通过固定历史队列长度上限解决,collections.deque的maxlen参数直接限制容量,超过上限自动丢弃旧数据。第三个是告警刷屏,一个摔倒事件在几秒内触发七八次推送,很影响使用体验。我加了告警冷却机制,同一个跟踪 ID 触发报警后,在冷却时间内不再重复推送,冷却时间建议设在 5 秒左右。

5.4 从开发到交付的额外忠告

最后说一个我在这类项目里反复体会到的经验:模型表现只是一个方面,系统的安装、配置、参数标定流程是否清晰,往往决定项目能不能真正落地。开发环境里效果再好,现场的人员、设备、环境一变,效果都会跟着变。交付时一定要附带简洁的参数标定指南,告诉对方摄像头装好之后,第一件事不是看效果,而是录一段现场正常活动的视频,把误报和漏报参数都标定一轮。否则维护人员被误报折腾几轮,系统就会被关掉,再好的算法也白搭。

我个人在多次调试后的体会是,YOLO26 这类目标检测模型为系统提供了可靠的上游感知,但真正让一个摔倒检测系统“可用”的,是判定逻辑、告警策略和现场标定这些看似不起眼的工程环节。建议你复制这套框架时,先把数据视频准备好,再逐个模块替换成自己的场景,排查每层环节是否正常运转,这样比自己从零堆代码要快得多。后续如果要做更深层的行为分析,还可以在 YOLO26 的基础上增加关键点分支或动作识别头,让系统不仅检测摔倒,还能识别走路不稳、长时间静止等风险状态,逐步扩展成更完整的照护预警平台。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询