CMS v9.10 YOLO + RTMW 门区风险部署包

该目录是 v9.10 的精简部署版本,只保留运行 YOLO + RTMW + risk 所需的代码、模型、标定文件和依赖清单。历史推理结果、研发测试、标注网页、参考图片、缓存与离线分析入口均未放入部署包。

1. 功能链路

视频帧
  -> YOLO11s 人体检测与轨迹 ID
  -> RTMW-L COCO-WholeBody 133 点关键点
  -> 手臂/手部时序融合
  -> 骨骼位置和尺度为主、人体框为辅的前后门归属
  -> CAN 活跃门过滤
  -> 手部区域(无有效手部时使用人体框兜底)
  -> 与固定车门危险区 mask 计算二维风险
  -> causal_results.jsonl

本版本不包含深度估计和 EdgeTAM。输出是二维图像风险,不是物理距离,也不是安全认证结论。

2. 目录结构

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,再安装其余依赖:

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,再执行:

pip install -r requirements-tensorrt-windows.txt

4. 运行

4.1 固定车门危险区

以后门 CAN=0、前门未进入电吸范围为例:

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。完整参数说明:

python run_risk.py --help

4.2 TensorRT RTMW

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 时,业务防夹建议读取:

risk.risk_type
risk.risk_level
risk.risk_score
risk.decision

需要同时展示前后门时分别读取:

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 没有活跃门

默认阈值:

warning_distance_relative = 0.30
release_distance_relative = 0.45

对每个风险区域:

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 数据结构

每个人的骨骼对象如下:

{
  "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 点顺序:

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 与当前叠加视频一致的绘制规则

当前风险叠加视频只绘制手臂和双手,不绘制面部、躯干和腿部。手臂连线:

(5,7), (7,9)      左肩-左肘-左腕
(6,8), (8,10)     右肩-右肘-右腕

每只手使用以下局部连线,分别作用到 91–111 和 112–132:

(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 和风险解释字段用于问题回溯。
S
Description
No description provided
Readme 366 MiB
Languages
Python 100%