当前位置:   article > 正文

人脸情绪识别(使用深度学习和OpenCV)_opencv emotion detection

opencv emotion detection

前言 

在这篇博客中,我将分享如何结合深度学习和OpenCV来创建一个能够实时识别人脸情感的系统。

本文主要为我个人的学习心得与总结,鉴于网络上知识信息的零散性,我特意进行了整合与阐述。若在整理过程中存在疏漏或错误之处,恳请各位不吝赐教,给予指正。需要强调的是,本文纯粹为学习交流之用,并不产生任何经济收益。若在文中出现任何涉及禁止转载或侵权的图片、文字内容,敬请及时与我取得联系,我将立即进行修正。

目录

前言 

项目简介

模型构建

导入必备的库

数据预处理 

模型构建

训练模型

保存模型 

实现面部表情识别:加载、训练和保存模型

实时应用 

代码分享与访问

总结


项目简介

情感检测在计算机科学领域中扮演着重要的角色,尤其在人机交互和情感智能应用中。本项目旨在利用深度学习技术,特别是卷积神经网络(CNN),来实现实时的情感检测。此外,OpenCV作为一个开源的计算机视觉库,为我们提供了处理图像和视频流的强大工具。

模型构建

导入必备的库

我们需要导入用到的Python库,包括数据处理库Pandas、科学计算库NumPy、深度学习框架Keras、以及计算机视觉库OpenCV

  1. import pandas as pd
  2. import numpy as np
  3. from keras.models import Sequential
  4. from keras.layers import Conv2D,MaxPooling2D,Dense,Dropout,Flatten
  5. from keras.losses import categorical_crossentropy
  6. from keras.optimizers import Adam
  7. from keras.utils import to_categorical

数据预处理 

在能够进行表情识别之前,我们需要加载并预处理数据。这一过程包括读取图像数据,将数据分割为训练和测试集,对数据进行标准化处理,以及将标签转换为one-hot编码格式。以下是数据预处理的代码段: 

  1. def load_and_preprocess_data(file_path):
  2. Catch_bat = pd.read_csv(file_path)
  3. X_train, Y_train, X_test, Y_test = [], [], [], []
  4. for index, row in Catch_bat.iterrows():
  5. val = row['pixels'].split(' ')
  6. try:
  7. if 'Training' in row['Usage']:
  8. X_train.append(np.array(val, 'float32'))
  9. Y_train.append(row['emotion'])
  10. elif 'PublicTest' in row['Usage']:
  11. X_test.append(np.array(val, 'float32'))
  12. Y_test.append(row['emotion'])
  13. except:
  14. pass
  15. X_train = np.array(X_train, 'float32')
  16. Y_train = np.array(Y_train, 'float32')
  17. X_test = np.array(X_test, 'float32')
  18. Y_test = np.array(Y_test, 'float32')
  19. X_train = (X_train - np.mean(X_train, axis=0)) / np.std(X_train, axis=0)
  20. X_test = (X_test - np.mean(X_test, axis=0)) / np.std(X_test, axis=0)
  21. labels = 7
  22. Y_train = to_categorical(Y_train, num_classes=labels)
  23. Y_test = to_categorical(Y_test, num_classes=labels)
  24. width, height = 48, 48
  25. X_train = X_train.reshape(X_train.shape[0], width, height, 1)
  26. X_test = X_test.reshape(X_test.shape[0], width, height, 1)
  27. return X_train, Y_train, X_test, Y_test

这段代码首先使用pandas读取CSV文件,然后根据“Usage”列将数据分割为训练集和测试集。接着,它将图像数据标准化,并将标签转换为one-hot编码格式。

模型构建

此函数的目的是构建一个卷积神经网络模型,用于面部表情的分类。以下是数据预处理的代码段: 

  1. def build_model(input_shape, num_classes):
  2. model = Sequential()
  3. model.add(Conv2D(64, kernel_size=(3, 3), activation='relu', input_shape=input_shape))
  4. model.add(Conv2D(64, kernel_size=(3, 3), activation='relu'))
  5. model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
  6. model.add(Dropout(0.5))
  7. model.add(Conv2D(64, kernel_size=(3, 3), activation='relu'))
  8. model.add(Conv2D(64, kernel_size=(3, 3), activation='relu'))
  9. model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
  10. model.add(Dropout(0.5))
  11. model.add(Conv2D(128, kernel_size=(3, 3), activation='relu'))
  12. model.add(Conv2D(128, kernel_size=(3, 3), activation='relu'))
  13. model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
  14. model.add(Flatten())
  15. model.add(Dense(512, activation='relu'))
  16. model.add(Dropout(0.2))
  17. model.add(Dense(num_classes, activation='softmax'))
  18. return model
  1. model = Sequential():初始化一个顺序模型。这是Keras中最简单的模型类型,允许我们按顺序一层层地添加模型层。
  2. model.add(Conv2D(...)):添加卷积层。这里使用64和128个滤波器(也就是输出空间的维度),每个卷积层后都跟着一个激活函数ReLU来增加非线性。
  3. MaxPooling2D(...):添加最大池化层,用于下采样,减少参数数量,防止过拟合。
  4. Dropout(0.5)和Dropout(0.2):添加Dropout层,随机丢弃一部分神经元(分别是50%和20%),以防止过拟合。
  5. Flatten():将多维的输入一维化,常用于卷积层到全连接层的过渡。
  6. Dense(...):添加全连接层。第一个全连接层有512个神经元,最后一个输出层的神经元数目等于分类的数目,使用softmax激活函数进行多分类。 

