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
| """ 基于3D人体姿态估计的OOP检测
输入: DMS/OMS摄像头 (RGB-IR, 全局快门) 模型: 轻量化3D HPE (Human Pose Estimation) 输出: 关键点3D坐标 → 姿态分类
关键点定义(COCO-17 + 车内扩展): 0: 鼻子 1-4: 眼睛耳朵 5-6: 肩膀 7-8: 手肘 9-10: 手腕 11-12: 髋部 13-14: 膝盖 15-16: 脚踝 扩展: 17-18: 头顶 19-20: 安全带位置 """
import numpy as np from typing import List
KEYPOINT_NAMES = [ "nose", "left_eye", "right_eye", "left_ear", "right_ear", "left_shoulder", "right_shoulder", "left_elbow", "right_elbow", "left_wrist", "right_wrist", "left_hip", "right_hip", "left_knee", "right_knee", "left_ankle", "right_ankle" ]
class OOPDetector: """OOP异常姿态检测器""" def __init__(self): self.normal_sitting = { 'torso_angle': 90, 'head_angle': 0, 'shoulder_symmetry': 0, 'hip_position': 'seat', } def classify_posture(self, keypoints_3d: np.ndarray) -> dict: """ 基于3D关键点分类乘员姿态 Args: keypoints_3d: shape=(17, 3), 3D坐标(x,y,z) 单位cm Returns: posture classification """ shoulder_mid = (keypoints_3d[5] + keypoints_3d[6]) / 2 hip_mid = (keypoints_3d[11] + keypoints_3d[12]) / 2 torso_vec = shoulder_mid - hip_mid torso_angle = np.degrees(np.arctan2(torso_vec[1], np.sqrt(torso_vec[0]**2 + torso_vec[2]**2))) head_vec = keypoints_3d[0] - shoulder_mid head_yaw = np.degrees(np.arctan2(head_vec[0], head_vec[2])) head_pitch = np.degrees(np.arctan2(head_vec[1], np.sqrt(head_vec[0]**2 + head_vec[2]**2))) shoulder_z_diff = abs(keypoints_3d[5][2] - keypoints_3d[6][2]) knee_mid = (keypoints_3d[13] + keypoints_3d[14]) / 2 leg_vec = knee_mid - hip_mid leg_angle = np.degrees(np.arctan2(leg_vec[1], np.sqrt(leg_vec[0]**2 + leg_vec[2]**2))) posture = "normal" risk_level = 0 if torso_angle < 50: posture = "reclined_excessive" risk_level = 3 elif torso_angle < 65: posture = "reclined_moderate" risk_level = 2 if abs(head_yaw) > 60: posture = "looking_sideways" if posture == "normal" else posture + "+sideways" risk_level = max(risk_level, 2) if abs(head_yaw) > 120: posture = "rear_facing" risk_level = 3 if torso_angle > 110: posture = "leaning_forward" risk_level = 3 if leg_angle > 80 and keypoints_3d[15][1] > keypoints_3d[11][1]: posture = "feet_on_dash" if posture == "normal" else posture + "+feet_up" risk_level = max(risk_level, 2) return { 'posture': posture, 'risk_level': risk_level, 'torso_angle': round(float(torso_angle), 1), 'head_yaw': round(float(head_yaw), 1), 'head_pitch': round(float(head_pitch), 1), 'shoulder_z_diff': round(float(shoulder_z_diff), 2), 'leg_angle': round(float(leg_angle), 1), 'submarining_risk': self.estimate_submarining(torso_angle) } def estimate_submarining(self, torso_angle: float) -> str: """基于躯干角度估计submarining风险""" if torso_angle >= 90: return "低" elif torso_angle >= 65: return "中" elif torso_angle >= 50: return "高" else: return "极高"
if __name__ == "__main__": det = OOPDetector() normal_kp = np.array([ [0, 50, 30], [-2, 52, 30], [2, 52, 30], [-5, 50, 30], [5, 50, 30], [0, 45, 25], [0, 45, 25], [0, 35, 25], [0, 35, 25], [0, 25, 25], [0, 25, 25], [0, 20, 25], [0, 20, 25], [0, 10, 28], [0, 10, 28], [0, 0, 30], [0, 0, 30], ], dtype=float) r1 = det.classify_posture(normal_kp) print(f"正常坐姿: {r1['posture']} (风险={r1['risk_level']}, 躯干={r1['torso_angle']}°)") print(f" Submarining风险: {r1['submarining_risk']}") reclined_kp = normal_kp.copy() reclined_kp[5:7, 1] -= 15 reclined_kp[5:7, 2] += 20 reclined_kp[11:13, 1] -= 5 r2 = det.classify_posture(reclined_kp) print(f"\n后靠坐姿: {r2['posture']} (风险={r2['risk_level']}, 躯干={r2['torso_angle']}°)") print(f" Submarining风险: {r2['submarining_risk']}")
|