WACV 2024 论文解读:通过面部特征估计血液酒精浓度——酒驾损伤检测的视觉AI突破

WACV 2024 论文解读:通过面部特征估计血液酒精浓度——酒驾损伤检测的视觉AI突破

论文信息

项目 内容
标题 Estimating Blood Alcohol Level Through Facial Features for Driver Impairment Assessment
作者 Ensiyeh Keshtkaran, Brodie von Berg, Grant Regan, David Suter, Syed Zulqarnain Gilani
会议 IEEE/CVF Winter Conference on Applications of Computer Vision (WACV 2024)
年份 2024
链接 https://openaccess.thecvf.com/content/WACV2024/papers/Keshtkaran_Estimating_Blood_Alcohol_Level_Through_Facial_Features_for_Driver_Impairment_WACV_2024_paper.pdf
机构 Edith Cowan University, Australia

核心创新

首次使用标准RGB摄像头预测临界BAC水平(0.05 g/dL),准确率75%。通过面部特征(眼睛、嘴巴、头部运动)的非侵入式检测,无需呼吸测试或血液采样。

关键突破点

突破 描述
非侵入式 仅使用车内摄像头,无需额外传感器
临界精度 0.05 g/dL(WHO推荐驾驶上限)检测准确率75%
实时性 视频流处理,帧率30fps
低成本 利用现有DMS摄像头,无需新增硬件

1. 问题背景与动机

1.1 酒驾事故统计

地区 数据
全球 酒驾相关事故占道路死亡的20-30%
澳大利亚 每年约400人死亡,30%涉酒精
美国 每年约10,000人死亡,28%涉酒精
WHO标准 BAC ≥ 0.05 g/dL 禁止驾驶

1.2 传统检测局限

方法 局限 成本
呼吸测试 需要主动配合,单次测量 $50-100/设备
血液采样 医疗介入,无法实时 $100-200/次
驾驶行为 间接推断,延迟高 已集成ADAS
车内传感器 需接触方向盘/座椅 $200-500

1.3 视觉AI优势

优势 描述
非侵入式 驾驶员无需额外操作
实时监测 持续视频分析
利用现有硬件 DMS摄像头复用
隐私可控 本地处理,不上传云端

2. 方法详解

2.1 数据集构建

首个真实饮酒场景数据集:

数据集参数
被试人数 28人(18男,10女)
年龄段 21-55岁
种族多样性 多种族(欧洲、亚洲、中东)
饮酒场景 真实饮酒(酒吧/车辆)
BAC范围 0.00 - 0.15 g/dL
视频长度 每人约10分钟
标注方式 呼气测试仪(每分钟)
总帧数 ~50,000帧

2.2 面部特征提取

三类特征通道:

graph LR
    A[RGB视频帧] --> B[眼睛特征]
    A --> C[嘴巴特征]
    A --> D[头部运动]
    
    B --> E[眼睑开度]
    B --> F[眨眼频率]
    B --> G[瞳孔直径]
    B --> H[虹膜纹理]
    
    C --> I[嘴唇张开度]
    C --> J[嘴角位置]
    C --> K[面部松弛度]
    
    D --> L[头部倾斜]
    D --> M[点头频率]
    D --> N[摇晃频率]
    
    E --> O[特征融合]
    F --> O
    G --> O
    H --> O
    I --> O
    J --> O
    K --> O
    L --> O
    M --> O
    N --> O
    
    O --> P[BAC估计模型]

眼睛特征详解

特征 物理意义 酒精影响
眼睑开度(EAR) 上下眼睑距离 酒精→肌肉松弛→眼睑下垂
眨眼频率 单位时间眨眼次数 酒精→频率增加/减少
瞳孔直径 虹膜孔径 酒精→瞳孔扩大
虹膜纹理 高频纹理特征 酜精→纹理模糊
注视稳定性 视线抖动 酒精→抖动增加

嘴巴特征详解

特征 物理意义 酒精影响
嘴唇张开度 上下嘴唇距离 酒精→面部松弛→张嘴
嘴角位置 左右嘴角Y坐标 酒精→嘴角下垂
面部松弛度 关键点抖动 酒精→抖动增加

头部运动特征详解

特征 物理意义 酒精影响
头部倾斜角 头部Pitch/Roll/Yaw 酜精→稳定性下降
点头频率 头部上下运动次数 酒精→频率增加
摇晃频率 头部左右摆动次数 酜精→频率增加

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
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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
"""
WACV 2024 论文复现:通过面部特征估计BAC
参考:Keshtkaran et al., WACV 2024

核心方法:
1. MediaPipe提取68个面部关键点
2. 计算EAR/MAR/头部姿态特征
3. 特征序列标准化
4. LSTM时序建模
5. BAC回归预测
"""

