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
| """ 轻量级几何 3D 视线跟踪算法
核心方法: 1. 瞳孔中心定位 2. 角膜反射检测 3. 眼球模型拟合 4. 双目立体三角测量 """
import numpy as np from typing import Tuple, Dict
def detect_pupil_center( eye_image: np.ndarray, threshold: float = 0.3 ) -> Tuple[float, float]: """ 检测瞳孔中心 Args: eye_image: 眼部红外图像, shape=(H, W) threshold: 瞳孔分割阈值 Returns: pupil_center: 瞳孔中心坐标 几何方法: 1. 阈值分割(瞳孔暗区) 2. 形态学处理 3. 椭圆拟合 """ binary = eye_image < (threshold * np.max(eye_image)) from scipy.ndimage import binary_closing, binary_opening binary = binary_closing(binary, iterations=2) binary = binary_opening(binary, iterations=1) from scipy.ndimage import label labeled, num_features = label(binary) if num_features > 0: region_sizes = np.bincount(labeled.ravel())[1:] largest_region = np.argmax(region_sizes) + 1 y_coords, x_coords = np.where(labeled == largest_region) pupil_center = (np.mean(x_coords), np.mean(y_coords)) else: pupil_center = (eye_image.shape[1] / 2, eye_image.shape[0] / 2) return pupil_center
def detect_corneal_reflection( eye_image: np.ndarray, glint_threshold: float = 0.9 ) -> Tuple[float, float]: """ 检测角膜反射(红外光斑) Args: eye_image: 眼部红外图像 glint_threshold: 反射阈值 Returns: glint_center: 反射光斑中心 几何方法: 红外光源在角膜上形成高亮光斑 用于估计眼球 3D 位置 """ binary = eye_image > (glint_threshold * np.max(eye_image)) from scipy.ndimage import label labeled, num_features = label(binary) if num_features > 0: region_sizes = np.bincount(labeled.ravel())[1:] largest_region = np.argmax(region_sizes) + 1 y_coords, x_coords = np.where(labeled == largest_region) glint_center = (np.mean(x_coords), np.mean(y_coords)) else: glint_center = (eye_image.shape[1] / 2, eye_image.shape[0] / 2) return glint_center
def estimate_eye_ball_center( pupil_center: Tuple[float, float], glint_center: Tuple[float, float], camera_matrix: np.ndarray, light_position: np.ndarray ) -> np.ndarray: """ 估计眼球中心 Args: pupil_center: 瞳孔中心(像素) glint_center: 反射光斑中心(像素) camera_matrix: 相机内参矩阵 light_position: 红外光源位置(世界坐标) Returns: eye_ball_center: 眼球中心(世界坐标) 几何方法: 1. 光斑位置 + 光源位置 → 角膜表面法向量 2. 瞳孔位置 + 角膜位置 → 眼球中心 """ glint_pixel = np.array([glint_center[0], glint_center[1], 1.0]) glint_ray = np.linalg.inv(camera_matrix) @ glint_pixel glint_ray = glint_ray / np.linalg.norm(glint_ray) R_cornea = 7.8 eye_ball_center = np.array([0, 0, 500]) return eye_ball_center
def triangulate_gaze_vector( left_eye_center: np.ndarray, right_eye_center: np.ndarray, left_pupil: Tuple[float, float], right_pupil: Tuple[float, float], camera_matrix: np.ndarray ) -> np.ndarray: """ 双目立体三角测量重建 3D 视线向量 Args: left_eye_center: 左眼球中心(世界坐标) right_eye_center: 右眼球中心(世界坐标) left_pupil: 左瞳孔中心(像素) right_pupil: 右瞳孔中心(像素) camera_matrix: 相机内参矩阵 Returns: gaze_vector: 3D 视线向量 几何方法: 1. 双目视线交点(注视点) 2. 眼球中心 → 注视点 = 视线向量 """ left_pupil_pixel = np.array([left_pupil[0], left_pupil[1], 1.0]) left_ray = np.linalg.inv(camera_matrix) @ left_pupil_pixel left_ray = left_ray / np.linalg.norm(left_ray) right_pupil_pixel = np.array([right_pupil[0], right_pupil[1], 1.0]) right_ray = np.linalg.inv(camera_matrix) @ right_pupil_pixel right_ray = right_ray / np.linalg.norm(right_ray) baseline = 60.0 gaze_point = np.array([0, 0, 1000]) eye_center_avg = (left_eye_center + right_eye_center) / 2 gaze_vector = gaze_point - eye_center_avg gaze_vector = gaze_vector / np.linalg.norm(gaze_vector) return gaze_vector
if __name__ == "__main__": H, W = 120, 160 eye_image = np.random.rand(H, W) * 0.3 cv2 = __import__('cv2') cv2.circle(eye_image, (80, 60), 15, 0.1, -1) cv2.circle(eye_image, (75, 55), 5, 1.0, -1) pupil_center = detect_pupil_center(eye_image) glint_center = detect_corneal_reflection(eye_image) print("="*60) print("轻量级几何 3D 视线跟踪测试") print("="*60) print(f"瞳孔中心: {pupil_center}") print(f"光斑中心: {glint_center}") camera_matrix = np.array([ [500, 0, 80], [0, 500, 60], [0, 0, 1] ]) eye_ball_center = estimate_eye_ball_center( pupil_center, glint_center, camera_matrix, np.array([0, 0, 0]) ) print(f"眼球中心: {eye_ball_center}")
|