feat(v1): add temporal fall state machine
This commit is contained in:
@@ -34,7 +34,7 @@ V1 的同一数据流既可接 RTSP,也可回放本地录像。V2 复用同一
|
||||
| Pose 适配器 | `v1/pose.py` | 校验锁定模型的 SHA-256、pose/person/17×3 契约,统一返回 box、关键点、置信度 | 跟踪、摔倒业务结论 |
|
||||
| 跟踪 | `v1/tracking.py` | 以归一化 box 中心距离为连续人员输出稳定 `track_id` | 根据姿态报警 |
|
||||
| 质量与证据 | `v1/evidence.py` | 拒绝缺失肩/髋/膝/踝的姿态,计算水平姿态和躯干归一化下移证据 | GUI 状态、确认事件 |
|
||||
| 状态机 | `v1/fall_state.py` | 管理每个 ID 的 NORMAL、SUSPECT、CONFIRMED、RECOVERING | 播放声音或存文件 |
|
||||
| 状态机 | `v1/fall_state.py` | 管理每个 ID 的 NORMAL、SUSPECT、CONFIRMED、RECOVERING,并在首次确认时产生一个带确认延迟的事件 | 播放声音或存文件 |
|
||||
| 报警工件 | `v1/alerts.py` | 对确认事件去重、播放声音、保存截图、写日志 | 推理或事件计算 |
|
||||
| PyQt UI | `v1/gui.py` | 渲染帧、骨架、状态、设置和弹窗 | 直接读 RTSP 或写判定规则 |
|
||||
| 回归工具 | `v1/tests/` 与 `v1/scripts/` | 回放录像、断言事件和延迟 | 生产 UI |
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
| T-102 | 实现可重连的视频源与录像回放适配器 | T-101 | 有效本地录像可按时间戳产帧;无效源进入连接错误状态且不崩溃。 | DONE |
|
||||
| T-103 | 实现 Pose 适配器与模型来源校验 | T-102 | 输出 person box、17 点和置信度;错误模型或哈希不符时给出明确错误。 | DONE |
|
||||
| T-104 | 实现人员跟踪与姿态质量门控 | T-103 | 连续人员维持 ID;低质量、缺失膝踝或空帧不会产生倒地候选。 | DONE |
|
||||
| T-105 | 实现按 ID 的时序摔倒状态机 | T-104 | 正例在配置秒数内确认;坐下、弯腰、短时低姿态回到 NORMAL;事件副作用只触发一次。 | DOING |
|
||||
| T-105 | 实现按 ID 的时序摔倒状态机 | T-104 | 正例在配置秒数内确认;坐下、弯腰、短时低姿态回到 NORMAL;事件副作用只触发一次。 | DONE |
|
||||
|
||||
## Phase 2 · V1 演示闭环
|
||||
|
||||
|
||||
@@ -293,7 +293,7 @@ git commit -m "feat(v1): add pose quality evidence"
|
||||
- Create: `v1/fall_state.py`
|
||||
- Create: `v1/tests/test_fall_state.py`
|
||||
|
||||
- [ ] **Step 1: Write event timing tests**
|
||||
- [x] **Step 1: Write event timing tests**
|
||||
|
||||
```python
|
||||
def test_confirmed_event_is_emitted_once_after_persistence():
|
||||
@@ -318,12 +318,12 @@ def test_confirmed_person_recovers_before_new_event_is_allowed():
|
||||
assert machine.state_of("7") is FallState.NORMAL
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run tests to verify failure**
|
||||
- [x] **Step 2: Run tests to verify failure**
|
||||
|
||||
Run: `python -m pytest v1/tests/test_fall_state.py -v`
|
||||
Expected: FAIL because `FallStateMachine` is missing.
|
||||
|
||||
- [ ] **Step 3: Implement the four-state contract**
|
||||
- [x] **Step 3: Implement the four-state contract**
|
||||
|
||||
```python
|
||||
from dataclasses import dataclass
|
||||
@@ -399,12 +399,12 @@ class FallStateMachine:
|
||||
|
||||
Use per-ID state, not global `frame_has_fall`. A source error and a rejected pose must not advance the machine.
|
||||
|
||||
- [ ] **Step 4: Run tests**
|
||||
- [x] **Step 4: Run tests**
|
||||
|
||||
Run: `python -m pytest v1/tests/test_fall_state.py -v`
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
- [x] **Step 5: Commit**
|
||||
|
||||
```powershell
|
||||
git add v1/fall_state.py v1/tests/test_fall_state.py docs progress.md
|
||||
|
||||
+4
-12
@@ -65,23 +65,15 @@ PoseEvidence = {
|
||||
}
|
||||
FallEvent = {
|
||||
event_id: string,
|
||||
source_id: string,
|
||||
track_id: string,
|
||||
started_at_utc: string,
|
||||
confirmed_at_utc: string,
|
||||
suspected_at_monotonic: float,
|
||||
confirmed_at_monotonic: float,
|
||||
latency_seconds: float,
|
||||
state: "CONFIRMED",
|
||||
evidence: {
|
||||
horizontal_pose: bool,
|
||||
rapid_vertical_change: bool,
|
||||
persistence_seconds: float
|
||||
},
|
||||
screenshot_path: string,
|
||||
config_version: string
|
||||
state: "CONFIRMED"
|
||||
}
|
||||
```
|
||||
|
||||
`FallEvent` 只在状态首次进入 `CONFIRMED` 时创建一次。连续帧更新 UI 状态,但不重复创建事件。
|
||||
`FallEvent` 是 T-105 状态机的纯内存确认事件,只在状态首次进入 `CONFIRMED` 时创建一次。连续帧更新 UI 状态,但不重复创建事件。T-202 的 `alerts` 会在不改变事件幂等语义的前提下,为截图/JSONL 记录补充来源、UTC 时间、证据和配置版本。
|
||||
|
||||
`PersonPose` 是 T-103 的纯模型输出,不带人员 ID;T-104 的跟踪模块产生 `TrackedPersonPose` 后,才允许事件证据按人员连续积累。
|
||||
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
## 当前快照
|
||||
|
||||
- 日期:2026-07-21
|
||||
- 阶段:V1 工程化起步;T-105 进行中。
|
||||
- 阶段:V1 事件引擎基线已建立;T-105 已验收,等待 T-201。
|
||||
- 已验证环境:Windows PowerShell;Python 3.8.10;Ultralytics 8.3.205;PyQt5 可导入。
|
||||
- 旧生产基线:`demo/main.py`、`demo/fall_detection_gui.py`、`demo/detect_fall.py`、`demo/best.pt`。
|
||||
- V1 代码:已建立安全配置、视频源与 Pose 适配器,以及 `v1/tracking.py` 的稳定人员 ID 和 `v1/evidence.py` 的质量/几何证据;状态机和 GUI 尚未实现。
|
||||
- V1 代码:已建立安全配置、视频源、Pose、跟踪、质量/几何证据,以及 `v1/fall_state.py` 的按 ID 四态事件机;PyQt GUI、声音、弹窗、截图、JSONL 和真实 RTSP 接入尚未实现。
|
||||
- V2 代码:`v2/` 目录存在但尚无实现。
|
||||
- 非代码设计工件:docs/ui/silver-pose-ui-ux-spec.md、docs/ui/2026-07-20-html-prototype-plan.md、docs/ui/silver-pose-v1-prototype.html 与 docs/ui/silver-pose-v2-prototype.html 已建立。v2 HTML 是符合正式浅色 Windows 规范的当前视觉参考:浅灰蓝底、白色卡片,红色只表示确认摔倒、其弹窗和事件证据;文件名中的 v2 只表示原型设计修订,不能理解为 Go V2 实现已开始。v1 HTML 保留为历史深色对照。两者均使用顶部双 Tab、设置草稿与状态交互,且画面、事件和时间都是模拟数据,不连接真实摄像头、模型或网络,也不改变 Phase 1 任务顺序。
|
||||
- 测试:`python -m compileall -q demo` 已通过;`python -m pytest v1/tests -v` 当前有 14 项配置/视频源/Pose/跟踪/证据测试并已通过。`demo/1.mp4` 的首两帧回放时间戳已验证为 0.000000 与 0.033333 秒,首帧 Pose smoke 得到 2 名人员、每人 17 点。`init.ps1` 会检查运行时依赖、编译旧基线并运行 V1 测试,但不会安装软件包。
|
||||
- 测试:`python -m compileall -q demo` 已通过;`python -m pytest v1/tests -v` 当前有 20 项配置/视频源/Pose/跟踪/证据/状态机测试并已通过。`demo/1.mp4` 的首两帧回放时间戳已验证为 0.000000 与 0.033333 秒,首帧 Pose smoke 得到 2 名人员、每人 17 点。`init.ps1` 会检查运行时依赖、编译旧基线并运行 V1 测试,但不会安装软件包。
|
||||
- 模型:`demo/best.pt` 可加载为 YOLO Pose,类别 `person`,`kpt_shape=[17, 3]`;与 `D:\PythonP\fall_detection\best.pt` 哈希一致。
|
||||
- 当前标准启动:`./init.ps1`。
|
||||
- 当前标准验证:`python -m compileall -q demo`。
|
||||
- 当前 blocker:回归录像及事件标签尚未创建;真实海康 RTSP 流尚未接入。
|
||||
- 当前 blocker:尚未把 Pose/跟踪/证据连接到状态机;回归录像及事件标签尚未创建;真实海康 RTSP 流尚未接入。
|
||||
|
||||
全局环境的 `pip check` 存在其他项目的包冲突,因此它不是 Silver Pose 的验收命令。`init.ps1` 只检查本项目实际导入的 OpenCV、NumPy、Ultralytics 与 PyQt5,并在命令非零退出时失败。
|
||||
|
||||
@@ -32,9 +32,9 @@
|
||||
|
||||
## 任务状态
|
||||
|
||||
- 已完成:T-000(Harness 文档与旧基线快照)、T-101(V1 安全配置基线)、T-102(视频源与录像回放)、T-103(Pose 适配器与模型校验)、T-104(跟踪与姿态质量证据)。
|
||||
- 正在进行:T-105(实现按 ID 的时序摔倒状态机)。
|
||||
- 下一个可领取:完成 T-105 后为 T-201。
|
||||
- 已完成:T-000(Harness 文档与旧基线快照)、T-101(V1 安全配置基线)、T-102(视频源与录像回放)、T-103(Pose 适配器与模型校验)、T-104(跟踪与姿态质量证据)、T-105(按 ID 时序状态机)。
|
||||
- 正在进行:无。
|
||||
- 下一个可领取:T-201。
|
||||
|
||||
## 当前可运行内容
|
||||
|
||||
|
||||
Reference in New Issue
Block a user