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
| import numpy as np from scipy.stats import entropy
def extract_gaze_features(gaze_x, gaze_y, fixations, saccades, pupil_diameter): """ 从IDD数据集提取损伤检测关键特征 Args: gaze_x: (N,) 水平视线位置 0-1 gaze_y: (N,) 垂直视线位置 0-1 fixations: list of (start, end, duration) saccades: list of (start, end, amplitude) pupil_diameter: (N,) 瞳孔直径 mm Returns: features: dict, 用于损伤分类的特征向量 """ features = {} hist_2d, _, _ = np.histogram2d(gaze_x, gaze_y, bins=20) hist_2d_norm = hist_2d / hist_2d.sum() features['gaze_entropy'] = entropy(hist_2d_norm.flatten()) fix_durations = [f[2] for f in fixations] features['fixation_count'] = len(fixations) features['mean_fixation_duration'] = np.mean(fix_durations) features['fixation_rate'] = len(fixations) / (len(gaze_x) / 60) saccade_amplitudes = [s[2] for s in saccades] features['saccade_count'] = len(saccades) features['mean_saccade_amplitude'] = np.mean(saccade_amplitudes) if saccade_amplitudes else 0 features['pupil_mean'] = np.mean(pupil_diameter) features['pupil_std'] = np.std(pupil_diameter) features['pupil_trend'] = np.polyfit(range(len(pupil_diameter)), pupil_diameter, 1)[0] features['gaze_x_std'] = np.std(gaze_x) features['gaze_y_std'] = np.std(gaze_y) features['gaze_spread'] = np.sqrt( np.var(gaze_x) + np.var(gaze_y) ) return features
from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import cross_val_score
def train_impairment_classifier(features_dict, labels): """ 使用IDD提取的特征训练损伤分类器 Args: features_dict: list of feature dicts labels: 0=正常, 1=认知分心, 2=酒精损伤, 3=复合 Returns: clf: 训练好的分类器 """ feature_names = list(features_dict[0].keys()) X = np.array([[f[k] for k in feature_names] for f in features_dict]) y = np.array(labels) clf = RandomForestClassifier(n_estimators=100, max_depth=10, random_state=42) scores = cross_val_score(clf, X, y, cv=10, scoring='f1_macro') print(f"损伤分类器性能:") print(f" 特征数: {len(feature_names)}") print(f" 10折交叉验证 F1: {scores.mean():.3f} ± {scores.std():.3f}") clf.fit(X, y) importances = sorted(zip(feature_names, clf.feature_importances_), key=lambda x: -x[1]) print(f"\n特征重要性排序:") for name, imp in importances: print(f" {name}: {imp:.4f}") return clf
if __name__ == "__main__": np.random.seed(42) n_samples = 60 * 60 normal_gaze_x = np.random.normal(0.5, 0.15, n_samples) normal_gaze_y = np.random.normal(0.3, 0.12, n_samples) normal_pupil = np.random.normal(4.0, 0.3, n_samples) cog_gaze_x = np.random.normal(0.5, 0.08, n_samples) cog_gaze_y = np.random.normal(0.25, 0.06, n_samples) cog_pupil = np.random.normal(4.2, 0.4, n_samples) alc_gaze_x = np.random.normal(0.5, 0.05, n_samples) alc_gaze_y = np.random.normal(0.2, 0.04, n_samples) alc_pupil = np.random.normal(3.8, 0.2, n_samples) print("正常驾驶特征:") normal_feat = extract_gaze_features( normal_gaze_x, normal_gaze_y, [(0, 60, 0.3)] * 80, [(60, 65, 5)] * 40, normal_pupil ) for k, v in normal_feat.items(): print(f" {k}: {v:.4f}") print("\n认知分心特征:") cog_feat = extract_gaze_features( cog_gaze_x, cog_gaze_y, [(0, 60, 0.5)] * 50, [(60, 65, 3)] * 25, cog_pupil ) for k, v in cog_feat.items(): print(f" {k}: {v:.4f}") print("\n酒精损伤特征:") alc_feat = extract_gaze_features( alc_gaze_x, alc_gaze_y, [(0, 60, 0.7)] * 30, [(60, 65, 2)] * 15, alc_pupil ) for k, v in alc_feat.items(): print(f" {k}: {v:.4f}") print("\n" + "=" * 50) print("隧道视觉量化 (gaze_spread):") print(f" 正常: {normal_feat['gaze_spread']:.4f}") print(f" 认知分心: {cog_feat['gaze_spread']:.4f} (×{cog_feat['gaze_spread']/normal_feat['gaze_spread']:.2f})") print(f" 酒精损伤: {alc_feat['gaze_spread']:.4f} (×{alc_feat['gaze_spread']/normal_feat['gaze_spread']:.2f})")
|