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 集成注意事项
- 每帧先按
track_id关联检测框、骨骼、门区和风险,避免多人时按数组顺序长期跟踪。 - 主界面风险展示使用
risk;需要前后门双状态时使用door_risks.front/rear。 unknown、inactive和clear是三种不同状态,不能合并显示。risk_score == null表示该状态没有可用数值风险,不应转换成 0。ungated_risk只用于诊断叠加,不能作为最终防夹指令。- 更换分辨率或裁剪策略后必须核对车门 mask、骨骼坐标与视频坐标是否仍一致。
- 当前系统可能把玻璃倒影或反光误检成人,部署 Demo 应保留原视频、检测框、
track_id和风险解释字段用于问题回溯。