1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
| """ Euro NCAP 2026 安全带误用检测算法
核心方法:肩带关键点检测 + 路径分析 + 误用分类 """
import numpy as np from typing import List, Tuple, Dict from dataclasses import dataclass
@dataclass class BeltKeypoint: """安全带关键点""" name: str position: Tuple[float, float] confidence: float
@dataclass class BeltMisuseResult: """安全带误用检测结果""" is_misuse: bool misuse_type: str confidence: float warning_level: int
def detect_belt_keypoints(image: np.ndarray) -> List[BeltKeypoint]: """ 检测安全带关键点 Args: image: 座舱图像, shape=(H, W, 3) Returns: keypoints: 安全带关键点列表 IMS落地应用: 关键点定义: - belt_anchor_top: 安全带顶部锚点(B柱) - belt_anchor_bottom: 安全带底部锚点(座椅侧面) - shoulder_cross: 肩带跨肩位置 - lap_left: 腰带左侧位置 - lap_right: 腰带右侧位置 - buckle: 安全带扣位置 """ keypoints = [ BeltKeypoint('belt_anchor_top', (200, 150), 0.95), BeltKeypoint('belt_anchor_bottom', (250, 400), 0.92), BeltKeypoint('shoulder_cross', (300, 200), 0.88), BeltKeypoint('lap_left', (280, 350), 0.90), BeltKeypoint('lap_right', (320, 350), 0.90), BeltKeypoint('buckle', (300, 360), 0.95) ] return keypoints
def classify_belt_misuse(keypoints: List[BeltKeypoint], shoulder_position: Tuple[float, float]) -> BeltMisuseResult: """ 分类安全带误用类型 Args: keypoints: 安全带关键点 shoulder_position: 乘客肩部位置(从身体姿态估计) Returns: result: 误用检测结果 Euro NCAP 2026 检测逻辑: 1. lap-only误用:肩带关键点未检测到或置信度<0.5 2. 肩带过低:shoulder_cross.y > shoulder_position.y + 50px 3. 肩带过外:shoulder_cross.x偏离肩中线>30px """ shoulder_cross = None lap_points = [] anchor_top = None for kp in keypoints: if kp.name == 'shoulder_cross': shoulder_cross = kp elif kp.name in ['lap_left', 'lap_right']: lap_points.append(kp) elif kp.name == 'belt_anchor_top': anchor_top = kp LAP_ONLY_THRESHOLD = 0.5 LOW_SHOULDER_THRESHOLD = 50 OUTER_SHOULDER_THRESHOLD = 30 misuse_type = "normal" confidence = 1.0 warning_level = 0 if shoulder_cross is None or shoulder_cross.confidence < LAP_ONLY_THRESHOLD: misuse_type = "lap_only" confidence = 0.9 if shoulder_cross is None else 0.7 warning_level = 2 elif shoulder_cross.position[1] > shoulder_position[1] + LOW_SHOULDER_THRESHOLD: misuse_type = "low_shoulder" confidence = 0.85 warning_level = 1 elif abs(shoulder_cross.position[0] - shoulder_position[0]) > OUTER_SHOULDER_THRESHOLD: misuse_type = "outer_shoulder" confidence = 0.80 warning_level = 1 is_misuse = misuse_type != "normal" return BeltMisuseResult( is_misuse=is_misuse, misuse_type=misuse_type, confidence=confidence, warning_level=warning_level )
def generate_warning(result: BeltMisuseResult) -> str: """ 生成警告消息 Args: result: 误用检测结果 Returns: warning_msg: 警告消息 IMS落地应用: 一级警告:视觉提示+声音提示 二级警告:持续声音警告+限制启动 """ if not result.is_misuse: return "安全带佩戴正常" warning_msgs = { "lap_only": "⚠️ 警告:检测到只系腰带,肩带未正确佩戴!请重新调整安全带。", "low_shoulder": "⚠️ 提示:肩带位置过低,建议调整至肩部中央位置。", "outer_shoulder": "⚠️ 提示:肩带位置偏离肩中线,建议调整位置。", "behind_back": "⚠️ 警告:安全带绕过背后,严重误用!请重新佩戴。", "under_arm": "⚠️ 警告:安全带夹在腋下,严重误用!请重新佩戴。" } return warning_msgs.get(result.misuse_type, "安全带佩戴异常")
if __name__ == "__main__": keypoints_normal = [ BeltKeypoint('belt_anchor_top', (200, 150), 0.95), BeltKeypoint('belt_anchor_bottom', (250, 400), 0.92), BeltKeypoint('shoulder_cross', (300, 180), 0.88), BeltKeypoint('lap_left', (280, 350), 0.90), BeltKeypoint('lap_right', (320, 350), 0.90), BeltKeypoint('buckle', (300, 360), 0.95) ] shoulder_pos = (300, 170) result_normal = classify_belt_misuse(keypoints_normal, shoulder_pos) print("="*50) print("正常佩戴测试") print("="*50) print(f"误用类型: {result_normal.misuse_type}") print(f"警告: {generate_warning(result_normal)}") keypoints_lap_only = [ BeltKeypoint('belt_anchor_top', (200, 150), 0.95), BeltKeypoint('belt_anchor_bottom', (250, 400), 0.92), BeltKeypoint('shoulder_cross', (300, 180), 0.30), BeltKeypoint('lap_left', (280, 350), 0.90), BeltKeypoint('lap_right', (320, 350), 0.90), BeltKeypoint('buckle', (300, 360), 0.95) ] result_lap_only = classify_belt_misuse(keypoints_lap_only, shoulder_pos) print("="*50) print("Lap-only误用测试") print("="*50) print(f"误用类型: {result_lap_only.misuse_type}") print(f"置信度: {result_lap_only.confidence:.2f}") print(f"警告等级: {result_lap_only.warning_level}") print(f"警告: {generate_warning(result_lap_only)}") keypoints_low = [ BeltKeypoint('belt_anchor_top', (200, 150), 0.95), BeltKeypoint('belt_anchor_bottom', (250, 400), 0.92), BeltKeypoint('shoulder_cross', (300, 250), 0.88), BeltKeypoint('lap_left', (280, 350), 0.90), BeltKeypoint('lap_right', (320, 350), 0.90), BeltKeypoint('buckle', (300, 360), 0.95) ] result_low = classify_belt_misuse(keypoints_low, shoulder_pos) print("="*50) print("肩带过低测试") print("="*50) print(f"误用类型: {result_low.misuse_type}") print(f"警告: {generate_warning(result_low)}")
|