基于 YOLO26 的跌倒检测预警系统:从模型到 Streamlit 全流程实战
关键词:YOLO26、跌倒检测、智慧养老、独居监护、目标检测、Streamlit、Ultralytics
一、背景
1.1 行业痛点
跌倒被称为老年人的"隐形杀手"——对 65 岁以上人群而言,一次无人发现的跌倒往往意味着错过最佳抢救窗口。但监护环节长期依赖人力,存在三个结构性难题:
- 人工盯屏不可持续:护士站一台监控常常对着多间病房,值班人员不可能 7×24 逐画面注视,漏看往往就是几分钟、甚至十几分钟的事;
- 事后查证滞后:传统视频方案只能回放录像,跌倒已经发生后才能发现,处置完全跟不上"黄金抢救时间";
- 独居监护无手段:老人独居场景下,家属与社区最需要的"跌倒即告警"能力恰恰最缺失,可穿戴手环又有佩戴率低、误触高的问题。
把摄像头 + AI 视觉感知接入监护场景后,用一台普通工控机就能 7×24 实时框出画面中的跌倒人员并给出置信度与位置,进而对接到护士站看板、家属短信 / 电话、社区告警平台。本项目就是这条路线下的一个完整落点:基于 YOLO26n,识别「跌倒」单类目标,并提供一个开箱即用的 Streamlit 可视化界面。
视频演示与源码下载

包含: 📦完整项目源码 📦 预训练 模型权重
🗂️数据集
1.2 项目运行效果
- *Web 界面总览

*单张图片识别效果

*批量图片合规检查

