在计算机视觉领域,面部表情识别(FER)是一个长期热门的研究方向。作为该领域最经典的基准数据集之一,CK(Extended Cohn-Kanade Dataset)和CK+(Extended Cohn-Kanade Dataset+)由卡耐基梅隆大学机器人研究所于2000-2010年间收集整理,已成为表情识别算法研发和性能评估的黄金标准。
这两个数据集记录了210名18-50岁被试者在实验室环境下表现出的面部表情变化,包含多种族、多年龄段的样本分布。原始CK数据集提供486个视频序列,而CK+在其基础上扩展至593个视频序列,并增加了更精确的表情标注。每个视频以中性表情开始,逐步过渡到目标表情的峰值状态,平均时长约20帧(约0.67秒),采用640x490或640x480分辨率保存。
重要提示:使用这类数据集时需严格遵守数据使用协议。虽然CK/CK+属于学术公开数据集,但商用前仍需确认授权状态,特别是涉及人脸数据的商业应用需额外注意隐私合规问题。
数据采集在严格控制的实验室环境中完成:
表情标注采用两种体系:
数据集目录结构示例:
code复制CK+
├── EmoLabel
│ ├── S005_001_00000011_emotion.txt
│ └── ...
├── Landmarks
│ ├── S005_001_00000011_landmarks.txt
│ └── ...
└── Images
├── S005_001
│ ├── S005_001_00000001.png
│ └── ...
└── ...
实际应用中通常需要以下预处理步骤:
python复制import dlib
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
def align_face(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = detector(gray)
if len(faces) == 1:
landmarks = predictor(gray, faces[0])
# 计算对齐变换矩阵
# 应用仿射变换...
return aligned_face
python复制aug = albumentations.Compose([
albumentations.HorizontalFlip(p=0.5),
albumentations.GaussNoise(var_limit=(10, 50), p=0.3),
albumentations.RandomBrightnessContrast(
brightness_limit=0.2, contrast_limit=0.2, p=0.5),
albumentations.Rotate(limit=15, p=0.5)
])
使用PyTorch实现的基础模型架构:
python复制class BasicCNN(nn.Module):
def __init__(self, num_classes=7):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(1, 64, 3, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(64, 128, 3, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(128, 256, 3, padding=1),
nn.BatchNorm2d(256),
nn.ReLU(),
nn.MaxPool2d(2)
)
self.classifier = nn.Sequential(
nn.Linear(256*6*6, 1024),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(1024, num_classes)
)
def forward(self, x):
x = self.features(x)
x = torch.flatten(x, 1)
return self.classifier(x)
结合LSTM的时序处理模型:
python复制class CNNLSTM(nn.Module):
def __init__(self, num_classes=7):
super().__init__()
self.cnn = BasicCNN() # 复用前面的CNN结构
self.lstm = nn.LSTM(
input_size=1024,
hidden_size=256,
num_layers=2,
batch_first=True
)
self.fc = nn.Linear(256, num_classes)
def forward(self, x):
# x shape: (batch, seq_len, C, H, W)
batch, seq_len = x.shape[:2]
cnn_features = []
for t in range(seq_len):
feat = self.cnn.features(x[:, t])
feat = torch.flatten(feat, 1)
feat = self.cnn.classifier[:2](feat) # 获取CNN倒数第二层特征
cnn_features.append(feat)
lstm_input = torch.stack(cnn_features, dim=1)
lstm_out, _ = self.lstm(lstm_input)
return self.fc(lstm_out[:, -1]) # 取最后时间步输出
CK+各类表情样本数量分布:
| 表情类别 | 样本数量 |
|---|---|
| 愤怒 | 45 |
| 厌恶 | 59 |
| 恐惧 | 25 |
| 快乐 | 69 |
| 悲伤 | 28 |
| 惊讶 | 83 |
| 中性 | 327 |
应对策略:
python复制class_counts = torch.tensor([45, 59, 25, 69, 28, 83, 327])
weights = 1. / (class_counts / class_counts.sum())
criterion = nn.CrossEntropyLoss(weight=weights)
当将在CK+上训练的模型迁移到其他数据集(如FER2013)时,常见性能下降问题。解决方案:
python复制# 使用MMD损失进行特征对齐
def mmd_loss(source, target):
diff = source.mean(0) - target.mean(0)
return diff.pow(2).sum()
# 在训练循环中加入
src_feat = model.features(src_img)
trg_feat = model.features(trg_img)
adapt_loss = mmd_loss(src_feat, trg_feat)
total_loss = class_loss + 0.1 * adapt_loss
CK+通常采用两种评估方案:
Subject-independent 10-fold交叉验证
固定划分方案
| 模型类型 | 参数量 | 准确率(%) | 推理速度(fps) |
|---|---|---|---|
| 传统SVM+HOG | - | 72.3 | 120 |
| 浅层CNN | 1.2M | 85.7 | 90 |
| ResNet-18 | 11.2M | 93.2 | 45 |
| 3D-CNN | 8.7M | 95.1 | 25 |
| CNN-LSTM | 6.3M | 96.8 | 18 |
实测建议:在嵌入式设备部署时,推荐使用MobileNetV3等轻量架构,可在保持90%+准确率的同时实现100+fps的实时性能。
CK+虽然主要针对宏表情,但其数据采集方法为微表情研究提供了基础。当前前沿方向包括:
结合其他模态数据提升性能:
python复制class MultimodalModel(nn.Module):
def __init__(self):
super().__init__()
self.visual_stream = CNNLSTM()
self.audio_stream = AudioNet()
self.fusion = nn.Linear(256+128, 7) # 视觉256维 + 音频128维
def forward(self, video, audio):
vis_feat = self.visual_stream(video)
aud_feat = self.audio_stream(audio)
return self.fusion(torch.cat([vis_feat, aud_feat], dim=1))
实际部署中发现,当视频帧率低于15fps时,时序模型性能会显著下降。这时可以: