认知分心检测突破:眼动熵+规律性指标实现隐性分心识别

认知分心检测突破:眼动熵+规律性指标实现隐性分心识别

来源: Euro NCAP 2026 + IEEE TITS
发布时间: 2026年4月
核心价值: 认知分心是Euro NCAP 2026新要求,传统视觉方法难以检测


核心洞察

认知分心 vs 视觉分心:

特征 视觉分心 认知分心
定义 视线偏离道路 视线在道路但心思不在
检测难度 容易(视线追踪) 困难(需行为分析)
占比 ~60% ~40%
传统DMS ✅ 可检测 难检测

Euro NCAP 2026新要求:

  • 需检测认知分心(隐性分心)
  • 眼动规律性、微扫视特征
  • 反应时间异常检测

一、认知分心定义

1.1 分心类型分类

类型 描述 示例
视觉分心 眼睛离开道路 看手机、看导航
手动分心 手离开方向盘 操作中控
认知分心 心思不在驾驶 思考问题、走神
听觉分心 注意力被声音吸引 通话、音乐

1.2 认知分心特征

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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
"""
认知分心特征分析
"""

import numpy as np
from dataclasses import dataclass
from typing import List, Tuple
from collections import deque

@dataclass
class GazeMetrics:
"""眼动指标"""
entropy: float # 眼动熵
regularity: float # 眼动规律性
micro_saccade_rate: float # 微扫视频率
fixation_duration: float # 注视持续时间
saccade_amplitude: float # 扫视幅度

class CognitiveDistractionDetector:
"""
认知分心检测器

检测指标:
1. 眼动熵(Gaze Entropy)
2. 眼动规律性(Gaze Regularity)
3. 微扫视特征
4. 注视模式变化
"""

def __init__(self,
window_size: int = 300, # 10秒 @ 30fps
entropy_threshold: float = 0.7,
regularity_threshold: float = 0.5):
"""
初始化检测器

Args:
window_size: 分析窗口大小
entropy_threshold: 熵阈值
regularity_threshold: 规律性阈值
"""
self.window_size = window_size
self.entropy_threshold = entropy_threshold
self.regularity_threshold = regularity_threshold

# 历史缓冲
self.gaze_history = deque(maxlen=window_size)
self.fixation_history = deque(maxlen=50) # 最近50次注视

def update(self,
gaze_x: float,
gaze_y: float,
timestamp: float) -> Tuple[bool, GazeMetrics]:
"""
更新检测状态

Args:
gaze_x: 视线X坐标(归一化0-1)
gaze_y: 视线Y坐标(归一化0-1)
timestamp: 时间戳

Returns:
(is_distracted, metrics)
"""
# 记录历史
self.gaze_history.append((gaze_x, gaze_y, timestamp))

# 需要足够数据
if len(self.gaze_history) < self.window_size // 2:
return False, GazeMetrics(0, 0, 0, 0, 0)

# 计算指标
metrics = self._compute_metrics()

# 判断认知分心
is_distracted = (
metrics.entropy > self.entropy_threshold or
metrics.regularity < self.regularity_threshold
)

return is_distracted, metrics

def _compute_metrics(self) -> GazeMetrics:
"""计算眼动指标"""
gaze_array = np.array(list(self.gaze_history))
x = gaze_array[:, 0]
y = gaze_array[:, 1]

# 1. 计算眼动熵
entropy = self._compute_entropy(x, y)

# 2. 计算规律性
regularity = self._compute_regularity(x, y)

# 3. 计算微扫视频率
micro_saccade_rate = self._compute_micro_saccade_rate(x, y)

# 4. 计算注视持续时间
fixation_duration = self._compute_fixation_duration(x, y)

# 5. 计算扫视幅度
saccade_amplitude = self._compute_saccade_amplitude(x, y)

return GazeMetrics(
entropy=entropy,
regularity=regularity,
micro_saccade_rate=micro_saccade_rate,
fixation_duration=fixation_duration,
saccade_amplitude=saccade_amplitude
)