import numpy as np
import cv2
from typing import Dict, List, Tuple
from dataclasses import dataclass

@dataclass
class FacialFeatures:
"""面部特征数据结构"""
ear_left: float # 左眼开度
ear_right: float # 右眼开度
mar: float # 嘴巴开度
pupil_diameter: float # 瞳孔直径
head_pitch: float # 头部俯仰角
head_roll: float # 头部侧倾角
head_yaw: float # 头部偏航角
timestamp: float # 时间戳

class AlcoholImpairmentDetector:
"""
酒驾损伤检测器

流程:
1. 面部关键点检测
2. 特征计算(EAR/MAR/Head Pose)
3. 时序特征聚合
4. BAC估计
"""

def __init__(self):
# 面部关键点索引(MediaPipe格式)
# 左眼:[33, 133, 159, 145, 158, 144, 153, 154]
# 右眼:[362, 263, 387, 373, 386, 372, 380, 381]
# 嘴巴:[61, 291, 0, 17, 78, 308]

self.left_eye_indices = [33, 133, 159, 145]
self.right_eye_indices = [362, 263, 387, 373]
self.mouth_indices = [61, 291, 0, 17]

def calculate_ear(
self,
landmarks: np.ndarray,
eye_indices: List[int]
) -> float:
"""
计算Eye Aspect Ratio (EAR)

EAR = |p2-p6| + |p3-p5| / 2|p1-p4|

Args:
landmarks: 面部关键点, shape=(468, 3)
eye_indices: 眼睛关键点索引

Returns:
ear: 眼睛开度比值

EAR < 0.2 表示闭眼
EAR > 0.3 表示睁眼
酒精影响:EAR平均值下降(眼睑下垂)
"""
p1 = landmarks[eye_indices[0]] # 外眼角
p4 = landmarks[eye_indices[1]] # 内眼角

p2 = landmarks[eye_indices[2]] # 上眼睑中点
p3 = landmarks[eye_indices[2] + 1] # 上眼睑另一点
p5 = landmarks[eye_indices[3]] # 下眼睑中点
p6 = landmarks[eye_indices[3] + 1] # 下眼睑另一点

# 垂直距离
vertical_1 = np.linalg.norm(p2 - p6)
vertical_2 = np.linalg.norm(p3 - p5)

# 水平距离
horizontal = np.linalg.norm(p1 - p4)

# EAR
ear = (vertical_1 + vertical_2) / (2.0 * horizontal + 1e-6)

return ear

def calculate_mar(
self,
landmarks: np.ndarray
) -> float:
"""
计算Mouth Aspect Ratio (MAR)

MAR = |p8-p10| / |p7-p9|

Args:
landmarks: 面部关键点

Returns:
mar: 嘴巴开度比值

酒精影响:MAR平均值增加(面部松弛张嘴)
"""
# 嘴巴关键点
left_corner = landmarks[61] # 左嘴角
right_corner = landmarks[291] # 右嘴角
upper_lip = landmarks[0] # 上嘴唇中点
lower_lip = landmarks[17] # 下嘴唇中点

# 垂直距离
vertical = np.linalg.norm(upper_lip - lower_lip)

# 水平距离
horizontal = np.linalg.norm(left_corner - right_corner)

# MAR
mar = vertical / (horizontal + 1e-6)

return mar

def estimate_head_pose(
self,
landmarks: np.ndarray,
image_size: Tuple[int, int]
) -> Tuple[float, float, float]:
"""
估计头部姿态(Pitch/Roll/Yaw)

Args:
landmarks: 面部关键点
image_size: 图像尺寸 (H, W)

Returns:
pitch: 俯仰角(度)
roll: 侧倾角(度)
yaw: 偏航角(度)

方法:solvePnP求解3D-2D对应

酒精影响:头部稳定性下降,角度抖动增加
"""
# 3D模型点(标准人脸模型)
model_points = np.array([
(0.0, 0.0, 0.0), # 鼻尖
(0.0, -330.0, -65.0), # 下巴
(-225.0, 170.0, -135.0), # 左眼外角
(225.0, 170.0, -135.0), # 右眼外角
(-150.0, -150.0, -125.0), # 左嘴角
(150.0, -150.0, -125.0) # 右嘴角
])

# 2D图像点
image_points = np.array([
landmarks[1], # 鼻尖
landmarks[152], # 下巴
landmarks[33], # 左眼外角
landmarks[263], # 右眼外角
landmarks[61], # 左嘴角
landmarks[291] # 右嘴角
], dtype=np.float64)

# 相机内参(假设)
focal_length = image_size[1]
camera_matrix = np.array([
[focal_length, 0, image_size[1] / 2],
[0, focal_length, image_size[0] / 2],
[0, 0, 1]
], dtype=np.float64)

