共计 2645 个字符,预计需要花费 7 分钟才能阅读完成。
背景与应用价值
微表情识别在测谎、医疗诊断、人机交互等领域具有重要应用价值。这些短暂的面部表情变化(持续时间通常仅 1 /25 到 1 / 5 秒)往往能揭示人们试图隐藏的真实情绪。CASME 数据集作为微表情研究的基准数据集,提供了高帧率(200fps)的面部视频序列,并采用 FACS(面部动作编码系统)进行精细标注。

CASME 数据集的主要技术挑战包括:
- 数据量有限(CASME-II 仅 247 个样本)
- 微表情持续时间极短(平均仅 0.4 秒)
- 个体差异导致的表情幅度变化大
- 需要处理高帧率视频的时序特征
技术方案对比
传统光流法 vs 深度学习方法
- 传统光流法(如 TV-L1):
- 优点:计算资源需求低,可解释性强
-
缺点:对光照变化敏感,难以捕捉微小运动
-
深度学习方法 :
- 优点:自动学习特征表达,识别准确率高
- 缺点:需要大量训练数据,计算成本高
3D-CNN+LSTM 混合架构
这种混合架构结合了空间和时间特征提取的优势:
- 3D-CNN 部分:
- 使用 3D 卷积核同时捕捉空间和时间特征
-
典型配置:4 层 3D 卷积,每层后接批归一化和 ReLU
-
LSTM 部分:
- 处理长时序依赖关系
- 通常使用两层 LSTM,隐藏单元数设为 128
数据增强策略
针对样本不足问题,可采用以下增强方法:
- 时序插值:生成中间帧
- 空间变换:随机裁剪、旋转
- 颜色抖动:调整亮度、对比度
- 表情混合:不同样本的加权组合
代码实现
PyTorch DataLoader 示例
import torch
from torch.utils.data import Dataset, DataLoader
import cv2
import numpy as np
class CASMEDataset(Dataset):
def __init__(self, video_paths, labels, transform=None):
self.video_paths = video_paths
self.labels = labels
self.transform = transform
def __len__(self):
return len(self.video_paths)
def __getitem__(self, idx):
# 读取视频帧
cap = cv2.VideoCapture(self.video_paths[idx])
frames = []
while True:
ret, frame = cap.read()
if not ret:
break
# 转换为灰度并归一化
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
frame = frame.astype(np.float32) / 255.0
frames.append(frame)
cap.release()
# 时序切片处理(固定长度 50 帧)if len(frames) > 50:
start = random.randint(0, len(frames)-50)
frames = frames[start:start+50]
else:
# 不足时补零
padding = [np.zeros_like(frames[0])]*(50-len(frames))
frames.extend(padding)
frames = np.stack(frames, axis=0)
frames = torch.FloatTensor(frames)
if self.transform:
frames = self.transform(frames)
label = self.labels[idx]
return frames.unsqueeze(1), label # 添加通道维度
模型关键组件
import torch.nn as nn
class MicroExpressionModel(nn.Module):
def __init__(self, num_classes):
super().__init__()
# 3D-CNN 部分
self.cnn = nn.Sequential(nn.Conv3d(1, 32, kernel_size=(3,5,5), stride=(1,2,2)),
nn.BatchNorm3d(32),
nn.ReLU(),
nn.MaxPool3d(kernel_size=(1,2,2)),
nn.Conv3d(32, 64, kernel_size=(3,3,3)),
nn.BatchNorm3d(64),
nn.ReLU(),
nn.MaxPool3d(kernel_size=(1,2,2))
)
# LSTM 部分
self.lstm = nn.LSTM(input_size=64*6*6,
hidden_size=128,
num_layers=2,
batch_first=True)
# 分类头
self.fc = nn.Linear(128, num_classes)
def forward(self, x):
# x 形状: (batch, channel, time, height, width)
batch_size = x.size(0)
# 3D-CNN 处理
x = self.cnn(x) # 输出形状: (batch, 64, time, 6, 6)
# 调整形状适应 LSTM
x = x.permute(0, 2, 1, 3, 4) # (batch, time, 64, 6, 6)
x = x.reshape(batch_size, x.size(1), -1) # (batch, time, 64*6*6)
# LSTM 处理
x, _ = self.lstm(x)
x = x[:, -1, :] # 取最后一个时间步
# 分类
x = self.fc(x)
return x
实验与性能
在 CASME-II 子集上的实验结果:
| 模型 | 准确率 | 召回率 | F1 分数 |
|---|---|---|---|
| 3D-CNN+LSTM | 0.72 | 0.68 | 0.70 |
| ResNet18+TSN | 0.65 | 0.62 | 0.63 |
| EfficientNet-B0 | 0.69 | 0.66 | 0.67 |
关键超参数选择依据:
- 学习率:1e-4(小学习率防止震荡)
- batch size:8(受限于显存)
- 优化器:Adam(自适应学习率)
- 损失函数:交叉熵(多分类标准选择)
避坑指南
- 时间对齐问题 :
- 使用动态时间规整(DTW)对齐不同长度的视频
-
或采用注意力机制自适应关注关键帧
-
面部遮挡处理 :
- 添加随机遮挡增强(模拟真实场景)
- 使用注意力机制忽略遮挡区域
- 结合面部关键点定位
总结与展望
未来改进方向包括:
- 跨数据集迁移学习(如结合 SAMM、SMIC 数据集)
- 引入自监督预训练(利用大量未标注视频)
- 扩展 FACS 编码识别(不仅识别情绪类别,还能识别具体面部动作单元)
建议读者尝试将模型部署到实际应用场景,如在线面试分析、临床心理评估等,进一步验证模型的实用价值。
正文完