def _compute_entropy(self, x: np.ndarray, y: np.ndarray) -> float:
"""
计算眼动熵

高熵表示视线分散(认知分心)
低熵表示视线集中(正常驾驶)
"""
# 离散化到网格
grid_size = 10
x_bins = np.digitize(x, np.linspace(0, 1, grid_size))
y_bins = np.digitize(y, np.linspace(0, 1, grid_size))

# 计算联合概率
hist, _, _ = np.histogram2d(x_bins, y_bins, bins=grid_size)
prob = hist / hist.sum()

# 计算熵
prob_flat = prob.flatten()
prob_flat = prob_flat[prob_flat > 0]
entropy = -np.sum(prob_flat * np.log2(prob_flat))

# 归一化到0-1
max_entropy = np.log2(grid_size * grid_size)
normalized_entropy = entropy / max_entropy

return normalized_entropy

def _compute_regularity(self, x: np.ndarray, y: np.ndarray) -> float:
"""
计算眼动规律性

使用自相关分析
高规律性 = 正常驾驶(扫视模式规律)
低规律性 = 认知分心(扫视模式混乱)
"""
# 计算视线位置序列的自相关
x_centered = x - np.mean(x)
y_centered = y - np.mean(y)

# 自相关(滞后10帧)
lag = 10
if len(x) < lag * 2:
return 0.5

x_autocorr = np.corrcoef(x_centered[:-lag], x_centered[lag:])[0, 1]
y_autocorr = np.corrcoef(y_centered[:-lag], y_centered[lag:])[0, 1]

# 综合规律性
regularity = (abs(x_autocorr) + abs(y_autocorr)) / 2

# 归一化
regularity = max(0, min(1, regularity))

return regularity

def _compute_micro_saccade_rate(self, x: np.ndarray, y: np.ndarray) -> float:
"""计算微扫视频率"""
# 计算视线速度
dx = np.diff(x)
dy = np.diff(y)
velocity = np.sqrt(dx**2 + dy**2)

# 微扫视阈值(<1°)
micro_saccade_threshold = 0.01 # 归一化坐标
micro_saccades = np.sum(velocity > micro_saccade_threshold)

# 频率(次/秒)
duration = len(x) / 30 # 假设30fps
rate = micro_saccades / duration

return rate

def _compute_fixation_duration(self, x: np.ndarray, y: np.ndarray) -> float:
"""计算平均注视持续时间"""
# 检测注视点(速度<阈值的连续帧)
velocity = np.sqrt(np.diff(x)**2 + np.diff(y)**2)
fixation_threshold = 0.005

fixation_durations = []
current_duration = 1

for v in velocity:
if v < fixation_threshold:
current_duration += 1
else:
if current_duration > 3: # 至少3帧
fixation_durations.append(current_duration / 30) # 秒
current_duration = 1

if len(fixation_durations) == 0:
return 0.0

return np.mean(fixation_durations)

def _compute_saccade_amplitude(self, x: np.ndarray, y: np.ndarray) -> float:
"""计算平均扫视幅度"""
velocity = np.sqrt(np.diff(x)**2 + np.diff(y)**2)
saccade_threshold = 0.01

saccade_amplitudes = velocity[velocity > saccade_threshold]

if len(saccade_amplitudes) == 0:
return 0.0

return np.mean(saccade_amplitudes)


# 实际测试
if __name__ == "__main__":
detector = CognitiveDistractionDetector()

print("=== 认知分心检测测试 ===")

# 场景1:正常驾驶
print("\n[场景1:正常驾驶]")
np.random.seed(42)
for i in range(300):
# 模拟规律扫视(前方+后视镜)
t = i / 30
x = 0.5 + 0.1 * np.sin(2 * np.pi * 0.3 * t) + np.random.randn() * 0.02
y = 0.5 + 0.05 * np.sin(2 * np.pi * 0.2 * t) + np.random.randn() * 0.02
x = np.clip(x, 0, 1)
y = np.clip(y, 0, 1)

