视线熵指标:认知分心检测的核心突破

核心发现

2024-2025年多项研究表明,视线熵(Gaze Entropy)指标是区分认知分心等级最有效的单一指标,准确率显著超越传统PERCLOS方法。

graph TD
    A[认知分心挑战] --> B{解决方案}
    B --> C[传统方法失效]
    B --> D[视线熵突破]
    
    C --> C1[PERCLOS无法区分认知分心]
    C --> C2[眼动轨迹无规则]
    C --> C3[缺乏量化指标]
    
    D --> D1[空间视线熵SGE]
    D --> D2[时间视线熵GTE]
    D --> D3[组合指标最佳]
    
    D3 --> E[准确率提升20%+]
    
    style D fill:#c8e6c9
    style E fill:#a5d6a7

认知分心 vs 视觉分心:本质区别

问题定义

类型 定义 表现特征 传统检测方法
视觉分心 视线偏离道路(看手机、导航等) 眼睛看向非道路区域 ✅ 视线落点检测有效
认知分心 思维游离(走神、思考问题) 视线在道路上但”心不在焉” ❌ 传统方法失效

为什么认知分心难以检测?

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
"""
认知分心的检测难点

核心问题:
- 驾驶员视线仍然看向道路
- 眼睛没有明显偏离
- 但注意资源被认知任务占用
- 导致对突发事件的反应延迟

传统PERCLOS失效原因:
- PERCLOS衡量"闭眼时长"
- 认知分心时眼睛是睁开的
- 无法通过眼睑开度检测

需要的新思路:
- 分析视线"如何"看,而非"看哪里"
- 眼动轨迹的"熵"(随机性)是关键
"""

import numpy as np

def explain_cognitive_distraction():
"""
认知分心的视线特征

正常驾驶:
- 眼动轨迹有规律(看前方、扫视后视镜、检查仪表)
- 空间分布相对集中
- 时间序列有周期性

认知分心:
- 眼动轨迹变得"随机"(试图集中但失败)
- 空间分布更分散
- 时间序列不规则
- "凝视但未真正看"的状态
"""
pass

视线熵指标详解

1. 空间视线熵(Spatial Gaze Entropy, SGE)

定义:衡量视线在空间中的分布离散程度

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()

# 去除零值(避免log(0))
prob = prob[prob > 0]

# 计算熵
sge = entropy(prob, base=2)

# 归一化到[0, 1](最大熵为log2(n_bins))
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, # 10秒 @ 30fps
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}")

2. 时间视线熵(Gaze Transition Entropy, GTE)

定义:衡量视线转移模式的规律性

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
class GazeTransitionEntropy:
"""
时间视线熵计算器

核心思想:
- 统计视线从一个区域转移到另一个区域的概率
- 构建转移概率矩阵
- 计算转移序列的熵
- 熵越高,转移越随机(认知分心)
"""

def __init__(self, grid_size: Tuple[int, int] = (5, 5)):
self.grid_size = grid_size
self.n_states = grid_size[0] * grid_size[1]

def compute(self, gaze_positions: np.ndarray) -> float:
"""
计算时间视线熵

Args:
gaze_positions: 视线位置序列 (N, 2)

Returns:
GTE值
"""
# 量化视线位置到网格索引
indices = self._quantize_to_grid(gaze_positions)

# 构建转移矩阵
trans_matrix = self._build_transition_matrix(indices)

# 计算条件熵 H(next_state | current_state)
gte = 0.0

for i in range(self.n_states):
if trans_matrix[i].sum() > 0:
# 归一化转移概率
probs = trans_matrix[i] / trans_matrix[i].sum()
probs = probs[probs > 0]
# 条件熵贡献
gte -= np.sum(probs * np.log2(probs)) * (trans_matrix[i].sum() / trans_matrix.sum())

return gte

def _quantize_to_grid(self, positions: np.ndarray) -> np.ndarray:
"""将连续位置量化到网格索引"""
# 归一化到[0, 1]
pos_norm = (positions - positions.min(axis=0)) / (positions.max(axis=0) - positions.min(axis=0) + 1e-8)

# 量化到网格
grid_x = (pos_norm[:, 0] * (self.grid_size[1] - 1)).astype(int)
grid_y = (pos_norm[:, 1] * (self.grid_size[0] - 1)).astype(int)

# 转换为线性索引
indices = grid_y * self.grid_size[1] + grid_x

return indices

def _build_transition_matrix(self, indices: np.ndarray) -> np.ndarray:
"""构建转移概率矩阵"""
trans_matrix = np.zeros((self.n_states, self.n_states))

for i in range(len(indices) - 1):
from_state = indices[i]
to_state = indices[i + 1]
trans_matrix[from_state, to_state] += 1

return trans_matrix


# 使用示例
if __name__ == "__main__":
gte_calculator = GazeTransitionEntropy()

