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
| import numpy as np from typing import Tuple, List from scipy.stats import entropy
class SpatialGazeEntropy: """ 空间视线熵计算器 论文参考: - "Discriminative Capabilities of Eye Gaze Measures for Cognitive Load Evaluation" PMC, 2024 核心思想: - 将视野划分为网格 - 统计视线落在每个格子的频率 - 计算分布的熵值 - 熵越高,视线越分散(认知分心) """ def __init__(self, grid_size: Tuple[int, int] = (10, 10), range_x: Tuple[float, float] = (-1.0, 1.0), range_y: Tuple[float, float] = (-0.5, 0.5)): """ Args: grid_size: 网格大小 (rows, cols) range_x: 视线X范围(归一化) range_y: 视线Y范围(归一化) """ self.grid_size = grid_size self.range_x = range_x self.range_y = range_y def compute(self, gaze_positions: np.ndarray, normalize: bool = True) -> float: """ 计算空间视线熵 Args: gaze_positions: 视线位置序列 (N, 2),归一化坐标 normalize: 是否归一化到[0, 1] Returns: SGE值 (0-1) """ x_bins = np.linspace(self.range_x[0], self.range_x[1], self.grid_size[1] + 1) y_bins = np.linspace(self.range_y[0], self.range_y[1], self.grid_size[0] + 1) hist, _, _ = np.histogram2d( gaze_positions[:, 0], gaze_positions[:, 1], bins=[x_bins, y_bins] ) prob = hist.flatten() / hist.sum() prob = prob[prob > 0] sge = entropy(prob, base=2) if normalize: max_entropy = np.log2(self.grid_size[0] * self.grid_size[1]) sge = sge / max_entropy return sge def compute_sliding_window(self, gaze_positions: np.ndarray, window_size: int = 300, stride: int = 30) -> np.ndarray: """ 滑动窗口计算SGE序列 Args: gaze_positions: 视线位置序列 (N, 2) window_size: 窗口大小(帧数) stride: 步长(帧数) Returns: SGE序列 """ sge_values = [] for i in range(0, len(gaze_positions) - window_size, stride): window = gaze_positions[i:i+window_size] sge = self.compute(window) sge_values.append(sge) return np.array(sge_values)
if __name__ == "__main__": sge_calculator = SpatialGazeEntropy() np.random.seed(42) normal_gaze = np.random.normal(0, 0.1, (300, 2)) normal_sge = sge_calculator.compute(normal_gaze) distracted_gaze = np.random.uniform(-0.8, 0.8, (300, 2)) distracted_sge = sge_calculator.compute(distracted_gaze) print(f"正常驾驶 SGE: {normal_sge:.3f}") print(f"认知分心 SGE: {distracted_sge:.3f}") print(f"差异: {distracted_sge - normal_sge:.3f}")
|