瞳孔直径检测:疲劳与认知负荷的生理指标

瞳孔直径检测:疲劳与认知负荷的生理指标

引言

瞳孔直径变化是反映人体认知状态的重要生理指标。近年研究表明,瞳孔直径与认知疲劳、心理负荷呈显著相关性。在驾驶员监控系统中,瞳孔测量(Pupillometry)正成为继眨眼、PERCLOS之后的又一关键监测维度。本文将深入探讨瞳孔直径检测的原理、影响因素及在DMS中的实现方案。

检测原理

1. 瞳孔调控机制

瞳孔直径受自主神经系统调控:

神经系统 作用 触发条件
交感神经 扩瞳(瞳孔放大) 应激、兴奋、高认知负荷
副交感神经 缩瞳(瞳孔缩小) 放松、疲劳、休息

2. 认知负荷与瞳孔的关系

研究表明:

  • 高认知负荷 → 瞳孔扩张(任务诱发瞳孔反应,TEPR)
  • 认知疲劳 → 基线瞳孔直径下降
  • 任务难度增加 → 瞳孔直径变化增大

LC-NE系统关联:瞳孔直径与蓝斑核-去甲肾上腺素(LC-NE)系统活动密切相关,该系统负责调控注意力与认知控制。

3. 疲劳检测机制

1
2
3
4
5
6
7
正常状态 ─→ 瞳孔直径稳定,波动正常


轻度疲劳 ─→ 基线直径下降10-15%,波动减小


重度疲劳 ─→ 基线直径下降20%+,反应迟钝

影响因素

1. 光照条件

因素 影响 补偿方法
环境亮度 最主要因素 相对变化率而非绝对值
光源闪烁 测量噪声 高帧率采样+滤波
红外照明 瞳孔扩张 标定IR强度

2. 个体差异

  • 年龄:老年人瞳孔较小,反应速度下降
  • 药物影响:某些药物会导致瞳孔变化
  • 生理状态:疲劳、疾病影响基线

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
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
import cv2
import numpy as np
from scipy import signal
from collections import deque

class PupilDiameterMonitor:
"""瞳孔直径监测器"""

def __init__(self,
history_length=300, # 10秒@30fps
fatigue_threshold=0.15):
"""初始化

Args:
history_length: 历史数据长度
fatigue_threshold: 疲劳阈值(相对下降比例)
"""
self.history = deque(maxlen=history_length)
self.baseline = None
self.fatigue_threshold = fatigue_threshold

# 眼部检测器
self.eye_cascade = cv2.CascadeClassifier(
cv2.data.haarcascades + 'haarcascade_eye.xml'
)

def detect_pupil(self, eye_roi):
"""检测瞳孔

Args:
eye_roi: 眼部区域图像

Returns:
pupil_diameter: 瞳孔直径(像素)
confidence: 检测置信度
"""
gray = cv2.cvtColor(eye_roi, cv2.COLOR_BGR2GRAY) if len(eye_roi.shape) == 3 else eye_roi

# 高斯模糊减少噪声
blurred = cv2.GaussianBlur(gray, (5, 5), 0)

# 反向阈值(瞳孔是暗区域)
_, thresh = cv2.threshold(blurred, 50, 255, cv2.THRESH_BINARY_INV)

# 形态学操作
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

# 查找轮廓
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

if not contours:
return None, 0

# 选择最大的圆形轮廓(瞳孔)
best_contour = max(contours, key=lambda c: cv2.contourArea(c))
area = cv2.contourArea(best_contour)

if area < 10: # 过小的区域
return None, 0

# 计算等效直径
diameter = 2 * np.sqrt(area / np.pi)

# 计算圆度作为置信度
perimeter = cv2.arcLength(best_contour, True)
if perimeter == 0:
return None, 0
circularity = 4 * np.pi * area / (perimeter ** 2)

return diameter, circularity

def update_baseline(self, diameter):
"""更新基线

Args:
diameter: 当前瞳孔直径
"""
self.history.append(diameter)

if len(self.history) >= 100: # 至少3秒数据
self.baseline = np.mean(list(self.history)[-100:])

def assess_fatigue(self, current_diameter):
"""评估疲劳程度

Args:
current_diameter: 当前瞳孔直径

Returns:
fatigue_level: 疲劳等级 (0-3)
ratio: 相对基线变化比例
"""
if self.baseline is None:
return 0, 0

ratio = (self.baseline - current_diameter) / self.baseline

if ratio > 0.25:
return 3, ratio # 重度疲劳
elif ratio > 0.15:
return 2, ratio # 中度疲劳
elif ratio > 0.08:
return 1, ratio # 轻度疲劳
else:
return 0, ratio # 正常

def calculate_cognitive_load(self, time_window=30):
"""计算认知负荷指标

基于瞳孔直径波动分析

Args:
time_window: 时间窗口(帧数)

Returns:
load_index: 认知负荷指数
"""
if len(self.history) < time_window:
return 0

recent = np.array(list(self.history)[-time_window:])

