📅  最后修改于: 2023-12-03 15:22:11.123000             🧑  作者: Mango
FER (Facial Expression Recognition) 是一种通过计算机视觉技术和面部表情识别技术,将面部表情转化为情感分类的方法。在近年来,FER 被广泛应用于人机交互、智能家居、医疗诊断等领域。
在本篇文章中,我们将介绍使用深度神经网络进行 FER 的实现,并给出相应的代码实现。
在深度学习领域中,卷积神经网络 (CNN) 是常用的处理图像数据的模型。因此我们选择使用 CNN 来实现 FER。
为了能够得到好的模型效果,我们采用经典的卷积神经网络模型 —— VGG16。该模型已经被证明在图像识别方面效果非常好。
构建好模型,我们需要一份数据集来训练模型。在 FER 方面,我们可以使用 CK+ 和 FER-2013 两个数据集。
CK+ 数据集是由来自加拿大皇家军事学院 (RMCC) 的 Lucey 等人构建的,包含了各种表情的照片以及相应的情感标注。
FER-2013 数据集是由 Goodfellow 等人构建的大规模面部表情识别数据集。
在本篇文章中,我们将使用 CK+ 数据集来训练我们的模型。你可以到 Wiki 链接下载数据集,我们选择使用 data 文件夹中的数据。
我们需要预处理 CK+ 数据集。首先,我们要将数据转换为灰度图。然后,我们将每张图片调整为 48x48 大小,并归一化到 [0,1]。最后,将每个图像和对应的标签(情感)存储在两个列表中。
import numpy as np
import cv2
import os
data_dir = 'data'
IMG_SIZE = 48
emotion_classes = {
0: 'anger',
1: 'contempt',
2: 'disgust',
3: 'fear',
4: 'happy',
5: 'sadness',
6: 'surprise'
}
def load_data():
images = []
labels = []
for emotion_class in os.listdir(data_dir):
class_path = os.path.join(data_dir, emotion_class)
for image_name in os.listdir(class_path):
image_path = os.path.join(class_path, image_name)
image = cv2.imread(image_path, 0)
image = cv2.resize(image, (IMG_SIZE, IMG_SIZE))
image = np.array(image, dtype='float32') / 255.0
label = int(emotion_class)
images.append(image)
labels.append(label)
return np.array(images), np.array(labels)
我们使用 Keras 来实现我们的模型。VGG16 模型的预训练权重已经被保存在 Keras 库中,我们可以很方便地使用它。
from keras.models import Model
from keras.layers import Input, Conv2D, MaxPooling2D, Flatten, Dense, Dropout
def build_model():
input_tensor = Input(shape=(IMG_SIZE, IMG_SIZE, 1))
block1_conv1 = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv1')(input_tensor)
block1_conv2 = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv2')(block1_conv1)
block1_pool = MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(block1_conv2)
block2_conv1 = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv1')(block1_pool)
block2_conv2 = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv2')(block2_conv1)
block2_pool = MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(block2_conv2)
block3_conv1 = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv1')(block2_pool)
block3_conv2 = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv2')(block3_conv1)
block3_conv3 = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv3')(block3_conv2)
block3_pool = MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(block3_conv3)
block4_conv1 = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv1')(block3_pool)
block4_conv2 = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv2')(block4_conv1)
block4_conv3 = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv3')(block4_conv2)
block4_pool = MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(block4_conv3)
block5_conv1 = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv1')(block4_pool)
block5_conv2 = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv2')(block5_conv1)
block5_conv3 = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv3')(block5_conv2)
block5_pool = MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(block5_conv3)
flatten = Flatten(name='flatten')(block5_pool)
fc1 = Dense(4096, activation='relu', name='fc1')(flatten)
fc1_dropout = Dropout(0.5)(fc1)
fc2 = Dense(4096, activation='relu', name='fc2')(fc1_dropout)
fc2_dropout = Dropout(0.5)(fc2)
output = Dense(7, activation='softmax', name='output')(fc2_dropout)
model = Model(inputs=input_tensor, outputs=output)
return model
我们需要将数据集划分为训练集和测试集。然后我们就可以开始训练我们的模型了。我们使用交叉熵损失函数和 Adam 优化器来训练模型。在每个 epoch 完成后,我们会评估模型在测试集上的准确率。
from sklearn.model_selection import train_test_split
images, labels = load_data()
images = images.reshape(-1, IMG_SIZE, IMG_SIZE, 1)
X_train, X_test, y_train, y_test = train_test_split(images, labels, test_size=0.15, random_state=0)
model = build_model()
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
model.fit(X_train, y_train, batch_size=32, epochs=10, validation_data=(X_test, y_test))
模型训练完成后,我们可以使用测试集来评估模型。我们计算模型在测试集上的准确率并输出结果。
scores = model.evaluate(X_test, y_test, verbose=0)
print('Accuracy: ', scores[1])
模型训练完毕后,我们可以对新的图片进行表情识别。
def predict_emotions(image_path):
image = cv2.imread(image_path, 0)
image = cv2.resize(image, (IMG_SIZE, IMG_SIZE))
image = np.array(image, dtype='float32') / 255.0
image = np.expand_dims(image, axis=0)
image = np.expand_dims(image, axis=3)
predictions = model.predict(image)
emotion_label = np.argmax(predictions)
emotion = emotion_classes[emotion_label]
return emotion
在本篇文章中,我们介绍了使用深度神经网络构建面部表情识别器的方法。我们选择了经典的 VGG16 模型,使用了 CK+ 数据集进行训练,并实现了表情识别功能。
通过这篇文章,你将学到:
我们希望这篇文章对你有所帮助。