331 lines
12 KiB
Markdown
331 lines
12 KiB
Markdown
# 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` 和风险解释字段用于问题回溯。
|
||
|