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
| class CabinOOPDetector: """ 基于 PULSE + mmWave 雷达的座舱OOP检测器 优势: 1. 隐私保护(无图像) 2. 穿透毯子/衣物 3. 5.1ms推理延迟(实时) 4. 12M参数(可部署边缘NPU) 5. PULSE降低了MPJVE(抖动),适合时序稳定的OOP判断 部署方案: - 雷达:Infineon XENSIV 60GHz 或 TI IWR6843 - 处理器:QCS8255 Hexagon NPU 或 STM32N6 """ def __init__(self, threshold_lean: float = 30.0, threshold_kneel: float = 0.7): self.threshold_lean = threshold_lean self.threshold_kneel = threshold_kneel def detect_oop_from_joints(self, joints_3d: np.ndarray) -> dict: """ 从3D关节坐标检测OOP Args: joints_3d: (J, 3) 3D关节坐标 (mm) J=17 or 24 depending on skeleton format Returns: OOP检测结果 """ PELVIS, SPINE, NECK, HEAD = 0, 3, 12, 15 L_SHOULDER, R_SHOULDER = 16, 17 L_HIP, R_HIP = 1, 2 L_KNEE, R_KNEE = 4, 5 L_ANKLE, R_ANKLE = 7, 8 torso_vec = joints_3d[NECK] - joints_3d[PELVIS] forward_angle = np.degrees(np.arctan2( abs(torso_vec[2]), max(abs(torso_vec[1]), 1.0) )) side_angle = np.degrees(np.arctan2( torso_vec[0], max(abs(torso_vec[1]), 1.0) )) knee_y = min(joints_3d[L_KNEE][1], joints_3d[R_KNEE][1]) hip_y = max(joints_3d[L_HIP][1], joints_3d[R_HIP][1]) is_kneeling = knee_y > hip_y * 0.5 results = {} if forward_angle > self.threshold_lean: results['forward_lean'] = { 'angle': float(forward_angle), 'severity': min(forward_angle / 60, 1.0) } if abs(side_angle) > self.threshold_lean: results['side_lean'] = { 'angle': float(side_angle), 'severity': min(abs(side_angle) / 45, 1.0) } if is_kneeling: results['kneeling'] = { 'knee_height_ratio': float(knee_y / (hip_y + 1e-6)), 'severity': 0.8 } return { 'is_oop': len(results) > 0, 'oop_types': list(results.keys()), 'details': results, 'joint_metrics': { 'forward_angle': float(forward_angle), 'side_angle': float(side_angle), 'knee_hip_ratio': float(knee_y / (hip_y + 1e-6)) } }
if __name__ == "__main__": detector = CabinOOPDetector() normal_joints = np.array([ [0, -400, 0], [-100, -350, 0], [100, -350, 0], [0, -300, 0], [-100, -200, 0], [100, -200, 0], [0, -250, 0], [-100, -50, 0], [100, -50, 0], [0, -200, 0], [-100, -50, 0], [100, -50, 0], [0, -150, 0], [-150, -180, 0], [150, -180, 0], [0, -100, 0], [-200, -200, 0], [200, -200, 0], [-300, -300, 0], [300, -300, 0], [-400, -380, 0], [400, -380, 0], [-450, -380, 0], [450, -380, 0], ], dtype=np.float32) lean_joints = normal_joints.copy() lean_joints[NECK := 12] = [0, -100, 50] lean_joints[HEAD := 15] = [0, -50, 60] kneel_joints = normal_joints.copy() kneel_joints[4] = [-100, -350, 0] kneel_joints[5] = [100, -350, 0] print("=== 正常坐姿 ===") print(detector.detect_oop_from_joints(normal_joints)) print("\n=== 前倾OOP ===") print(detector.detect_oop_from_joints(lean_joints)) print("\n=== 跪立OOP ===") print(detector.detect_oop_from_joints(kneel_joints))
|