共计 2618 个字符,预计需要花费 7 分钟才能阅读完成。
微表情识别与 CASME2 数据集简介
微表情是人类在试图隐藏真实情感时,面部肌肉短暂、不自主的微小动作,持续时间通常只有 1 /25 到 1 / 5 秒。这种非语言行为在心理治疗、安全审讯等领域具有重要价值。CASME2 是目前最权威的微表情数据集之一,包含 26 名受试者的 247 个样本,具有以下特点:

- 高分辨率:所有视频帧均为 100×100 像素,聚焦面部区域
- 精细标注:包含 AUs(面部动作单元)编码、起始帧、情绪类别等
- 多模态数据:同时提供面部温度变化信息(需红外摄像头)
数据准备中的三大挑战
在实际使用 CASME2 时,初学者常会遇到这些难题:
- 视频帧提取复杂:原始 AVI 视频需要逐帧处理,且不同样本的时长差异大
- 标签解析困难:标注信息分散在 Excel 文件和视频文件名中
- 类别不均衡:”happiness” 类样本量是 ”disgust” 的 3 倍以上
实战准备工作
环境配置建议
推荐使用 Python 3.8+ 和以下库版本:
opencv-python==4.5.5.64
torch==1.11.0
pandas==1.4.2
数据预处理全流程
视频帧抽取与面部 ROI 裁剪
使用 OpenCV 进行关键帧提取时,要注意微表情的持续时间特征:
import cv2
def extract_frames(video_path, output_dir, fps=25):
cap = cv2.VideoCapture(video_path)
frame_count = 0
while True:
ret, frame = cap.read()
if not ret:
break
# 转换为灰度图并保存
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imwrite(f"{output_dir}/frame_{frame_count:04d}.jpg", gray)
frame_count += 1
cap.release()
标注文件解析技巧
AU_LOGGING.xlsx文件中包含关键的时间标注信息,建议这样处理:
import pandas as pd
def parse_annotations(excel_path):
df = pd.read_excel(excel_path)
# 提取微表情起止帧
annotations = df[['Subject', 'OnsetFrame', 'ApexFrame']].copy()
return annotations
解决类别不平衡问题
PyTorch 的 WeightedRandomSampler 能有效缓解样本不均衡:
from torch.utils.data import WeightedRandomSampler
# 计算每个类别的样本权重
class_counts = torch.bincount(labels)
class_weights = 1. / class_counts
sample_weights = class_weights[labels]
sampler = WeightedRandomSampler(
weights=sample_weights,
num_samples=len(sample_weights),
replacement=True
)
3D-CNN 模型构建
相比传统 2D-CNN,3D 卷积能同时捕捉空间和时间特征。这里给出 P3D-ResNet 的简化实现:
import torch.nn as nn
class P3DBlock(nn.Module):
def __init__(self, in_channels):
super().__init__()
# 空间卷积分支
self.spatial = nn.Sequential(nn.Conv3d(in_channels, in_channels, kernel_size=(1,3,3), padding=(0,1,1)),
nn.BatchNorm3d(in_channels),
nn.ReLU())
# 时间卷积分支
self.temporal = nn.Sequential(nn.Conv3d(in_channels, in_channels, kernel_size=(3,1,1), padding=(1,0,0)),
nn.BatchNorm3d(in_channels),
nn.ReLU())
def forward(self, x):
return self.temporal(self.spatial(x))
训练过程中的关键技巧
- 梯度累积:当 GPU 显存不足时,可以通过多次前向传播累积梯度
optimizer.zero_grad()
for i, (inputs, labels) in enumerate(train_loader):
outputs = model(inputs)
loss = criterion(outputs, labels)
loss = loss / accumulation_steps # 梯度累积
loss.backward()
if (i+1) % accumulation_steps == 0:
optimizer.step()
optimizer.zero_grad()
- EarlyStopping 配置:
from pytorchtools import EarlyStopping
es = EarlyStopping(patience=10, verbose=True)
for epoch in range(epochs):
val_loss = validate()
es(val_loss, model)
if es.early_stop:
break
效果评估与优化
在验证集上达到 0.65+ 的加权 F1-score 需注意:
- 使用
sklearn.metrics.classification_report计算各类别指标 - 重点关注少数类别的召回率
- 混淆矩阵能直观显示模型对相似表情(如 ”surprise” 和 ”fear”)的区分能力
常见问题解决方案
- 面部对齐问题:
- 使用 dlib 或 MTCNN 进行人脸关键点检测
-
应用相似变换统一面部位置
-
过拟合应对:
- 添加 SpatialDropout3D 层
- 使用 Label Smoothing 技术
开放性问题探讨
对于极低强度微表情的检测,可以考虑:
– 引入光流特征作为辅助输入
– 尝试 Transformer 架构捕捉长时序依赖
– 使用放大神经网络 (MicroExpNet) 增强微小运动
通过本教程,读者应该能够建立起完整的微表情识别流程。虽然 CASME2 数据集存在挑战,但通过合理的数据处理和模型设计,完全可以达到科研级的表现要求。
正文完