1.3 项目介绍
核心创新点:
| 维度 | 设计 |
|---|---|
| 类目设计 | 只检「跌倒」一个目标(nc=1),正样本聚焦、语义清晰,告警链路短、误报可控 |
| 模型选型 | YOLO26n,Anchor-Free 轻量架构,CPU 单图 < 100 ms,可部署在病房 / 养老院边缘盒子 |
| 部署形态 | Streamlit 单页应用 + 本地 best.pt,零依赖中间件,便于离线现场部署 |
| 输入兼容 | 图片 / 批量图片(含 zip)/ 视频 / 摄像头四种输入复用同一推理引擎 |
| 适配场景 | 养老院、医院病房、独居监护、公共场所四类场景均已覆盖 |
功能概览:
- 🚨 单图检测:上传监护画面 → 实时返回带框图 + 类别 / 置信度 / 坐标明细
- 📚 批量检测:单次最多 200 张,输出汇总表 + 检出分布 + zip 下载
- 🎬 视频检测:mp4 / avi / mov / mkv 通通可读,逐帧推理后落盘新视频
- 📷 摄像头实时检测:可对接病房 / 走廊 IPC 的 RTSP 流,做实时跌倒感知
1 种目标类别:
| 类别 | 描述 |
|---|---|
| 跌倒 | 人员倒地、滑倒、从站立 / 坐姿跌落等倒地姿态 |
技术栈:
| 层 | 选型 |
|---|---|
| 模型框架 | Ultralytics + PyTorch |
| 视觉算法 | YOLO26n(Anchor-Free,C2f Backbone,Decoupled Head + DFL) |
| Web 前端 | Streamlit + 自定义 HTML 主题(紫金配色,呼应安全预警风) |
| 视频 / 图像 | OpenCV、imageio-ffmpeg |
| 数据可视化 | Streamlit 原生 chart / Pandas |
| 配置管理 | 单一 configs/project.yaml,行业话术 / UI / 推理阈值统一收口 |
二、设计框架
2.1 系统架构
┌──────────────────────────────────────────┐
│ Streamlit Web 前端(单页 SPA) │
│ · 监护控制台 / 单图 / 批量 / 视频 / 摄像头 │
│ · 侧栏 · 阈值 · 目标图鉴 · 模型缓存 │
└────────────────────┬─────────────────────┘
│ Python 调用
▼
┌──────────────────────────────────────────┐
│ 推理服务层(infer_image_path 等) │
│ · bytes / Path / frame → tensor │
│ · 推理结果 → 标注图 + DataFrame │
└────────────────────┬─────────────────────┘
│
▼
┌──────────────────────────────────────────┐
│ YOLO26n 推理引擎(model/best.pt) │
│ Backbone (C2f+SPPF) → Neck (FPN/PAN) │
│ → Decoupled Head(DFL + cls) │
└────────────────────┬─────────────────────┘
│
▼
(可对接:护士站看板 / 家属告警 / 社区平台)
2.2 YOLO26 网络结构
输入 640×640×3
│
▼
[Backbone]
Conv → C2f → Conv → C2f → Conv → C2f → Conv → C2f → SPPF
多尺度卷积 + 跨阶段特征融合,对姿态多变的人体目标更稳
│
▼
[Neck] FPN 上采样 + PAN 下采样:P3 / P4 / P5 三级金字塔
近处倒地人体 → P3 层;远景 / 站立 → P4/P5
│
▼
[Head] Decoupled Head(cls 头 / reg 头解耦)
回归头采用 DFL(Distribution Focal Loss)
Anchor-Free,输出 (cx, cy, w, h, cls × 1)
│
▼
[NMS] iou=0.7, conf=0.30 → 最终检测框
2.3 检测流程
监护摄像头帧 / 单张图片
│
▼
Letterbox 640×640 + RGB
│
▼
YOLO26n forward
│
▼
Detect Head 输出 (cls × 1)
│
▼
conf 过滤 + NMS
│
▼
result.plot() 画框 + "跌倒"
│
▼
Streamlit 双列展示 + DataFrame + 置信度分析
│
▼
(可扩展:时间线告警 → 护士站 / 家属 / 社区联动)
三、代码结构(核心 50 行 + 解析)
项目目录:
跌倒检测系统/
├── app/streamlit_app.py # Web 入口
├── configs/project.yaml # 行业话术 / UI / 训练 / 推理参数
├── model/best.pt # 训练好的 YOLO26n 权重
├── dataset/ # train / valid / test 数据集
├── train/ # 训练产物(results.csv / 曲线图 / 混淆矩阵)
└── scripts/ # train / validate / export 等通用脚本
最核心的 50 行——模型加载 + 单图推理 + 批量 / 视频复用同一引擎:
# === 1. 配置驱动:置信度 / iou / 批量上限全部从 project.yaml 读取 ========
PROJECT_ROOT = Path(__file__).resolve().parent.parent
APP_CONFIG = load_yaml(PROJECT_ROOT / "configs" / "project.yaml")
DEFAULT_CONF = float(APP_CONFIG.get("inference", {
}).get("conf", 0.30))
# === 2. 模型加载(带 streamlit 资源缓存,避免每次刷新重载)============
@st.cache_resource(show_spinner=False)
def load_model(model_path: str) -> YOLO:
return YOLO(model_path)
# === 3. 单图推理:路径 → 标注图 + 检测明细 DataFrame ===================
def infer_image_path(model: YOLO, image_path: Path, conf: float) -> tuple:
result = model.predict(str(image_path), conf=conf, verbose=False)[0]
annotated = result.plot() # BGR ndarray,已画框
rows = []
if result.boxes is not None:
for box in result.boxes:
cls_id = int(box.cls.item())
x1, y1, x2, y2 = [float(v) for v in box.xyxy[0].tolist()]
rows.append({
"class_id": cls_id,
"class_name": result.names[cls_id], # "跌倒"
"confidence": round(float(box.conf.item()), 4),
"x1": round(x1, 1), "y1": round(y1, 1),
"x2": round(x2, 1), "y2": round(y2, 1),
})
# BGR → RGB 给 Streamlit;rows 转 DataFrame 给表格组件
return annotated[:, :, ::-1], pd.DataFrame(rows)
# === 4. bytes → 临时文件 → 复用同一函数 ================================
def run_image_inference(model: YOLO, image_bytes: bytes, conf: float, suffix: str = ".jpg"):
with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as f:
f.write(image_bytes); tmp = Path(f.name)
try:
return infer_image_path(model, tmp, conf)
finally:
tmp.unlink(missing_ok=True)
5 段解析:
project.yaml + get("conf", 0.30)把置信度、iou、批量上限全部从配置读取,运营侧针对养老院 / 医院 / 社区分别标定阈值时不用改一行代码。@st.cache_resource把YOLO(model_path)的耗时锁在第一次访问,对 7×24 长时间运行的监护场景尤其重要——一次启动一直跑,单图响应稳定在百毫秒级。result.plot()直接返回带颜色框 + 类别 + 置信度的BGR ndarray,[:, :, ::-1]转回 RGB 喂给 Streamlit,一条链路上完成"推理 + 可视化"。- 把每个
box的cls / conf / xyxy拍成dict再拼成DataFrame——后续表格、CSV 下载、时间线趋势全部复用同一份结构。 run_image_inference走临时文件而非 numpy 数组,是为了让 Ultralytics 内部的 EXIF / orientation 处理逻辑生效,对顶装 / 侧装摄像头不同朝向都更稳;批量、视频、摄像头三个入口复用同一套infer_image_path。
四、训练效果
模型在自建的跌倒场景 数据集上训练 (YOLO26n、640 输入、batch 16、200 epoch 早停),best.pt 对应指标如下:
| 指标 | 数值 |
|---|---|
| Precision | 0.882 |
| Recall | 0.763 |
| mAP@0.5 | 0.848 |
| mAP@0.5:0.95 | 0.499 |
从训练曲线看,box / cls / dfl 三路 loss 在前 50 epoch 快速收敛,之后稳步下降;mAP@0.5 稳定在 0.85 左右。单类检测下 Precision 0.882 说明误报抑制能力在线,适合直接做告警触发;而 mAP@0.5:0.95 约为 0.5,符合跌倒检测这一任务本身的特性——人体倒地姿态高度非刚性、遮挡与俯拍视角多变,严格 IoU 阈值下检测框中心回归难度天然偏高。这正是后续引入姿态估计 / 时序判定的切入点。
(原文此处为 PR 曲线截图 / 归一化混淆矩阵截图 / 训练曲线截图)
五、项目总结
做对了什么:
- 只检「跌倒」一个目标,把"盯监控"升级为"检跌倒",语义清晰、告警链路短,适合作为监护系统的触发模块;
- 选择 YOLO26n 而非更大的 v8s/v8m,模型轻量、CPU 单图百毫秒内完成推理,可在病房 / 养老院边缘盒子离线运行,敏感画面不出户,兼顾隐私合规;
- 用一份
project.yaml把"行业话术 / UI 主题色 / 训练超参 / 推理阈值 / 类别定义"全部收口,迁移到摔倒、离床、越界等其他监护事件只需替换数据集与重新训练。
还能怎么做:
- 引入时序模型(LSTM / SlowFast)做行为序列判定,把单帧"跌倒框"汇聚成"倒地持续 10 秒"等高置信事件,抑制单帧误报;
- 结合人体关键点(姿态估计)判断跌倒的持续状态与人员身份,区分"跌倒"与"蹲下系鞋带 / 俯身捡物";
- 告警联动:检测到跌倒后对接短信 / 电话 / 护士站看板,形成"检出—通知—处置"闭环,这是当前智慧养老最有商业价值的方向之一。