训练模型

  1. def train_model(model, X_train, Y_train, X_test, Y_test, batch_size=64, epochs=1):
  2. model.compile(loss=categorical_crossentropy, optimizer=Adam(), metrics=['accuracy'])
  3. model.fit(X_train, Y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(X_test, Y_test), shuffle=True)

这个函数用于训练上述定义的卷积神经网络模型。主要步骤包括:

  1.  model.compile(...):配置训练模型。使用categorical_crossentropy作为损失函数,这在多分类问题中很常见。Adam优化器用于调整权重,metrics=['accuracy']意味着训练和测试期间将监控精度。
  2.   model.fit(...):这里开始训练过程。使用提供的训练数据X_train和Y_train,批量大小batch_size,重复训练epochs次。同时,使用X_test和Y_test作为验证集来监控训练过程中的性能。

保存模型 

  1. def save_model(model, model_file, weights_file):
  2. model_json = model.to_json()
  3. with open(model_file, 'w') as json_file:
  4. json_file.write(model_json)
  5. model.save_weights(weights_file)

最后,这个函数用于保存训练好的模型,以便将来可以重新加载并使用,而无需重新训练。

  1. model_json = model.to_json():首先,将模型的架构转换为JSON格式的字符串。
  2. with open(model_file, 'w') as json_file:然后,将这个字符串写入一个文件中,保存模型的架构。
  3. model.save_weights(weights_file):最后,调用save_weights方法将模型的权重保存到另一个文件中。

实现面部表情识别:加载、训练和保存模型

在我们的项目中,我们使用了fer2013.csv数据集,它包含数千个标记了七种基本情感(愤怒、厌恶、恐惧、快乐、悲伤、惊讶和中性)的面部表情图像

  1. # 加载和预处理数据
  2. X_train, Y_train, X_test, Y_test = load_and_preprocess_data('fer2013.csv')
  3. # 构建模型
  4. input_shape = X_train.shape[1:]
  5. num_classes = 7
  6. model = build_model(input_shape, num_classes)
  7. # 训练模型
  8. train_model(model, X_train, Y_train, X_test, Y_test)
  9. # 保存模型
  10. save_model(model, 'file_name.json', 'file_name.h5')

实时应用 

  1. import cv2
  2. import numpy as np
  3. from keras.models import model_from_json
  4. with open('file_name.json', 'r') as json_file:
  5. loaded_model_json = json_file.read()
  6. model = model_from_json(loaded_model_json)
  7. model.load_weights('file_name.h5')
  8. face_prototxt = 'deploy.prototxt.txt'
  9. face_model = 'res10_300x300_ssd_iter_140000.caffemodel'
  10. face_net = cv2.dnn.readNetFromCaffe(face_prototxt, face_model)
  11. emotions = ('angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral')
  12. emotion_colors = {
  13. 'angry': (0, 0, 255),
  14. 'disgust': (0, 255, 0),
  15. 'fear': (255, 0, 0),
  16. 'happy': (255, 255, 0),
  17. 'sad': (255, 0, 255),
  18. 'surprise': (0, 255, 255),
  19. 'neutral': (255, 255, 255)
  20. }
  21. font = cv2.FONT_HERSHEY_SIMPLEX
  22. def process_image(img):
  23. gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  24. blob = cv2.dnn.blobFromImage(cv2.resize(img, (300, 300)), 1.0, (300, 300), (104.0, 177.0, 123.0))
  25. face_net.setInput(blob)
  26. faces = face_net.forward()
  27. for i in range(faces.shape[2]):
  28. confidence = faces[0, 0, i, 2]
  29. if confidence > 0.5:
  30. box = faces[0, 0, i, 3:7] * np.array([img.shape[1], img.shape[0], img.shape[1], img.shape[0]])
  31. (startX, startY, endX, endY) = box.astype("int")
  32. face = gray[startY:endY, startX:endX]
  33. face = cv2.resize(face, (48, 48))
  34. pixels = np.expand_dims(face, axis=0)
  35. pixels = pixels / 255.0
  36. pred = model.predict(pixels)
  37. max_index = np.argmax(pred[0])
  38. pred_emotion = emotions[max_index]
  39. color = emotion_colors.get(pred_emotion, (255, 255, 255))
  40. cv2.rectangle(img, (startX, startY), (endX, endY), color, 3)
  41. cv2.putText(img, pred_emotion, (int(startX), int(startY)), font, 1, color, 2)
  42. return img
  43. def process_image_file(file_path):
  44. img = cv2.imread(file_path)
  45. processed_img = process_image(img)
  46. cv2.namedWindow('image', 0)
  47. cv2.imshow('image', processed_img)
  48. cv2.waitKey(0)
  49. cv2.destroyAllWindows()
  50. process_image_file('you_image.jpg')