# 模拟有规律的视线转移(正常)
np.random.seed(42)
regular_pattern = np.zeros((300, 2))
for i in range(300):
phase = i / 30 # 每秒一个周期
regular_pattern[i, 0] = 0.3 * np.sin(phase * 2 * np.pi)
regular_pattern[i, 1] = 0.2 * np.cos(phase * 2 * np.pi)
regular_gte = gte_calculator.compute(regular_pattern)

# 模拟随机转移(认知分心)
random_pattern = np.random.randn(300, 2) * 0.5
random_gte = gte_calculator.compute(random_pattern)

print(f"规律转移 GTE: {regular_gte:.3f}")
print(f"随机转移 GTE: {random_gte:.3f}")

3. 组合指标:SGE + GTE

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
class CognitiveDistractionDetector:
"""
认知分心综合检测器

论文结论:
- SGE和GTE组合效果最佳
- 单独使用SGE准确率约75%
- 单独使用GTE准确率约70%
- 组合后准确率提升至85%+
"""

def __init__(self,
sge_threshold: float = 0.65,
gte_threshold: float = 2.5,
window_size: int = 300):
self.sge_threshold = sge_threshold
self.gte_threshold = gte_threshold
self.window_size = window_size

self.sge_calc = SpatialGazeEntropy()
self.gte_calc = GazeTransitionEntropy()

def detect(self, gaze_positions: np.ndarray) -> Tuple[bool, float, dict]:
"""
检测认知分心状态

Args:
gaze_positions: 视线位置序列 (N, 2)

Returns:
(is_distracted, confidence, metrics)
"""
# 计算指标
sge = self.sge_calc.compute(gaze_positions)
gte = self.gte_calc.compute(gaze_positions)

# 组合判断
sge_score = 1.0 if sge > self.sge_threshold else sge / self.sge_threshold
gte_score = 1.0 if gte > self.gte_threshold else gte / self.gte_threshold

# 加权组合(SGE权重更高)
combined_score = 0.6 * sge_score + 0.4 * gte_score

# 判断
is_distracted = combined_score > 0.6
confidence = combined_score

metrics = {
'SGE': sge,
'GTE': gte,
'SGE_score': sge_score,
'GTE_score': gte_score,
'combined': combined_score
}

return is_distracted, confidence, metrics

def analyze_time_series(self,
gaze_stream: np.ndarray,
stride: int = 30) -> List[dict]:
"""
分析时间序列,检测认知分心时段

Args:
gaze_stream: 完整视线数据流 (N, 2)
stride: 分析步长

Returns:
每个窗口的检测结果
"""
results = []

for i in range(0, len(gaze_stream) - self.window_size, stride):
window = gaze_stream[i:i+self.window_size]
is_distracted, confidence, metrics = self.detect(window)

results.append({
'start_frame': i,
'end_frame': i + self.window_size,
'is_distracted': is_distracted,
'confidence': confidence,
**metrics
})

return results

论文实验结果对比

研究 方法 数据集 准确率 备注
PMC 2024 SGE 模拟器实验 78% 认知负荷区分
PMC 2024 GTE 模拟器实验 72% 转移规律性
PMC 2024 SGE+GTE 模拟器实验 86% 最佳组合
ScienceDirect 2025 转向熵 真实驾驶 81% 行为指标补充
IEEE 2024 D-FFNN 多模态 84% 眼动+车辆行为

Euro NCAP 2026 认知分心要求

当前状态

Euro NCAP 2026对认知分心的态度:

项目 状态 备注
评分纳入 ⚠️ 研讨中 尚未明确纳入
技术路线 ❓ 未定 视线熵有潜力
阈值标准 ❌ 未定义 需要行业标准
验证方法 ❌ 未定义 需要可重复实验

技术建议

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
class EuroNCAPComplianceChecker:
"""
Euro NCAP认知分心合规检查

建议方案:
1. 采用SGE+GTE组合指标
2. 阈值基于大数据统计
3. 提供可追溯的证据链
"""

def __init__(self):
self.required_metrics = ['SGE', 'GTE', 'confidence']
self.min_accuracy = 0.80 # 目标准确率

def validate_detection(self,
detections: List[dict],
ground_truth: List[bool]) -> dict:
"""
验证检测结果是否符合Euro NCAP要求

Args:
detections: 检测结果列表
ground_truth: 真实标签列表

Returns:
验证报告
"""
# 计算准确率
correct = sum(
1 for det, gt in zip(detections, ground_truth)
if det['is_distracted'] == gt
)
accuracy = correct / len(ground_truth)

# 计算混淆矩阵
tp = sum(1 for det, gt in zip(detections, ground_truth) if det['is_distracted'] and gt)
fp = sum(1 for det, gt in zip(detections, ground_truth) if det['is_distracted'] and not gt)
tn = sum(1 for det, gt in zip(detections, ground_truth) if not det['is_distracted'] and not gt)
fn = sum(1 for det, gt in zip(detections, ground_truth) if not det['is_distracted'] and gt)