dist_coeffs = np.zeros((4, 1))

# solvePnP
success, rotation_vector, translation_vector = cv2.solvePnP(
model_points, image_points, camera_matrix, dist_coeffs,
flags=cv2.SOLVEPNP_ITERATIVE
)

if not success:
return 0.0, 0.0, 0.0

# 转换为角度
rotation_matrix = cv2.Rodrigues(rotation_vector)[0]
pitch = np.degrees(np.arcsin(-rotation_matrix[2, 1]))
roll = np.degrees(np.arctan2(rotation_matrix[2, 0], rotation_matrix[2, 2]))
yaw = np.degrees(np.arctan2(rotation_matrix[0, 1], rotation_matrix[1, 1]))

return pitch, roll, yaw

def extract_features(
self,
frame: np.ndarray,
landmarks: np.ndarray
) -> FacialFeatures:
"""
提取完整面部特征

Args:
frame: RGB图像帧
landmarks: MediaPipe关键点

Returns:
features: 面部特征数据
"""
# 计算EAR
ear_left = self.calculate_ear(landmarks, self.left_eye_indices)
ear_right = self.calculate_ear(landmarks, self.right_eye_indices)

# 计算MAR
mar = self.calculate_mar(landmarks)

# 估计头部姿态
pitch, roll, yaw = self.estimate_head_pose(
landmarks, frame.shape[:2]
)

# 瞳孔直径估计(简化)
# 实际需要虹膜检测
pupil_diameter = 0.0

return FacialFeatures(
ear_left=ear_left,
ear_right=ear_right,
mar=mar,
pupil_diameter=pupil_diameter,
head_pitch=pitch,
head_roll=roll,
head_yaw=yaw,
timestamp=0.0
)

def estimate_bac(
self,
feature_sequence: List[FacialFeatures],
window_seconds: int = 60
) -> float:
"""
从特征序列估计BAC

Args:
feature_sequence: 特征序列(多帧)
window_seconds: 时间窗口

Returns:
estimated_bac: 估计BAC值 (g/dL)

方法:特征统计 + 线性回归
论文实际使用Random Forest回归器
"""
if len(feature_sequence) < 10:
return 0.0

# 统计特征
ear_values = [f.ear_left + f.ear_right for f in feature_sequence]
mar_values = [f.mar for f in feature_sequence]
pitch_values = [f.head_pitch for f in feature_sequence]

# 时序统计
ear_mean = np.mean(ear_values)
ear_std = np.std(ear_values)
mar_mean = np.mean(mar_values)
mar_std = np.std(mar_values)
pitch_std = np.std(pitch_values)

# 简化回归模型(论文使用训练好的RF)
# 眼睑下垂 → BAC增加
# 嘴巴松弛 → BAC增加
# 头部不稳定 → BAC增加

bac_estimate = 0.0

# 眼睑开度阈值
if ear_mean < 0.25:
bac_estimate += 0.02
if ear_std > 0.05:
bac_estimate += 0.01

# 嘴巴开度阈值
if mar_mean > 0.3:
bac_estimate += 0.02

# 头部稳定性
if pitch_std > 5.0:
bac_estimate += 0.02

return min(bac_estimate, 0.15) # 上限0.15 g/dL


# 测试代码
if __name__ == "__main__":
detector = AlcoholImpairmentDetector()

# 模拟面部关键点
np.random.seed(42)
landmarks = np.random.randn(468, 3) * 100 + np.array([320, 240, 0])

# 模拟图像
frame = np.random.randint(0, 255, (480, 640, 3), dtype=np.uint8)

# 提取特征
features = detector.extract_features(frame, landmarks)

print(f"左眼EAR: {features.ear_left:.3f}")
print(f"右眼EAR: {features.ear_right:.3f}")
print(f"嘴巴MAR: {features.mar:.3f}")
print(f"头部Pitch: {features.head_pitch:.1f}°")
print(f"头部Roll: {features.head_roll:.1f}°")
print(f"头部Yaw: {features.head_yaw:.1f}°")

# 模拟特征序列(酒精影响)
feature_sequence = []
for i in range(120): # 120帧,约4秒
# 模拟酒精影响:EAR下降、MAR增加
alcohol_effect = i / 120 * 0.1 # 逐渐增加
f = FacialFeatures(
ear_left=0.3 - alcohol_effect * 0.1,
ear_right=0.3 - alcohol_effect * 0.1,
mar=0.2 + alcohol_effect * 0.2,
pupil_diameter=0.0,
head_pitch=np.random.randn() * (5 + alcohol_effect * 10),
head_roll=np.random.randn() * 2,
head_yaw=np.random.randn() * 2,
timestamp=i / 30
)
feature_sequence.append(f)