is_distracted, metrics = detector.update(x, y, t)

if i == 299:
print(f" 眼动熵: {metrics.entropy:.3f}")
print(f" 规律性: {metrics.regularity:.3f}")
print(f" 认知分心: {is_distracted}")

# 场景2:认知分心
print("\n[场景2:认知分心]")
detector = CognitiveDistractionDetector()
for i in range(300):
# 模拟随机扫视(走神)
t = i / 30
x = np.random.rand() # 随机位置
y = np.random.rand()

is_distracted, metrics = detector.update(x, y, t)

if i == 299:
print(f" 眼动熵: {metrics.entropy:.3f}")
print(f" 规律性: {metrics.regularity:.3f}")
print(f" 认知分心: {is_distracted}")

二、眼动熵分析

2.1 熵计算原理

信息熵定义:

1
2
3
4
5
6
H(X) = -Σ p(x) log2 p(x)

其中:
- p(x) 是视线落在区域x的概率
- 高熵 = 视线分散 = 认知分心
- 低熵 = 视线集中 = 正常驾驶

2.2 熵阈值确定

状态 熵值范围 说明
高度集中 0.0-0.3 注视单一区域
正常驾驶 0.3-0.6 规律扫视模式
轻度分心 0.6-0.8 扫视模式混乱
严重分心 0.8-1.0 视线高度分散

三、眼动规律性

3.1 规律性指标

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
"""
眼动规律性深度分析
"""

import numpy as np
from scipy import signal
from typing import Tuple, List

class GazeRegularityAnalyzer:
"""
眼动规律性分析器

分析方法:
1. 自相关分析
2. 频谱分析
3. 模式识别
"""

def __init__(self, sample_rate: int = 30):
self.sample_rate = sample_rate

def analyze_regularity(self,
x: np.ndarray,
y: np.ndarray) -> Tuple[float, dict]:
"""
分析眼动规律性

Args:
x: X坐标序列
y: Y坐标序列

Returns:
(regularity_score, details)
"""
# 1. 自相关分析
x_autocorr = self._autocorrelation(x)
y_autocorr = self._autocorrelation(y)

# 2. 频谱分析
x_freq = self._frequency_analysis(x)
y_freq = self._frequency_analysis(y)

# 3. 扫视模式识别
pattern_score = self._pattern_recognition(x, y)

# 综合规律性评分
regularity = (
x_autocorr * 0.25 +
y_autocorr * 0.25 +
x_freq['dominance'] * 0.15 +
y_freq['dominance'] * 0.15 +
pattern_score * 0.2
)

details = {
'x_autocorr': x_autocorr,
'y_autocorr': y_autocorr,
'x_dominant_freq': x_freq['dominant_freq'],
'y_dominant_freq': y_freq['dominant_freq'],
'pattern_score': pattern_score
}

return regularity, details

def _autocorrelation(self, signal: np.ndarray) -> float:
"""计算自相关系数"""
signal_centered = signal - np.mean(signal)

if np.std(signal_centered) < 1e-8:
return 0.0

# 计算滞后10帧的自相关
lag = 10
if len(signal) < lag * 2:
return 0.0

corr = np.corrcoef(signal_centered[:-lag], signal_centered[lag:])[0, 1]

return abs(corr) if not np.isnan(corr) else 0.0

def _frequency_analysis(self, signal: np.ndarray) -> dict:
"""频谱分析"""
# FFT
fft_result = np.fft.fft(signal)
freqs = np.fft.fftfreq(len(signal), 1/self.sample_rate)

# 功率谱
power = np.abs(fft_result) ** 2

# 只取正频率
positive_mask = freqs > 0
freqs = freqs[positive_mask]
power = power[positive_mask]

# 主频率
dominant_idx = np.argmax(power)
dominant_freq = freqs[dominant_idx]

# 频谱集中度(主频率能量占比)
total_power = np.sum(power)
dominant_power = power[dominant_idx]
dominance = dominant_power / total_power if total_power > 0 else 0

