中风患者居家康复训练系统

AI 驱动的 Brunnstrom 分期康复 · 技术文档

说人话:这是一个用浏览器摄像头就能用的康复训练工具。患者对着电脑做动作,摄像头拍下来,AI 识别关节角度、判断做得对不对,用红绿灯告诉你哪里要调整,还能出周报看进步。不用去医院,在家就能练。

1. 整体流程

打开网页
ROM 关节活动度评估
Brunnstrom 分期定级
自适应推送训练动作
实时做动作 + AI 纠错
生成周报

2. 每一步干了啥

2.1 打开网页,摄像头就绪

浏览器调用 getUserMedia 打开摄像头。每 100ms 抽一帧 JPEG,Base64 编码后 POST 到 /api/upload_frame。服务器跑 MediaPipe Pose + Hands 两个模型,同时检测身体 33 个关键点和双手各 21 个关键点。

2.2 ROM 关节活动度评估

进去之后先做 ROM 测试,分三步:肩外展(手臂从侧面抬起来)、肩前屈(手臂往前抬)、肘屈伸(手肘弯曲伸直)。每步系统会记录你的最大活动角度,三步做完算总分,自动定 Brunnstrom 分期。

2.3 Brunnstrom 分期定级

Brunnstrom 是康复医学里经典的六期分期法。系统根据 ROM 三项平均角度来推算:

分期特点平均角度范围
I 期(软瘫期)完全没力,动不了< 30°
II 期(痉挛初现)开始有点痉挛,勉强能动30°–60°
III 期(痉挛高峰)痉挛最严重,能做基本协同动作60°–100°
IV 期(开始恢复)痉挛减轻,能做分离动作100°–140°
V 期(分离运动)各关节能独立活动140°–170°
VI 期(接近正常)协调性基本恢复> 170°

2.4 自适应推送训练动作

定完分期后,系统的训练难度会自动适配。比如 ROM 测出来只恢复了 40%,那所有动作的目标角度就打四折——不会一上来就让你抬到 160°,而是从 64° 开始慢慢加。一句话:你能做多少就练多少,不硬来

2.5 实时动作反馈

每帧进来,系统做三件事:

① 算关节角度:肩外展、肩前屈、肩内收、肘屈伸、前臂旋前旋后、躯干倾斜——6 类角度全算出来。

② 跟目标对比:每个关节跟预设目标比对,Δ ≤ 容差 → 绿灯,容差 1~2 倍 → 黄灯,超过 2 倍容差 → 红灯

③ DTW 动作质量评分:不是只看单帧角度,而是把整段动作的时序序列跟参考模板做动态时间规整(DTW),算一个 0-100 的相似度分。你做得快一点慢一点没关系,DTW 会自动对齐时间轴。

④ 语音播报:动作到位了说"很好",角度偏了说"注意手肘角度",自带 3 秒冷却避免话痨。

2.6 训练数据存库 + 周报

每次训练自动记到 SQLite:哪一天、练了哪个动作、做了几次、每次多少分、花了多少秒。点"周报"按钮就能看到过去 7 天的汇总——训练天数、总次数、平均分、各动作明细,还有最近的 ROM 数据。

3. 软件基础信息