# 估计BAC
bac = detector.estimate_bac(feature_sequence)
print(f"\n估计BAC: {bac:.3f} g/dL")
print(f"判定: {'酒驾风险' if bac >= 0.05 else '正常'}")

2.4 BAC回归模型

论文使用 Random Forest Regressor

参数
特征数 18个(EAR/MAR/Head Pose + 统计值)
树数量 100
最大深度 10
训练集 20人
测试集 8人
交叉验证 5-fold

3. 实验结果

3.1 BAC估计精度

BAC阈值 准确率 应用场景
≥ 0.05 g/dL 75% WHO驾驶上限
≥ 0.08 g/dL 85% 美国驾驶上限
≥ 0.10 g/dL 92% 高度醉酒

3.2 特征重要性分析

特征 重要性排名 物理意义
EAR标准差 1 眼睑稳定性下降
EAR平均值 2 眼睑下垂
MAR平均值 3 面部松弛张嘴
Pitch标准差 4 头部稳定性下降
Yaw标准差 5 头部摇晃

3.3 与现有方法对比

方法 BAC估计准确率 成本 实时性
呼吸测试 95% $50-100 单次
血液采样 99% $100-200 医疗介入
行为分析 60% 已集成ADAS 实时
本论文视觉 75% $0(复用DMS) 实时

4. Euro NCAP 2026关联

4.1 酒驾检测要求

Euro NCAP 2026/2030路线图提及:

项目 2026 2030愿景
酒驾检测 未强制要求 纳入DSM评估
损伤检测 未强制 多模态融合
干预措施 未强制 MRM触发

4.2 IMS开发启示

开发项 优先级 技术路线
EAR特征提取 🔴 P0 MediaPipe + EAR计算
MAR特征提取 🔴 P0 同上
Head Pose估计 🔴 P0 solvePnP
时序特征聚合 🟡 P1 滑动窗口统计
BAC回归训练 🟡 P1 Random Forest
阈值判定 🟡 P1 ≥0.05触发警告
多模态融合 🟢 P2 视觉+驾驶行为

4.3 系统集成架构

graph TD
    A[DMS摄像头] --> B[面部关键点检测]
    B --> C[EAR/MAR/HeadPose特征]
    C --> D[时序窗口聚合]
    D --> E[BAC估计模型]
    
    E --> F{BAC ≥ 0.05?}
    F --> G[正常状态]
    F --> H[酒驾风险警告]
    
    H --> I[一级警告:声音+视觉]
    H --> J[二级警告:ADAS联动]
    H --> K[三级干预:MRM触发]
    
    E --> L[与疲劳检测融合]
    L --> M[综合损伤评估]

4.4 性能指标对比

指标 论文结果 IMS目标 Euro NCAP要求
BAC检测准确率 75% 80% 未规定(2030可能规定)
检测延迟 ~60秒 <30秒 未规定
误报率 ~15% <10% 未规定
漏报率 ~25% <15% 未规定
硬件成本 $0 $0 复用DMS

5. 局限性与未来方向

5.1 当前局限

局限 描述 解决方向
准确率不足 75%低于呼吸测试 多模态融合
光照敏感 暗光环境性能下降 红外摄像头
个体差异 不同人反应不同 个人化模型
遮挡问题 眼镜/帽子遮挡 多角度摄像头
数据集规模 28人偏小 扩大规模

5.2 未来研究方向

方向 描述 预期提升
多模态融合 视觉+驾驶行为+语音 准确率+10%
虹膜检测 瞲孔直径+纹理分析 准确率+5%
个人化建模 针对个体的阈值调整 准确率+10%
深度学习 CNN+LSTM端到端 准确率+5%
3D人脸建模 深度摄像头辅助 遮挡鲁棒性+20%

6. 总结

WACV 2024这篇论文是酒驾视觉检测的里程碑

  1. 首次证明标准RGB摄像头可以预测BAC≥0.05 g/dL(75%准确率)
  2. 非侵入式,无需额外传感器,复用现有DMS硬件
  3. 实时性,适合车内持续监测
  4. 低成本,无需新增硬件投入

对于IMS开发,这篇论文提供了可直接复现的技术路线:MediaPipe关键点 → EAR/MAR/HeadPose特征 → 时序聚合 → Random Forest回归 → BAC估计。

虽然准确率尚低于呼吸测试,但作为持续监测方案,可与疲劳/分心检测融合形成综合损伤评估系统,为Euro NCAP 2030酒驾检测要求提前布局。


参考链接:


WACV 2024 论文解读:通过面部特征估计血液酒精浓度——酒驾损伤检测的视觉AI突破
https://dapalm.com/2026/07/04/2026-07-04-alcohol-impairment-vision-bac-estimation-wacv-2024-zh/
作者
Mars
发布于
2026年7月4日
许可协议