Files

331 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CMS v9.10 YOLO + RTMW 门区风险部署包
该目录是 v9.10 的精简部署版本,只保留运行 `YOLO + RTMW + risk` 所需的代码、模型、标定文件和依赖清单。历史推理结果、研发测试、标注网页、参考图片、缓存与离线分析入口均未放入部署包。
## 1. 功能链路
```text
视频帧
-> YOLO11s 人体检测与轨迹 ID
-> RTMW-L COCO-WholeBody 133 点关键点
-> 手臂/手部时序融合
-> 骨骼位置和尺度为主、人体框为辅的前后门归属
-> CAN 活跃门过滤
-> 手部区域(无有效手部时使用人体框兜底)
-> 与固定车门危险区 mask 计算二维风险
-> causal_results.jsonl
```
本版本不包含深度估计和 EdgeTAM。输出是二维图像风险,不是物理距离,也不是安全认证结论。
## 2. 目录结构
```text
run_risk.py 主入口
requirements-realtime-gpu.txt CUDA 推理依赖
requirements-tensorrt-windows.txt Windows TensorRT 可选依赖
models/
yolo11s.onnx 人体检测模型
rtmw-l-384.onnx WholeBody 关键点模型
annotations/
constant_door_mask.json 当前固定机位车门危险区
door_zone_multifeature.json 当前前门/后门多特征标定
pipeline/ 推理、融合、门区和风险计算代码
```
`annotations` 中的两个 JSON 都与摄像头机位相关。当前参数来自研发临时机位;换成实车机位后必须重新标定和验证,不能直接将临时机位结论作为量产参数。
## 3. 环境安装
推荐 Python 3.10~3.12 和 NVIDIA CUDA GPU。先安装与目标机 CUDA 或 JetPack 匹配的 PyTorch,再安装其余依赖:
```powershell
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
pip install -r requirements-realtime-gpu.txt
```
不要同时安装 CPU 版 `onnxruntime` 和 `onnxruntime-gpu`。Jetson Orin 应优先使用 NVIDIA 针对对应 JetPack 发布的 PyTorch/torchvision,而不是强制使用桌面 wheel。
如需在 Windows 上使用 RTMW TensorRT Execution Provider,再执行:
```powershell
pip install -r requirements-tensorrt-windows.txt
```
## 4. 运行
### 4.1 固定车门危险区
以后门 CAN=0、前门未进入电吸范围为例:
```powershell
python run_risk.py `
--video D:\data\segment_008.mp4 `
--constant-door-mask annotations\constant_door_mask.json `
--door-zone-config annotations\door_zone_multifeature.json `
--active-door rear `
--output outputs\seg_08_rear `
--det-device 0 `
--pose-device cuda `
--write-video
```
`--active-door` 对应当前 CAN=0 的车门:
- `front`:只有前门进入电吸范围;
- `rear`:只有后门进入电吸范围;
- `both`:前后门都进入电吸范围;
- `none`:两门都不进行风险判断。
当前命令行参数对整个视频保持不变,用于离线部署验证。实车 CAN 随帧变化时,集成层需要把每帧实际 CAN 状态传给门级风险选择逻辑。
不需要叠加视频时不要传 `--write-video`,可减少编码和磁盘 I/O。完整参数说明:
```powershell
python run_risk.py --help
```
### 4.2 TensorRT RTMW
```powershell
python run_risk.py `
--video D:\data\test.mp4 `
--constant-door-mask annotations\constant_door_mask.json `
--active-door rear `
--output outputs\test_trt `
--pose-provider tensorrt `
--pose-device cuda
```
首次运行会在 `models/rtmw_l_trt_cache` 生成 TensorRT 缓存,该缓存与目标 GPU、TensorRT 版本和运行环境相关,不随部署包预置。
## 5. 输出文件
输出目录包含:
- `causal_results.jsonl`:逐帧因果结果,一行一个 JSON 对象,是 Demo 对接的主要接口;
- `summary.json`:模型、帧数、吞吐、延迟及风险统计;
- `rtmw_risk_overlay.mp4`:仅在传入 `--write-video` 时生成。
`causal_results.jsonl` 每行顶层字段:
| 字段 | 含义 |
|---|---|
| `frame_index` | 从 0 开始的视频帧号 |
| `track_ids` | 当前帧人体轨迹 ID 数组 |
| `boxes` | 与 `track_ids` 同序的人体框,格式 `[x1,y1,x2,y2]` |
| `skeletons` | 与检测人体对齐的 133 点融合骨骼 |
| `active_door` | 本次运行指定的 CAN=0 门:`front/rear/both/none` |
| `door_assignments` | 每个轨迹的前门/后门归属及特征解释 |
| `door_risks` | `front` 和 `rear` 两扇门各自的最终风险 |
| `risk` | 经过 CAN 和门区过滤后供业务使用的当前风险 |
| `ungated_risk` | 未经过前后门/CAN 过滤的原始二维风险,仅用于诊断 |
数组关联规则:`boxes[i]`、`track_ids[i]`、`skeletons[i].person_index == i`、`door_assignments[i].person_index == i` 表示同一个人。跨帧关联应使用 `track_id`,不要依赖数组下标。
## 6. `risk` 的含义
### 6.1 应读取哪个字段
单门 CAN=0 时,业务防夹建议读取:
```text
risk.risk_type
risk.risk_level
risk.risk_score
risk.decision
```
需要同时展示前后门时分别读取:
```text
door_risks.front
door_risks.rear
```
`ungated_risk` 只用于排查“图像上是否靠近危险区”,不能直接代替门级最终结论,否则会绕过前后门归属和 CAN 过滤。
### 6.2 风险标签
`risk_type` 是带门位置的最终风险标签:
| `risk_type` | `risk_level` | 含义 |
|---|---|---|
| `FRONT_CLEAR` / `REAR_CLEAR` | `clear` | 对应活跃门没有风险 |
| `FRONT_WATCH` / `REAR_WATCH` | `watch` | 进入关注距离,但未达到 warning |
| `FRONT_WARNING` / `REAR_WARNING` | `warning` | 距离达到 warning 阈值 |
| `FRONT_DANGER` / `REAR_DANGER` | `danger` | 人体风险区域与车门危险区相交 |
| `FRONT_UNKNOWN` / `REAR_UNKNOWN` | `unknown` | 人物处于 `transition`,无法可靠确定前后门 |
| `FRONT_INACTIVE` / `REAR_INACTIVE` | `inactive` | 该门 CAN 不活跃,不计算防夹风险 |
| `NO_ACTIVE_DOOR` | `inactive` | 前后门均不活跃 |
对应的 `decision`:
| `decision` | 含义 |
|---|---|
| `DANGER_INTERSECTION` | 风险区域与车门 mask 有像素相交 |
| `WARNING_NEAR` | 相对距离小于等于 warning 阈值 |
| `WATCH` | 相对距离处于 warning 与 release 之间 |
| `CLEAR` | 相对距离大于 release 阈值 |
| `CLEAR_NO_PERSON_ASSIGNED_TO_ACTIVE_DOOR` | 没有人被分配给该活跃门 |
| `EVIDENCE_UNAVAILABLE_TRANSITION_ZONE` | 存在 `transition` 人员,门归属不确定 |
| `DOOR_CAN_NOT_ACTIVE` | 该门 CAN 不活跃 |
| `NO_DOOR_CAN_ACTIVE` | 没有活跃门 |
默认阈值:
```text
warning_distance_relative = 0.30
release_distance_relative = 0.45
```
对每个风险区域:
```text
distance_relative = min_distance_px / sqrt(region_area_px)
risk_score = clip(1 - distance_relative / release_distance_relative, 0, 1)
```
只要 `door_overlap_px > 0`,就强制 `risk_score=1.0` 且等级为 `danger`。因此 `risk_score` 是归一化二维接近程度,不是概率,也不是厘米/毫米距离。
### 6.3 `regions` 与证据来源
每个门风险中的 `regions` 保存独立人体区域的解释信息,常用字段包括:
- `track_id`、`side`:所属轨迹和左右手;
- `source`:`RTMW_HAND_KEYPOINTS` 或 `YOLO_BODY_BOX_FALLBACK`;
- `region_area_px`:风险区域面积;
- `door_overlap_px`、`region_overlap_ratio`:与车门 mask 的相交量;
- `min_distance_px`:区域到车门 mask 的最小像素距离;
- `region_scale_px`:`sqrt(region_area_px)`;
- `distance_relative`:尺度归一化距离;
- `risk_score`、`risk_level`、`decision`:该区域自己的风险结果。
存在可用手部时,每只手用 21 点凸包计算风险;一个人没有任何可用手部时,才使用整个人体框兜底。人体框兜底更保守,也更容易产生误报。
### 6.4 `transition` 的当前行为
`door_assignments[].door_zone` 的位置标签为:
- `front`:归属前门;
- `rear`:归属后门;
- `transition`:前后门证据不足或位于过渡区;
- `unassigned`:人体尺度低于有效阈值,不参与门级风险。
当前 v9.10 中,`transition` 人员即使在 `ungated_risk` 中距离很近,也不会直接变成 `FRONT_WARNING/REAR_WARNING` 或 `DANGER`,而是让活跃门输出 `*_UNKNOWN`,其 `risk_score` 为 `null`。Demo 必须显式展示或处理 `unknown`,不能把它当成 `clear`。这是当前版本行为,不代表最终量产安全策略。
## 7. `skeletons` 的含义与可视化对接
### 7.1 数据结构
每个人的骨骼对象如下:
```json
{
"track_id": 1,
"person_index": 0,
"layout": "coco_wholebody_133",
"keypoints": [[x0, y0], [x1, y1]],
"metadata": {
"left": {},
"right": {}
}
}
```
- `keypoints` 实际固定为 `133 x 2`,示例中省略了其余点;
- 坐标单位是原视频像素,原点在左上角,x 向右、y 向下;
- 坐标保留 3 位小数;
- 这里没有逐点置信度,`metadata` 提供的是手臂/手部融合后的状态;
- `keypoints` 使用的正是当前叠加视频 `draw_fused` 使用的融合结果。
### 7.2 COCO-WholeBody 133 点索引
| 索引 | 含义 |
|---|---|
| `0` | nose |
| `1/2` | left/right eye |
| `3/4` | left/right ear |
| `5/6` | left/right shoulder |
| `7/8` | left/right elbow |
| `9/10` | left/right wrist |
| `11/12` | left/right hip |
| `13/14` | left/right knee |
| `15/16` | left/right ankle |
| `17/18/19` | left big toe / small toe / heel |
| `20/21/22` | right big toe / small toe / heel |
| `23–90` | 68 个面部关键点 |
| `91–111` | 左手 21 点 |
| `112–132` | 右手 21 点 |
每只手的局部 21 点顺序:
```text
0 wrist
1-4 thumb
5-8 index finger
9-12 middle finger
13-16 ring finger
17-20 little finger
```
左手局部索引需要加 91,右手局部索引需要加 112,才能得到 `keypoints` 中的全局索引。
### 7.3 与当前叠加视频一致的绘制规则
当前风险叠加视频只绘制手臂和双手,不绘制面部、躯干和腿部。手臂连线:
```text
(5,7), (7,9) 左肩-左肘-左腕
(6,8), (8,10) 右肩-右肘-右腕
```
每只手使用以下局部连线,分别作用到 `91–111` 和 `112–132`:
```text
(0,1),(1,2),(2,3),(3,4)
(0,5),(5,6),(6,7),(7,8)
(0,9),(9,10),(10,11),(11,12)
(0,13),(13,14),(14,15),(15,16)
(0,17),(17,18),(18,19),(19,20)
```
为了与现有视频表现一致:
- `metadata[side].limb_state == "consensus"`:手臂画实线,否则画虚线;
- `metadata[side].hand_state == "rejected"`:不画该手;
- 手未被拒绝且 `distance_eligible == true`:手部画实线;
- 手未被拒绝但 `distance_eligible == false`:手部画虚线;
- `alarm_eligible == true` 表示该手允许进入 risk 区域计算。
Demo 如果只需要复现当前可视化,读取上述 48 个点即可;如果后续需要完整人体展示,可以使用全部 133 点,但应自行补充完整 WholeBody 连线定义。
## 8. `door_assignments` 对接说明
常用字段:
- `track_id`、`person_index`:与检测框和骨骼关联;
- `door_zone`:经过最多 5 帧因果中值后的 `front/rear/transition/unassigned`;
- `raw_door_zone`:当前帧未经时序中值稳定的标签;
- `front_probability`:当前帧前门概率;
- `smoothed_front_probability`:因果时序中值;
- `confidence`:相对 0.5 的归属置信度,不是人体检测置信度;
- `pose_feature_count`:本帧可用骨骼特征数量;
- `features`、`feature_frontness`:标定特征值和各特征前门贡献;
- `history_frames`:当前轨迹已用于中值的历史帧数。
当前标定阈值为:`smoothed_front_probability >= 0.72` 判为前门,`<= 0.28` 判为后门,中间为 `transition`。这些参数应随实车机位重新验证。
## 9. Demo 集成注意事项
1. 每帧先按 `track_id` 关联检测框、骨骼、门区和风险,避免多人时按数组顺序长期跟踪。
2. 主界面风险展示使用 `risk`;需要前后门双状态时使用 `door_risks.front/rear`。
3. `unknown`、`inactive` 和 `clear` 是三种不同状态,不能合并显示。
4. `risk_score == null` 表示该状态没有可用数值风险,不应转换成 0。
5. `ungated_risk` 只用于诊断叠加,不能作为最终防夹指令。
6. 更换分辨率或裁剪策略后必须核对车门 mask、骨骼坐标与视频坐标是否仍一致。
7. 当前系统可能把玻璃倒影或反光误检成人,部署 Demo 应保留原视频、检测框、`track_id` 和风险解释字段用于问题回溯。