项目内容
功能AI 驱动的脑卒中居家手指/上肢康复训练系统
适用场景Brunnstrom I–VI 期脑卒中患者在家庭环境下的上肢康复训练
开发语言Python 3.10+
Web 框架Flask(单线程 + 线程锁保证帧同步)
人体检测MediaPipe Pose 0.10(33 关键点)+ MediaPipe Hands 0.10(21 关键点)
核心依赖OpenCV、NumPy、Pillow(中文渲染)、pyttsx3(语音)
数据库SQLite(本地文件,3 张表:ROM 评估 / 训练记录 / 逐次角度)
动作对比算法DTW 动态时间规整 + 指数衰减归一化
评分策略红黄绿三色交通灯 + 0-100 连续打分
部署方式systemd 服务化 + nginx 反代 + HTTPS(Let's Encrypt)

4. 系统设计要点

4.1 外部帧输入架构

不走传统的 OpenCV 本地摄像头循环,而是设计成 set_external_frame() → process_frame() → get_display_data() 三步调用。浏览器端 setInterval 定时 POST JPEG,服务器解码后塞给引擎处理。这样浏览器和服务器完全解耦,浏览器只管采帧和显示,服务器只管算。

4.2 线程安全的帧同步

Flask 默认多线程处理请求,但引擎只有一个实例。用 threading.Lock 保护 _latest_jpeg_latest_data,API 读取的时候不会读到半帧数据。MJPEG 流用 threading.Event 做帧就绪信号,避免空转烧 CPU。

4.3 MediaPipe Pose + Hands 双模型联调

身体用 Pose(model_complexity=1,平衡精度和速度),手部用 Hands(model_complexity=0,轻量模型)。双手数据单独跑,算出前臂旋前/旋后角度(拇指 vs 小指的垂直偏移 → arctan2 映射到 0°–180°)。这个设计是因为常规 Pose 模型检测不到手掌朝向,必须加 Hands 才能判断"手心朝上还是朝下"。

4.4 渐进式评分逻辑

不是简单的"对了/错了"二分。每个关节角度跟目标的偏差分三档:

偏差颜色计分
≤ 容差绿灯100 分
容差 ~ 2×容差黄灯50–99 分(线性衰减)
> 2×容差红灯0–50 分(线性衰减)

总分有两种模式:mean(所有关节取平均,适合标准动作)和 max(取最高分的关节,适合交替动作——比如一只手弯一只手直,只看做到位的那只)。

4.5 静态保持计时

有些动作需要"保持 X 秒不动"(比如前臂旋前旋后要保持 2 秒)。用 hold_seconds 字段控制:评分 ≥ 85 分才开始计时,中间掉下来就清零重来。屏幕上显示倒计时,到 0 算完成一次。

4.6 自适应难度调节

ROM 测完后,总角度 ÷ 理论最大值(300° = 三关节各 100° 的理想值),算出恢复百分比。所有训练动作的目标角度乘以这个百分比。比如你肩外展只能到 45°,那训练目标不是 90°,而是 45° × 0.5 = 22.5°,不让你硬拉。

4.7 跨平台中文字体

OpenCV 的 putText 不支持中文。用 Pillow 画中文再贴回 OpenCV 帧上。字体路径做了 Windows / Linux / macOS 三级 fallback:微软雅黑 → 文泉驿 → Noto Sans CJK → PingFang → 兜底遍历。字号缓存避免每次都重新加载字体文件。

4.8 DTW 动作质量评估

不是只看当前帧,而是录整段动作序列(最多 300 帧),跟理想的正弦波形参考模板做 DTW 对齐。公式:score = 100 × exp(-DTW距离 / (序列长度 × 特征维度) × 10)。指数衰减让分数对小幅偏差不敏感,大幅偏差快速惩罚。

4.9 语音反馈 + 冷却机制

pyttsx3 离线 TTS(不依赖网络),语速降到 160(老年人友好)。每条消息 3 秒内不重复播,避免"注意角度注意角度注意角度"洗脑循环。

5. 参数配置

参数默认值说明
MediaPipe 检测置信度0.7Pose 模型,低于此值认为没检测到人
MediaPipe 追踪置信度0.7帧间追踪稳定性
Hands 检测置信度0.6手部模型(比 Pose 低一点,因为有双手同时检测)
Pose 模型复杂度10=轻量(快但糙),1=标准,2=重(准但慢)
Hands 模型复杂度0轻量模型,手部关键点少但够用
关节角度容差20°–30°每个动作单独设置,越精细的动作容差越小
评分阈值(绿灯)≥ 85 分动作合格线
评分阈值(黄灯)60–84 分需要改进
保持计时触发线≥ 85 分静态动作开始计时的分数线
语音冷却3 秒相同提示不重复播
TTS 语速160pyttsx3 rate 参数,正常语速 200
MJPEG 帧间隔33ms(~30fps)video_feed 流输出间隔
周报统计范围7 天SQL 查询的 WHERE 条件

6. 五个训练动作

动作Brunnstrom监测关节评分模式特别说明
双侧上肢交替上举 IV 期 肩前屈 160°、肘关节 160° mean 基础动作,两手交替往上抬
双侧上肢触摸对肩上举 V 期 肩前屈 160°(上举)、肩内收 50°(够对肩) max 先摸对侧肩膀,再往上举直。两个阶段取最高分
双侧肘关节交替屈伸 III 期 肘关节 30° max + min聚合 一只手弯到 30° 同时另一只保持伸直。取弯的那只计分
前臂旋前旋后 V 期 肘关节 90°(保持)、旋前角度 160° max 曲肘 90° 固定,手心翻上翻下。需保持 2 秒
双手交替翻掌拍臂 V 期 肩内收 45°、旋前角度 160° mean 一手心朝上一手心朝下,交替翻掌。练协调性

7. 数据库设计

-- ROM 关节活动度评估记录
CREATE TABLE rom_assessments (
    id INTEGER PRIMARY KEY,
    timestamp TEXT,          -- ISO 时间戳
    shoulder_abduction REAL,   -- 肩外展角度
    shoulder_flexion REAL,     -- 肩前屈角度
    elbow_flexion REAL,        -- 肘屈曲角度
    total_score REAL,          -- 三项总分
    brunnstrom_stage INTEGER   -- 分期 1-6
);

-- 训练记录
CREATE TABLE training_sessions (
    id INTEGER PRIMARY KEY,
    timestamp TEXT,
    exercise_name TEXT,      -- 英文 key
    exercise_name_cn TEXT,    -- 中文名
    rep_count INTEGER,         -- 完成次数
    avg_score REAL,            -- 平均分
    duration_seconds INTEGER   -- 训练时长
);

-- 每次动作的关节角度快照(JSON)
CREATE TABLE session_angles (
    id INTEGER PRIMARY KEY,
    session_id INTEGER,        -- 关联 training_sessions
    rep_index INTEGER,
    joint_angles TEXT,         -- JSON: {"shoulder_flexion": 145, ...}
    score REAL
);

8. API 接口一览

路由方法用途
/api/upload_framePOST浏览器上传一帧 JPEG → 返回处理后的帧 (Base64) + 状态数据
/api/statusGET拿当前训练状态(模式、分数、关节角度、反馈文字)
/api/exercisesGET返回 5 个训练动作的 key 和中文名列表
/api/start_romPOST开始 ROM 关节活动度评估
/api/next_romPOSTROM 评估进入下一阶段(三步依次推进)
/api/start_exercisePOST开始指定训练动作(body 传 key)
/api/toggle_recordPOST开始/停止单次动作录制(用于 DTW 对比)
/api/return_menuPOST返回主菜单
/api/reportGET获取周报文本
/api/ref_video/<key>GET获取训练动作对应的参考视频路径
/video_feedGETMJPEG 实时流(处理后画面)

9. 部署信息

项目详情
服务器Ubuntu 22.04, 4 核 4GB
域名cdqtech.online
访问地址https://cdqtech.online/stroke-rehab/
后端端口127.0.0.1:5003
进程管理systemd(限制 127.0.0.1 监听,外网不可直连)
HTTPSnginx 443 反代 + Let's Encrypt 自动续期
代码路径/data/stroke-rehab/

cdqtech.online · 中风患者居家康复系统技术文档