# 使用Savitzky-Golay滤波器平滑
if len(recent) >= 11:
smoothed = signal.savgol_filter(recent, 11, 3)

# 计算变化幅度
variation = np.std(smoothed) / np.mean(smoothed)

# 归一化为负荷指数
load_index = min(variation * 10, 1.0)

return load_index

return 0

class PupilBasedFatigueDetector:
"""基于瞳孔的疲劳检测系统"""

def __init__(self):
self.pupil_monitor = PupilDiameterMonitor()
self.warning_count = 0

def process_frame(self, frame):
"""处理单帧图像

Args:
frame: BGR图像

Returns:
result: 检测结果字典
"""
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# 检测面部
face_cascade = cv2.CascadeClassifier(
cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)

results = {
'pupil_detected': False,
'diameter': None,
'fatigue_level': 0,
'cognitive_load': 0,
'warning': None
}

for (x, y, w, h) in faces:
roi_gray = gray[y:y+h, x:x+w]
eyes = self.pupil_monitor.eye_cascade.detectMultiScale(roi_gray)

for (ex, ey, ew, eh) in eyes:
eye_roi = roi_gray[ey:ey+eh, ex:ex+ew]
diameter, confidence = self.pupil_monitor.detect_pupil(
cv2.cvtColor(frame[y+ey:y+ey+eh, x+ex:x+ex+ew], cv2.COLOR_BGR2GRAY)
)

if diameter and confidence > 0.5:
results['pupil_detected'] = True
results['diameter'] = diameter

# 更新基线
self.pupil_monitor.update_baseline(diameter)

# 评估疲劳
fatigue, ratio = self.pupil_monitor.assess_fatigue(diameter)
results['fatigue_level'] = fatigue

# 计算认知负荷
results['cognitive_load'] = self.pupil_monitor.calculate_cognitive_load()

# 生成警告
if fatigue >= 2:
results['warning'] = f"疲劳警告:瞳孔直径下降{ratio*100:.1f}%"
self.warning_count += 1
elif fatigue == 1:
results['warning'] = "轻度疲劳,请保持警觉"

return results

# 使用示例
if __name__ == "__main__":
detector = PupilBasedFatigueDetector()

# 模拟视频处理
for i in range(100):
frame = np.random.randint(0, 255, (480, 640, 3), dtype=np.uint8)
result = detector.process_frame(frame)

if result['pupil_detected']:
print(f"帧{i}: 直径={result['diameter']:.1f}, "
f"疲劳={result['fatigue_level']}, "
f"负荷={result['cognitive_load']:.2f}")

方法对比

方法 检测原理 优点 缺点 适用场景
基线比较法 相对基线变化 简单、个体化 需校准期 长时驾驶
TEPR分析 任务诱发反应 评估实时负荷 干扰因素多 复杂路况
波动分析 变异系数 抗光照干扰 需要足够数据 实时监测
多指标融合 瞳孔+眨眼+PERCLOS 高可靠性 实现复杂 生产级方案

IMS开发建议

1. 传感器选型

传感器类型 瞳孔检测精度 成本 推荐场景
IR摄像头(940nm) 量产首选
RGB-IR融合 很高 高端车型
ToF深度相机 多功能融合

2. 算法优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 光照归一化处理
def normalize_pupil_diameter(diameter, ambient_light):
"""光照归一化

Args:
diameter: 原始直径
ambient_light: 环境光照度

Returns:
normalized: 归一化后的直径变化
"""
# 基于光照-瞳孔关系的经验公式
# 瞳孔直径 ≈ k / log(lux + 1)
expected = 5.0 / np.log(ambient_light + 1)
normalized = (diameter - expected) / expected
return normalized

3. 融合策略

1
2
3
4
5
瞳孔指标 ─┬─ 疲劳评估 ─┐
│ │
眨眼指标 ─┼─ 疲劳评估 ─┼─→ 综合疲劳指数
│ │
PERCLOS ──┴─ 疲劳评估 ─┘

4. Euro NCAP合规

当前Euro NCAP未强制瞳孔检测,但建议:

  • 将瞳孔指标作为疲劳评估的辅助特征
  • 建立瞳孔-疲劳的个体化模型
  • 与眨眼、PERCLOS形成多维度验证

总结

瞳孔直径检测为DMS系统提供了认知层面的监测能力,是对传统视觉行为监测的重要补充。虽然存在光照干扰等挑战,但通过合理的算法设计和多指标融合,瞳孔测量可有效提升疲劳检测的准确性和鲁棒性。


参考文献:

  1. PLOS One - Eye tracking cognitive load using pupil diameter
  2. MDPI - Measuring Mental Effort in Real Time Using Pupillometry
  3. PsyPost - Pupil size revealed to be a key indicator of cognitive fatigue
  4. Wikipedia - Task-invoked pupillary response

瞳孔直径检测:疲劳与认知负荷的生理指标
https://dapalm.com/2026/06/01/2026-06-01-瞳孔直径检测疲劳与认知负荷的生理指标/
作者
Mars
发布于
2026年6月1日
许可协议