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 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
| """ Euro NCAP 2026 异常姿态检测人体建模 基于深度摄像头的3D人体姿态重建
关键技术: 1. 深度图像处理(Intel RealSense D435) 2. 人体3D关键点提取 3. 头部-仪表板距离计算 4. 脚部姿态分类 """
import numpy as np import cv2 from typing import Dict, Tuple, Optional from dataclasses import dataclass
@dataclass class OccupantPose3D: """乘员3D姿态数据结构""" head_position_3d: Tuple[float, float, float] head_distance_to_dashboard: float left_foot_position_3d: Tuple[float, float, float] right_foot_position_3d: Tuple[float, float, float] left_foot_on_dashboard: bool right_foot_on_dashboard: bool foot_posture_class: str pose_confidence: float
class DepthCameraOccupantMonitor: """ 深度摄像头乘员监控系统 使用Intel RealSense D435深度摄像头进行: - 人体3D关键点提取 - 头部距离计算 - 脚部姿态分类 硬件配置: - Intel RealSense D435 - Depth: 1280×720, 30fps - RGB: 1920×1080, 30fps - Depth range: 0.1m - 10m """ def __init__(self, dashboard_baseline_distance_cm: float = 80.0, head_proximity_threshold_cm: float = 20.0): """ Args: dashboard_baseline_distance_cm: 仪表板基准距离(正常坐姿下头部距离) head_proximity_threshold_cm: 头部靠近阈值(Euro NCAP要求20cm) """ self.dashboard_baseline = dashboard_baseline_distance_cm self.head_proximity_threshold = head_proximity_threshold_cm self.dashboard_reference_3d = (0.0, 0.0, 0.0) def process_depth_frame(self, depth_image: np.ndarray, rgb_image: np.ndarray) -> Optional[OccupantPose3D]: """ 处理深度帧,提取乘员姿态 Args: depth_image: 深度图像(H×W,单位:mm) rgb_image: RGB图像(H×W×3) Returns: OccupantPose3D: 乘员3D姿态数据,若检测失败返回None """ occupant_mask = self._segment_occupant(depth_image) if np.sum(occupant_mask) == 0: return None keypoints_2d = self._detect_body_keypoints_rgb(rgb_image, occupant_mask) if keypoints_2d is None: return None keypoints_3d = self._convert_keypoints_to_3d(keypoints_2d, depth_image) head_position = keypoints_3d.get('head', (0, 0, 0)) head_distance = self._calculate_head_distance(head_position) left_foot = keypoints_3d.get('left_foot', (0, 0, 0)) right_foot = keypoints_3d.get('right_foot', (0, 0, 0)) left_foot_on_dash = self._detect_foot_on_dashboard(left_foot) right_foot_on_dash = self._detect_foot_on_dashboard(right_foot) foot_posture = self._classify_foot_posture(left_foot, right_foot) depth_quality = np.mean(depth_image[occupant_mask > 0]) pose_confidence = min(1.0, depth_quality / 5000.0) return OccupantPose3D( head_position_3d=head_position, head_distance_to_dashboard=head_distance, left_foot_position_3d=left_foot, right_foot_position_3d=right_foot, left_foot_on_dashboard=left_foot_on_dash, right_foot_on_dashboard=right_foot_on_dash, foot_posture_class=foot_posture, pose_confidence=pose_confidence ) def _segment_occupant(self, depth_image: np.ndarray) -> np.ndarray: """ 人体分割(基于深度阈值) 分割逻辑: - 前排座椅区域:深度500mm - 1500mm - 排除背景(仪表板、车窗等) """ h, w = depth_image.shape min_depth_mm = 500 max_depth_mm = 1500 occupant_mask = ((depth_image > min_depth_mm) & (depth_image < max_depth_mm)).astype(np.uint8) kernel = np.ones((5, 5), np.uint8) occupant_mask = cv2.morphologyEx(occupant_mask, cv2.MORPH_OPEN, kernel) occupant_mask = cv2.morphologyEx(occupant_mask, cv2.MORPH_CLOSE, kernel) return occupant_mask def _detect_body_keypoints_rgb(self, rgb_image: np.ndarray, occupant_mask: np.ndarray) -> Optional[Dict[str, Tuple[int, int]]]: """ 人体关键点检测(RGB图像) 关键点需求: - 头部(头部顶部位置) - 左脚/右脚(脚部位置) 使用MediaPipe Pose或自定义模型 """ y_coords, x_coords = np.where(occupant_mask > 0) if len(y_coords) == 0: return None head_y = np.min(y_coords) head_x = int(np.mean(x_coords[y_coords == head_y])) foot_y = np.max(y_coords) foot_left_x = int(np.percentile(x_coords[y_coords == foot_y], 25)) foot_right_x = int(np.percentile(x_coords[y_coords == foot_y], 75)) return { 'head': (head_x, head_y), 'left_foot': (foot_left_x, foot_y), 'right_foot': (foot_right_x, foot_y) } def _convert_keypoints_to_3d(self, keypoints_2d: Dict[str, Tuple[int, int]], depth_image: np.ndarray) -> Dict[str, Tuple[float, float, float]]: """ 关键点2D→3D转换 Args: keypoints_2d: 2D关键点坐标(像素坐标) depth_image: 深度图像 Returns: keypoints_3d: 3D坐标(单位:cm) """ keypoints_3d = {} fx, fy = 610.0, 610.0 cx, cy = 320.0, 240.0 for key, (x, y) in keypoints_2d.items(): if 0 <= y < depth_image.shape[0] and 0 <= x < depth_image.shape[1]: depth_mm = depth_image[y, x] z_cm = depth_mm / 10.0 x_cm = (x - cx) * z_cm / fx y_cm = (y - cy) * z_cm / fy keypoints_3d[key] = (x_cm, y_cm, z_cm) else: keypoints_3d[key] = (0.0, 0.0, 0.0) return keypoints_3d def _calculate_head_distance(self, head_position: Tuple[float, float, float]) -> float: """ 计算头部距仪表板距离 Euro NCAP要求: - 仪表板基准距离:正常坐姿下头部距离 - 当前距离:实时测量 - 距离差值:当前距离 - 基准距离 Args: head_position: 头部3D坐标 Returns: distance_to_dashboard: 头部距仪表板距离(cm) """ dashboard_z = 0.0 head_z = head_position[2] distance_to_dashboard = head_z - dashboard_z return distance_to_dashboard def _detect_foot_on_dashboard(self, foot_position: Tuple[float, float, float]) -> bool: """ 检测脚是否放在仪表板 判定逻辑: - 脚部Z坐标 < 仪表板基准距离的50%(说明脚部抬高) - 脚部Y坐标 < 正常坐姿脚部高度(说明脚部在仪表板区域) Args: foot_position: 脚部3D坐标 Returns: is_on_dashboard: 是否在仪表板 """ foot_z = foot_position[2] foot_y = foot_position[1] is_elevated = foot_z < (self.dashboard_baseline * 0.5) dashboard_height_threshold_cm = 30.0 is_in_dashboard_region = foot_y < dashboard_height_threshold_cm return is_elevated and is_in_dashboard_region def _classify_foot_posture(self, left_foot: Tuple[float, float, float], right_foot: Tuple[float, float, float]) -> str: """ 脚部姿态分类 Euro NCAP要求三种姿态: - Inboard:脚偏向车内侧(X坐标偏向车内) - Centerline:脚沿座椅中心线(X坐标居中) - Outboard:脚偏向车外侧(X坐标偏向车外) Args: left_foot: 左脚3D坐标 right_foot: 右脚3D坐标 Returns: posture_class: 姿态分类 """ left_x = left_foot[0] right_x = right_foot[0] centerline_x = 0.0 left_on_dash = self._detect_foot_on_dashboard(left_foot) right_on_dash = self._detect_foot_on_dashboard(right_foot) if not left_on_dash and not right_on_dash: return "normal" avg_x = (left_x + right_x) / 2.0 offset_threshold = 10.0 if avg_x < -offset_threshold: return "inboard" elif avg_x > offset_threshold: return "outboard" else: return "centerline"
if __name__ == "__main__": monitor = DepthCameraOccupantMonitor( dashboard_baseline_distance_cm=80.0, head_proximity_threshold_cm=20.0 ) h, w = 720, 1280 depth_test = np.zeros((h, w), dtype=np.uint16) depth_test[100:500, 200:800] = 1000 rgb_test = np.zeros((h, w, 3), dtype=np.uint8) pose = monitor.process_depth_frame(depth_test, rgb_test) if pose: print(f"=== 乘员姿态检测结果 ===") print(f"头部位置:{pose.head_position_3d}") print(f"头部距仪表板:{pose.head_distance_to_dashboard:.2f} cm") print(f"左脚在仪表板:{pose.left_foot_on_dashboard}") print(f"右脚在仪表板:{pose.right_foot_on_dashboard}") print(f"脚部姿态:{pose.foot_posture_class}") print(f"置信度:{pose.pose_confidence:.3f}")
|