precision = tp / (tp + fp) if (tp + fp) > 0 else 0
recall = tp / (tp + fn) if (tp + fn) > 0 else 0
f1 = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0

return {
'accuracy': accuracy,
'precision': precision,
'recall': recall,
'f1_score': f1,
'confusion_matrix': {
'TP': tp, 'FP': fp,
'TN': tn, 'FN': fn
},
'compliant': accuracy >= self.min_accuracy
}

IMS开发实施计划

第一阶段:数据采集(4周)

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
DATA_COLLECTION_PLAN = {
"scenarios": [
"高速公路巡航(认知任务:n-back测试)",
"城市道路(认知任务:心算)",
"复杂路况(认知任务:回忆任务)"
],

"cognitive_load_levels": [
"无负荷(正常驾驶)",
"低负荷(简单心算)",
"中负荷(双任务)",
"高负荷(复杂n-back)"
],

"metrics_to_record": [
"视线位置 (x, y)",
"眨眼事件",
"瞳孔直径",
"车辆行为(转向、速度)"
],

"min_samples": 5000, # 每个负荷等级

"validation": "主观报告(NASA-TLX量表)"
}

第二阶段:模型训练(3周)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
TRAINING_PIPELINE = {
"features": [
"SGE(空间视线熵)",
"GTE(时间视线熵)",
"眨眼频率变化",
"瞳孔直径变异",
"转向熵(补充)"
],

"model": "XGBoost / LightGBM(可解释性强)",

"cross_validation": "5-fold",

"hyperparameters": {
"max_depth": 6,
"learning_rate": 0.1,
"n_estimators": 200
},

"target_metric": "F1-Score > 0.80"
}

第三阶段:边缘部署(2周)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
DEPLOYMENT_CONFIG = {
"platform": "Qualcomm QCS8255",

"model_compression": {
"quantization": "INT8",
"pruning": "30% weights",
"target_size": "< 2MB"
},

"real_time_constraints": {
"inference_time": "< 10ms",
"fps": ">= 30",
"latency": "< 100ms(端到端)"
},

"integration": {
"input": "视线追踪模块输出",
"output": "认知分心等级 + 置信度",
"trigger": "连续3秒高熵值"
}
}

与疲劳检测融合

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
class FatigueAndCognitiveFusion:
"""
疲劳 + 认知分心融合检测

融合策略:
1. 并行检测两种状态
2. 区分疲劳和认知分心
3. 复合状态特殊处理
"""

def __init__(self):
self.fatigue_detector = PERCLOSDetector()
self.cognitive_detector = CognitiveDistractionDetector()

def detect(self,
eye_data: np.ndarray,
gaze_data: np.ndarray) -> dict:
"""
综合检测

Args:
eye_data: 眼睛数据(眼睑开度等)
gaze_data: 视线数据

Returns:
状态判断
"""
# 疲劳检测
is_fatigued, fatigue_conf = self.fatigue_detector.detect(eye_data)

# 认知分心检测
is_cognitive, cognitive_conf, metrics = self.cognitive_detector.detect(gaze_data)

# 状态判断
if is_fatigued and is_cognitive:
state = "FATIGUE_AND_COGNITIVE"
severity = "CRITICAL"
elif is_fatigued:
state = "FATIGUE"
severity = "WARNING"
elif is_cognitive:
state = "COGNITIVE_DISTRACTION"
severity = "WARNING"
else:
state = "NORMAL"
severity = "NONE"

return {
'state': state,
'severity': severity,
'fatigue_confidence': fatigue_conf,
'cognitive_confidence': cognitive_conf,
'gaze_entropy': metrics
}

关键参考文献

  1. “Discriminative Capabilities of Eye Gaze Measures for Cognitive Load Evaluation” - PMC 2024

    • SGE/GTE对比实验
    • 验证视线熵有效性
  2. “Driver Cognitive Distraction Detection based on eye movement behavior” - ScienceDirect 2025

    • 多视角特征融合
    • 实车验证
  3. “Towards recognizing cognitive distraction levels with steering entropy” - ScienceDirect 2025

    • 转向熵作为补充指标
    • 低成本实现
  4. Euro NCAP 2026-2027 Protocol Draft (待发布)


总结:视线熵(SGE+GTE)为认知分心检测提供了量化、可解释、高准确率的解决方案。IMS团队应优先完成数据采集和阈值标定,为Euro NCAP可能的认知分心评分做好准备。


视线熵指标:认知分心检测的核心突破
https://dapalm.com/2026/07/22/2026-07-23-gaze-entropy-cognitive-distraction/
作者
Mars
发布于
2026年7月22日
许可协议