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
| import numpy as np from typing import List, Dict, Tuple
class SeatbeltDetector: """ 安全带检测器 检测流程: 1. 乘员检测 → 确定ROI 2. 安全带分割 → 提取安全带区域 3. 关键点检测 → 肩部、腰部、扣点 4. 路径分析 → 判断误用 """ def __init__(self): self.belt_colors = { 'black': (np.array([0, 0, 0]), np.array([50, 50, 50])), 'gray': (np.array([100, 100, 100]), np.array([200, 200, 200])), 'beige': (np.array([180, 160, 120]), np.array([220, 200, 160])) } self.belt_width_range = (20, 60) self.KEYPOINTS = { 'shoulder_point': 0, 'upper_torso': 1, 'hip_point': 2, 'buckle': 3, 'lap_belt_left': 4, 'lap_belt_right': 5 } def detect(self, frame: np.ndarray, occupant_box: Tuple[int, int, int, int]) -> Dict: """ 检测安全带状态 Args: frame: RGB图像 occupant_box: 乘员边界框 (x1, y1, x2, y2) Returns: result: 检测结果 """ x1, y1, x2, y2 = occupant_box roi = frame[y1:y2, x1:x2] belt_mask = self.segment_belt(roi) keypoints = self.detect_keypoints(belt_mask, roi) misuse = self.analyze_misuse(keypoints) return { 'belt_detected': len(keypoints) > 0, 'keypoints': keypoints, 'misuse_type': misuse['type'], 'misuse_detected': misuse['type'] != 'proper', 'confidence': misuse['confidence'] } def segment_belt(self, roi: np.ndarray) -> np.ndarray: """ 分割安全带区域 Args: roi: 乘员ROI Returns: mask: 安全带二值掩码 """ import cv2 hsv = cv2.cvtColor(roi, cv2.COLOR_RGB2HSV) lower, upper = self.belt_colors['black'] mask = cv2.inRange(roi, lower, upper) kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) belt_mask = np.zeros_like(mask) for contour in contours: x, y, w, h = cv2.boundingRect(contour) aspect_ratio = max(w, h) / (min(w, h) + 1e-7) if aspect_ratio > 3 and w > 10 and h > 10: cv2.drawContours(belt_mask, [contour], -1, 255, -1) return belt_mask def detect_keypoints(self, belt_mask: np.ndarray, roi: np.ndarray) -> Dict: """ 检测安全带关键点 Args: belt_mask: 安全带掩码 roi: 原始ROI Returns: keypoints: 关键点坐标 """ import cv2 keypoints = {} skeleton = cv2.ximgproc.thinning(belt_mask) belt_points = np.where(skeleton > 0) if len(belt_points[0]) == 0: return keypoints points = np.column_stack([belt_points[0], belt_points[1]]) top_points = points[points[:, 0] < roi.shape[0] * 0.3] if len(top_points) > 0: keypoints['shoulder_point'] = top_points[np.argmin(top_points[:, 1])] bottom_points = points[points[:, 0] > roi.shape[0] * 0.6] if len(bottom_points) > 0: keypoints['buckle'] = bottom_points[ np.argmin(np.abs(bottom_points[:, 1] - roi.shape[1] * 0.5)) ] return keypoints def analyze_misuse(self, keypoints: Dict) -> Dict: """ 分析安全带误用 Args: keypoints: 关键点 Returns: misuse: 误用分析结果 """ misuse_type = 'proper' confidence = 0.5 if 'shoulder_point' not in keypoints: misuse_type = 'lap_only' confidence = 0.8 elif 'buckle' not in keypoints: misuse_type = 'not_buckled' confidence = 0.9 return { 'type': misuse_type, 'confidence': confidence }
|