共计 3226 个字符,预计需要花费 9 分钟才能阅读完成。
微表情识别与 CASME2 数据集简介
微表情是人类在试图隐藏真实情绪时,面部肌肉短暂且难以控制的表情变化,持续时间通常只有 1 /25 到 1 / 5 秒。在心理学研究、安全审讯和临床诊断等领域具有重要价值。CASME2 是当前最权威的微表情数据集之一,包含 26 名受试者的 247 个样本,具有以下特点:

- 分辨率统一为 100×100 像素
- 每个样本标注了起始帧(onset)、高峰帧(apex)和结束帧(offset)
- 采用面部动作编码系统(FACS)标注了动作单元(AU)
- 包含 5 种基本情绪类别:高兴、厌恶、惊讶、压抑和紧张
数据处理中的三大痛点
在实际使用 CASME2 时,初学者常会遇到以下问题:
- 视频帧提取困难 :原始 AVI 视频需要逐帧解析,且不同样本的微表情持续时间差异大
- 标签解析复杂 :标注信息分散在 Excel 文件和视频元数据中,需要合并处理
- 样本不均衡 :各类别样本量差异显著(如紧张类样本占比超过 40%)
技术实现方案
视频帧提取与面部 ROI 处理
使用 OpenCV 进行视频抽帧和面部裁剪:
import cv2
def extract_frames(video_path, output_dir):
cap = cv2.VideoCapture(video_path)
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
frame_count = 0
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# 转换为灰度图并检测人脸
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.1, 4)
for (x,y,w,h) in faces:
roi = frame[y:y+h, x:x+w]
resized = cv2.resize(roi, (100, 100))
cv2.imwrite(f'{output_dir}/frame_{frame_count}.jpg', resized)
frame_count += 1
cap.release()
标签文件解析
使用 Pandas 处理 AU_LOGGING.xlsx 文件:
import pandas as pd
def parse_annotations(excel_path):
df = pd.read_excel(excel_path)
# 提取关键列并重命名
annotations = df[['Subject', 'Filename', 'OnsetFrame', 'ApexFrame',
'OffsetFrame', 'Emotion']].copy()
annotations.columns = ['subject', 'filename', 'onset', 'apex', 'offset', 'emotion']
# 处理情绪类别编码
emotion_map = {'happiness':0, 'disgust':1, 'surprise':2,
'repression':3, 'tension':4}
annotations['label'] = annotations['emotion'].map(emotion_map)
return annotations
处理类别不平衡
在 PyTorch 中使用加权随机采样:
from torch.utils.data import WeightedRandomSampler
# 计算每个类别的样本权重
class_counts = np.bincount(labels)
class_weights = 1. / class_counts
sample_weights = class_weights[labels]
sampler = WeightedRandomSampler(
weights=sample_weights,
num_samples=len(sample_weights),
replacement=True
)
dataloader = DataLoader(dataset, batch_size=32, sampler=sampler)
模型架构设计
3D-CNN 与传统 2D-CNN 对比
| 特性 | 2D-CNN | 3D-CNN |
|---|---|---|
| 输入维度 | (C, H, W) | (C, T, H, W) |
| 卷积方式 | 空间卷积 | 时空卷积 |
| 时序建模 | 需额外 LSTM | 原生支持 |
| 参数量 | 较少 | 较大 |
| 适用场景 | 静态特征提取 | 动态序列分析 |
P3D-ResNet 轻量级实现
基于 PyTorch 的模型核心结构:
import torch.nn as nn
class P3DBlock(nn.Module):
def __init__(self, in_channels, out_channels):
super().__init__()
# 空间卷积分支
self.spatial = nn.Sequential(nn.Conv3d(in_channels, out_channels, kernel_size=(1,3,3), padding=(0,1,1)),
nn.BatchNorm3d(out_channels),
nn.ReLU())
# 时序卷积分支
self.temporal = nn.Sequential(nn.Conv3d(out_channels, out_channels, kernel_size=(3,1,1), padding=(1,0,0)),
nn.BatchNorm3d(out_channels),
nn.ReLU())
def forward(self, x):
x = self.spatial(x)
x = self.temporal(x)
return x
class MicroExpressionNet(nn.Module):
def __init__(self, num_classes=5):
super().__init__()
self.features = nn.Sequential(P3DBlock(3, 64),
nn.MaxPool3d(kernel_size=(1,2,2)),
P3DBlock(64, 128),
nn.MaxPool3d(kernel_size=(1,2,2)),
P3DBlock(128, 256)
)
self.classifier = nn.Sequential(nn.AdaptiveAvgPool3d(1),
nn.Flatten(),
nn.Linear(256, num_classes)
)
def forward(self, x):
# x 形状: (B, C, T, H, W)
x = self.features(x)
return self.classifier(x)
训练技巧与避坑指南
关键训练配置
- 学习率调度 :初始学习率设为 3e-4,每 10 个 epoch 衰减 0.1 倍
- 梯度累积 :在小批量显存不足时使用(示例配置 accum_steps=4)
- 早停机制 :当验证集损失连续 5 个 epoch 不下降时终止训练
常见问题解决方案
- 面部对齐问题 :
- 使用 dlib 的 68 点特征检测替代 OpenCV Haar 特征
-
对裁剪区域增加 10% 的边界缓冲
-
过拟合对策 :
- 在 P3D 块后添加 Dropout 层(p=0.3)
- 使用 MixUp 数据增强(α=0.2)
- 限制训练 epoch 不超过 50
性能评估与结果
在 80%-20% 的训练 - 验证划分下,模型应达到:
| 指标 | 目标值 |
|---|---|
| 加权准确率 | ≥0.68 |
| 加权 F1-score | ≥0.65 |
| 各类别召回率 | ≥0.55 |
开放性问题思考
对于极低强度微表情的检测,可以考虑:
1. 引入光流特征作为补充输入
2. 使用注意力机制强化关键帧特征
3. 设计专用的微表情强度评估模块
4. 结合心理学先验知识约束模型
结语
通过本实践,我们完成了从原始 CASME2 数据到可运行微表情识别系统的完整流程。建议初学者先复现基线模型,再逐步尝试:调整网络深度、引入 Transformer 模块、测试不同的数据增强策略等改进方向。记住在微表情识别任务中,时序建模能力和细粒度特征提取同样重要。
正文完