return {
'dominant_freq': dominant_freq,
'dominance': dominance
}

def _pattern_recognition(self, x: np.ndarray, y: np.ndarray) -> float:
"""扫视模式识别"""
# 计算扫视序列
dx = np.diff(x)
dy = np.diff(y)

# 检测扫视事件
velocity = np.sqrt(dx**2 + dy**2)
saccade_threshold = 0.01

saccade_mask = velocity > saccade_threshold

# 计算扫视间隔
saccade_indices = np.where(saccade_mask)[0]

if len(saccade_indices) < 3:
return 0.0

intervals = np.diff(saccade_indices)

# 间隔的变异系数(越小越规律)
if len(intervals) < 2:
return 0.0

cv = np.std(intervals) / (np.mean(intervals) + 1e-8)

# 变异系数转换为规律性评分
pattern_score = 1 / (1 + cv)

return pattern_score


# 实际测试
if __name__ == "__main__":
analyzer = GazeRegularityAnalyzer()

# 模拟正常驾驶数据
t = np.linspace(0, 10, 300)
x_normal = 0.5 + 0.1 * np.sin(2 * np.pi * 0.3 * t) + np.random.randn(300) * 0.02
y_normal = 0.5 + 0.05 * np.sin(2 * np.pi * 0.2 * t) + np.random.randn(300) * 0.02

regularity, details = analyzer.analyze_regularity(x_normal, y_normal)

print("=== 正常驾驶眼动规律性 ===")
print(f"规律性评分: {regularity:.3f}")
print(f"X自相关: {details['x_autocorr']:.3f}")
print(f"Y自相关: {details['y_autocorr']:.3f}")
print(f"主频率: X={details['x_dominant_freq']:.2f}Hz, Y={details['y_dominant_freq']:.2f}Hz")

# 模拟认知分心数据
x_distracted = np.random.rand(300)
y_distracted = np.random.rand(300)

regularity, details = analyzer.analyze_regularity(x_distracted, y_distracted)

print("\n=== 认知分心眼动规律性 ===")
print(f"规律性评分: {regularity:.3f}")
print(f"X自相关: {details['x_autocorr']:.3f}")
print(f"Y自相关: {details['y_autocorr']:.3f}")

四、Euro NCAP合规

4.1 认知分心测试场景

场景 描述 检测方法
CD-01 驾驶员听复杂对话 眼动熵+反应时间
CD-02 驾驶员思考问题 眼动规律性
CD-03 驾驶员情绪波动 多指标融合
CD-04 驾驶员疲劳初期 PERCLOS+认知指标

4.2 检测时限要求

指标 检测时间 警告延迟
眼动熵异常 持续10秒 ≤3秒
规律性下降 持续15秒 ≤5秒
综合判断 持续8秒 ≤3秒

五、IMS开发建议

5.1 实现优先级

功能 优先级 难度
眼动熵计算 P0
规律性分析 P0
微扫视检测 P1
模式识别 P2

5.2 性能要求

指标 要求 说明
检测延迟 ≤100ms 实时计算
准确率 ≥85% 认知分心检测
误报率 ≤5% 正常驾驶

六、总结

6.1 核心要点

  1. 认知分心是隐性分心,传统方法难检测
  2. 眼动熵是最有效指标
  3. 规律性分析提供互补信息
  4. 多指标融合提升精度

6.2 未来方向

  • EEG辅助认知分心检测
  • 多模态行为分析
  • 个性化阈值学习

参考链接:

  • Euro NCAP 2026 Cognitive Distraction Protocol
  • IEEE TITS: Gaze Entropy for Distraction Detection
  • Springer: Driver Cognitive Distraction Detection

认知分心检测突破:眼动熵+规律性指标实现隐性分心识别
https://dapalm.com/2026/04/24/2026-04-24-cognitive-distraction-gaze-entropy-regularity/
作者
Mars
发布于
2026年4月24日
许可协议