在这段代码中,我们加载了面部表情识别模型和人脸检测模型,然后定义了一个处理图像的函数。该函数首先将图像转换为灰度图,并使用人脸检测模型检测人脸。然后,对每个检测到的人脸进行表情识别,并根据预测结果在图像上绘制矩形和文本。最后,我们调用了处理单张图像文件的函数,并传入了一个示例图像文件的路径。 

除了能够处理静态图像,我们还可以让我们的系统实时处理视频流,并对其中的人脸进行情绪识别。下面是添加处理视频功能的代码:

  1. def process_video(video_path, output_path):
  2. cap = cv2.VideoCapture(video_path)
  3. fps = int(cap.get(cv2.CAP_PROP_FPS))
  4. frame_size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
  5. fourcc = cv2.VideoWriter_fourcc(*'XVID')
  6. out = cv2.VideoWriter(output_path, fourcc, fps, frame_size)
  7. while True:
  8. ret, frame = cap.read()
  9. if not ret:
  10. break
  11. processed_frame = process_image(frame)
  12. resize_frame = cv2.resize(processed_frame, frame_size)
  13. cv2.imshow('video', resize_frame)
  14. out.write(resize_frame)
  15. key = cv2.waitKey(1)
  16. if key == ord('q') or cv2.getWindowProperty('video', cv2.WND_PROP_VISIBLE) < 1:
  17. break
  18. cap.release()
  19. out.release()
  20. cv2.destroyAllWindows()

在上述代码中,我们添加了一个名为 process_video的函数,它接受输入视频文件的路径和输出视频文件的路径。这个函数会打开输入视频文件,逐帧读取视频流,并对每一帧进行情绪识别处理。然后,将处理后的帧写入输出视频文件。最后,释放资源并关闭所有窗口。

为了让我们的情绪识别系统更加实用和互动,我们进一步扩展了其功能,使之能够实时处理来自摄像头的视频流。以下是实现此功能的详细代码:

  1. def process_camera():
  2. cap = cv2.VideoCapture(0)
  3. while True:
  4. ret, frame = cap.read()
  5. if not ret:
  6. break
  7. processed_frame = process_image(frame)
  8. resize_frame = cv2.resize(processed_frame, (1000, 700))
  9. cv2.imshow('frame', resize_frame)
  10. key = cv2.waitKey(1)
  11. if key == ord('q') or cv2.getWindowProperty('frame', cv2.WND_PROP_VISIBLE) < 1:
  12. break
  13. cap.release()
  14. cv2.destroyAllWindows()

在这段代码中,我们首先通过 cv2.VideoCapture(0) 打开系统默认的摄像头。接下来,程序进入一个循环,在这个循环中持续从摄像头读取帧。对于每一帧,我们调用 process_image 函数进行所需的图像处理。为了更好的显示效果,我们还将处理后的帧大小调整为 1000x700 像素。如果用户按下 'q' 键或关闭显示窗口,循环将终止,释放摄像头资源并关闭所有开启的窗口。 

代码分享与访问

为了方便大家更好地理解和使用我在本文中提到的技术和方法,我已经将相关代码上传至我的GitHub仓库。

您可以通过以下链接访问我GitHub仓库,并下载或查看这些代码:

GitHub - maxuan777/Face-Emotion-Recognition-: 基于opencv与深度学习的人脸情绪识别

在仓库中,您可以找到与本文内容相对应的代码文件和项目结构。这些代码已经经过我的测试与验证,应该可以正常运行。当然,如果您在使用过程中遇到任何问题或建议,欢迎在下方留言,我会尽快回复并帮助您解决。

总结

感谢您的阅读与支持!如果您对我的博客或代码有任何意见或建议,欢迎在下方留言或私信我。

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号