当前位置:   article > 正文

基于深度学习的人脸表情识别系统_python课程设计报告基于深度学习人脸表情识别系统

python课程设计报告基于深度学习人脸表情识别系统

目录

1.项目背景:

2.人脸检测

2.1 Haar特征

2.2 级联分类器

2.3 OpenCV人脸检测

3.人脸表情识别

3.1 Mini-Xception网络

3.1.1 深度可分离卷积

3.1.2 批量归一化层

3.1.3算法代码实现

3.2 基于Mini-Xception的表情识别

3.2.1 数据预处理

3.2.2 构建网络模型

4.实验结果与分析

4.1 模型训练

4.2 结果分析

4.3 应用测试


1.项目背景:

人类的面部表情是其最直接有效的情绪表达方式,针对表情识别技术的研究被认为是未来人机情感交互的主要发展方向。美国的心理学家Ekman和Friesen经过大量的实验与测试后,将人类的表情定义为以下六类:生气(Angry)、厌恶(Disgust)、恐惧(Fear)、高兴(Happiness)、悲伤(Sadness)和惊讶(Surprise)。实际情况下为了和无表情有所区分,一般还增加一类:正常(Neutral),共计7种基础表情,如图1所示。在这个人工智能技术成为热门的时代,人脸表情识别已成为其中的一项研究热点,而卷积神经网络、深度信念网络和多层感知器等端对端的算法在人脸面部表情识别领域的运用尤为广泛。

                       

                                                图1-人类常见的七种表情

目前,人脸识别( Facial Recognition, FR)精度已经超过人眼,人脸表情识别作为FR技术的一个重要组成部分,在计算机视觉、人机交互和情感计算中有着广泛的研究前景,包括人机交互、情绪分析、智能安全、娱乐、网络教育、智能医疗等。人脸表情识别的主要框架分为三个步骤:图像预处理、人脸检测和表情分类,如图2所示。

图2-人脸表情识别步骤

图片预处理通过调整大小和色彩优化图像,减少光照和角度的干扰,提升模型准确性。人脸检测算法用于定位图片中的一个或多个人脸位置,以便进行表情识别。早期研究依赖特征工程和分类算法,如LBP、HOG和Haar特征,这些方法虽简便但适应性有限。本文采用深度学习,训练卷积神经网络构建表情分类模型,实现更快速、准确的表情识别。

2.人脸检测

人脸检测就是用来判断一张图片中是否存在人脸的操作。如果图片中存在人脸,则定位该人脸在图片中的位置;如果图片中不存在人脸,则返回图片中不存在人脸的提示信息。人脸检测是表情识别中必不可少的环节,其检测效果的好坏,将直接影响整个系统的性能优劣。如图3所示,绿色矩形框代表了从图片中检测到的人脸图像位置。

                                         

                                                   图3-人脸检测示意图

在本文中,摄像头捕获人脸面部图像后,利用Haar特征和Adaboost级联分类器将捕获的图像进行人脸检测。本文使用的是OpenCV中的人脸检测方法——Haar级联分类器,该方法思路如下:

  1. 使用一个检测窗口在图片上滑动,提取该窗口内图片的特征;
  2. 通过分类器判断该窗口中是否存在人脸;
  3. 如果该窗口中存在人脸则返回该窗口坐标,如果不存在人脸则重复步骤(1);
  4. 若图片的全部区域被扫描完毕,结束检测。

Haar级联分类器可对一整张图片进行多区域、多尺度的检测。多区域检测,即将图片划分为多块,对每个块(检测窗口)进行检测。在人脸检测过程中,出现同一个人脸被多次检测时,需要进行区域的合并,该过程通常使用非极大值抑制(Non-Maximum Suppression, NMS)[6],以防止人脸区域被多次检出的问题。

2.1 Haar特征

Haar特征,也称为Haar-like特征,是Viola-Jones识别器的核心组成部分。这种特征最初在《Robust Real-Time Face Detection》一文中被详细描述,并广泛用于人脸检测任务。Haar特征的提取方法相对简单,主要通过在图像上应用不同的模板来提取特征,然后选择最具代表性的特征进行分类。

Haar特征主要分为三类:边缘特征、线性特征、中心特征和对角线特征。这些特征通过特定的模板来提取,模板由黑色和白色矩形组成,其特征值计算为白色矩形像素值之和减去黑色矩形像素值之和。这种计算方式使得Haar特征能够反映图像中的灰度变化情况。

例如,脸部的某些特征如眼睛或嘴部周围的颜色通常比较深,而脸颊或额头等区域的颜色较浅,这种差异可以通过Haar特征有效地捕捉。然而,Haar特征对于简单的图形结构如边缘和线段较为敏感,因此主要用于描述具有特定方向(如水平、垂直或对角)的结构。

在实际应用中,Haar特征通过不同模板的黑白区域像素值差异进行提取。这些模板的设计使得它们能够捕捉到图像中特定方向上的灰度变化,从而用于描述人脸等复杂图案的特定特征。尽管Haar特征具有一定的局限性,只能描述具有特定方向的结构,但其在人脸检测领域的应用表明了其有效性和实用性。

图4-Haar特征采用的特征模板

Haar特征模板由相邻的黑白矩形组成,通过计算白色矩形像素值之和与黑色矩形像素值之和的差来提取图像特征。这些矩形特征对简单图形结构如边缘和线段敏感,适用于区分人脸与非人脸区域。在图像中移动这些模板可以量化人脸特征,从而帮助识别人脸。图5展示了用Haar特征提取人脸图像特征的过程,其中模板应用于图像不同区域以生成用于分类的数据。

图5-Haar特征提取过程演示

2.2 级联分类器

OpenCV在人脸检测中需计算检测区域的Haar特征值。这些值由AdaBoost算法分析,以判断是否存在人脸。AdaBoost算法结合多个弱分类器形成一个强分类器。为提高检测效果,OpenCV采用级联分类器,串联多个基于AdaBoost的强分类器。在检测过程中,仅当所有分类器均判定存在人脸时,该区域才被认定为人脸区域。级联分类器方法提高了人脸检测的准确性和效率。

图6-基于级联分类器的人脸检测流程

将所有特征应用于所有训练图像,对于每个特征,算法会找到最佳的阈值,该阈值会将人脸分为正面和负面。在此过程中会出现错误或分类错误,算法选择错误率最低的特征,即对人脸和非人脸图像进行最准确分类的特征。在开始时,每个图像的权重均相等,在每次分类后,错误分类的图像的权重都会增加。然后执行相同的过程,将计算新的错误率并据此更新权重。重复进行该过程,直到达到所需的精度或错误率或找到所需的功能数量为止。

2.3 OpenCV人脸检测

以Haar特征分类器为基础的对象检测技术是一种非常有效的对象检测技术,它是基于机器学习的,使用大量的正负样本训练得到分类器。其实就是基于对人脸特征的描述,分类器根据训练的样品数据进行训练,完成后即可感知读取到的图片上的特征,进而对图片进行人脸识别。以下是基于OpenCV的人脸检测算法的代码

  1. # encoding:utf-8
  2. import cv2
  3. import numpy as np
  4. # 加载人脸检测器
  5. face_cascade = cv2.CascadeClassifier('haarcascade_files/haarcascade_frontalface_default.xml')
  6. # 加载眼睛检测器
  7. eye_cascade = cv2.CascadeClassifier('haarcascade_files/haarcascade_eye.xml')
  8. # 读取图片
  9. img = cv2.imread('lovers.jpg')
  10. # 将图片转换为灰度图
  11. gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  12. # 使用人脸检测器检测人脸
  13. faces = face_cascade.detectMultiScale(gray,
  14. scaleFactor=1.1,
  15. minNeighbors=5,
  16. minSize=(30, 30),
  17. flags=cv2.CASCADE_SCALE_IMAGE)
  18. # 输出检测到的人脸数量
  19. print('Detected ', len(faces), " face")
  20. # 遍历检测到的人脸
  21. for (x, y, w, h) in faces:
  22. # 在原图上画出人脸矩形框
  23. img = cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 1)
  24. # 提取人脸区域的灰度图和彩色图
  25. roi_gray = gray[y: y + h, x: x + w]
  26. roi_color = img[y: y + h, x: x + w]
  27. # 使用眼睛检测器检测眼睛
  28. eyes = eye_cascade.detectMultiScale(roi_gray)
  29. # 遍历检测到的眼睛
  30. for (ex, ey, ew, eh) in eyes:
  31. # 在人脸区域画出眼睛矩形框
  32. cv2.rectangle(roi_color, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 1)
  33. # 在图片上添加文字标签
  34. label = 'Result: Detected ' + str(len(faces)) +" faces !"
  35. cv2.putText(img, label, (10, 20),
  36. cv2.FONT_HERSHEY_SCRIPT_COMPLEX,
  37. 0.8, (0, 0, 0), 1)
  38. # 显示图片
  39. cv2.imshow('img', img)
  40. # 等待按键,关闭窗口
  41. cv2.waitKey(0)
  42. cv2.destroyAllWindows()

以上代码利用Haar级联分类器对图片中人物的脸部及眼睛区域利用矩形框进行标记,其检测结果如图7所示:

图7-人脸检测结果

3.人脸表情识别

表情识别(Facial Expression Recognition, FER)是计算机理解人类情感的一个重要方向,是指从静态照片或视频序列中识别出表情状态,从而确定对人物的情绪与心理变化。传统人脸表情识别的实现过程主要由人脸图像获取、人脸检测、特征提取、特征分类四部分组成,其研究主要体现在特征提取和特征分类上,传统的表情识别方法主要依赖于手工特征提取技术如主元分析法(PCA)、独立分量分析法(ICA)、线性判别分析法(LDA)以及LBP算子等,和分类技术如贝叶斯网络、隐马尔科夫模型、近邻法和支持向量机等。这些方法在小样本上表现良好,但在新环境中的鲁棒性不足,且特征提取与分类是分开的两个阶段,无法整合为一个端到端的模型。卷积神经网络(CNN),受到生物视觉系统启发,通过局部连接、子采样和权重共享等特性,能在图像平移、缩放和旋转中保持较高的不变性,已从理论原型发展为可实际运用的网络模型。尽管CNN因其自学习能力而广受应用,但存在训练时间长和参数量大等问题。针对这些问题,本文基于Xception网络,简化了网络层级,去除了全连接层,并使用深度可分离卷积代替传统卷积层,构建了mini-Xception网络模型用于表情分类,旨在提高模型效率和性能。

3.1 Mini-Xception网络

传统的卷积操作联合映射了通道和空间的相关性。而Szegedy等提出的Extreme Inception模块和Chollet等提出的Xception网络,假设并实现了通道与空间相关性的完全分离,通过深度可分离卷积来优化这一过程。Xception网络先对每个信道进行常规卷积和逐点卷积,每次卷积后都加入批量归一化和ReLU激活函数,中间模块采用残差连接以简化训练。本文的表情分类网络架构Mini-Xception,包含4个残差深度可分离卷积块,每个卷积后进行批量归一化和ReLU激活。最后用全局平均池化层和softmax激活函数进行预测,旨在提升模型效率和性能。

图8-Mini-Xception网络结构示意图

mini-Xception网络模型在Xception基础上简化结构,移除全连接层并采用深度可分离卷积层。此改变显著减少训练参数和时间,增强模型泛化能力。

3.1.1 深度可分离卷积

深度可分离卷积(Depthwise Separable Convolution)是Xception中的一项改进之处,它替代了原来Inception V3网络中的卷积操作。深度可分离卷积由深度卷积(DepthWise Convolution)和逐点卷积(PointWise Convolution)两部分组成。深度卷积对输入层的每个通道独立进行卷积运算,而逐点卷积的运算与常规卷积运算非常相似,将上一步的特征图(Feature Maps)在深度方向上进行加权组合,生成新的特征图,有多少个卷积核就有多少个输出特征图。

图9-卷积操作示意图

3.1.2 批量归一化层

当网络层级结构较多时,训练收敛速度可能变慢。Xception模型在每层输入前插入BN层,对数据进行归一化处理,保证数据稳定性,并避免过拟合问题。这样,数据的分布被控制在一个稳定的范围内,有利于网络的稳定训练和性能提升

3.1.3算法代码实现

Mini-Xception网络的Python实现如下,具体采用Keras框架实现:

  1. # 定义一个名为mini_XCEPTION的函数,它接受输入形状、类别数和一个可选的L2正则化参数
  2. def mini_XCEPTION(input_shape, num_classes, l2_regularization=0.01):
  3. # 创建一个L2正则化对象,用于在模型训练过程中对权重进行惩罚,以防止过拟合
  4. regularization = l2(l2_regularization)
  5. # 基础层(base layer)
  6. # 创建一个输入层,用于接收指定形状的图像数据
  7. img_input = Input(input_shape)
  8. # 第一个卷积层,使用3x3的卷积核,步长为1,不使用偏置项,应用了之前定义的L2正则化
  9. x = Conv2D(8, (3, 3), strides=(1, 1), kernel_regularizer=regularization, use_bias=False)(img_input)
  10. # 对卷积层的输出进行批量归一化,这有助于规范化激活值,加速训练过程
  11. x = BatchNormalization()(x)
  12. # 应用ReLU激活函数,引入非线性,增强模型的表达能力
  13. x = Activation('relu')(x)
  14. # 第二个卷积层,与第一个卷积层类似,但作用于上一层输出的特征图
  15. x = Conv2D(8, (3, 3), strides=(1, 1), kernel_regularizer=regularization, use_bias=False)(x)
  16. x = BatchNormalization()(x)
  17. x = Activation('relu')(x)
  18. # 模块1(module 1)
  19. # 创建一个残差连接,通过1x1卷积进行下采样,将特征图的通道数减半
  20. residual = Conv2D(16, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
  21. # 对残差连接的输出进行批量归一化
  22. residual = BatchNormalization()(residual)
  23. # 使用SeparableConv2D进行深度可分离卷积,这是一种高效的卷积方式,可以减少参数量
  24. x = SeparableConv2D(16, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x)
  25. # 对深度可分离卷积的输出进行批量归一化
  26. x = BatchNormalization()(x)
  27. # 应用ReLU激活函数
  28. x = Activation('relu')(x)
  29. # 再次应用深度可分离卷积,增加特征的复杂度
  30. x = SeparableConv2D(16, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x)
  31. x = BatchNormalization()(x)
  32. # 使用最大池化层进行下采样,减少特征图的空间尺寸
  33. x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)
  34. # 将下采样的输出与残差连接相加,这是残差学习的基本操作,有助于训练深层网络
  35. x = layers.add([x, residual])
  36. # 模块2(module 2)
  37. # 创建另一个残差连接,通过1x1卷积进行下采样,将特征图的通道数进一步减半
  38. residual = Conv2D(32, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
  39. # 对残差连接的输出进行批量归一化
  40. residual = BatchNormalization()(residual)
  41. # 继续模块2(module 2)的处理
  42. # 使用SeparableConv2D进行深度可分离卷积,这是一种高效的卷积方式,可以减少参数量
  43. x = SeparableConv2D(32, (3, 3), padding='same', kernel_regularizer=regularization,
  44. use_bias=False)(x)
  45. # 对深度可分离卷积的输出进行批量归一化
  46. x = BatchNormalization()(x)
  47. # 应用ReLU激活函数
  48. x = Activation('relu')(x)
  49. # 再次应用深度可分离卷积,增加特征的复杂度
  50. x = SeparableConv2D(32, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x)
  51. x = BatchNormalization()(x)
  52. # 使用最大池化层进行下采样,减少特征图的空间尺寸
  53. x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)
  54. # 将下采样的输出与残差连接相加,这是残差学习的基本操作,有助于训练深层网络
  55. x = layers.add([x, residual])
  56. # 模块3(module 3)
  57. # 创建另一个残差连接,通过1x1卷积进行下采样,将特征图的通道数进一步减半
  58. residual = Conv2D(64, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
  59. # 对残差连接的输出进行批量归一化
  60. residual = BatchNormalization()(residual)
  61. # 使用SeparableConv2D进行深度可分离卷积
  62. x = SeparableConv2D(64, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x)
  63. # 对深度可分离卷积的输出进行批量归一化
  64. x = BatchNormalization()(x)
  65. # 应用ReLU激活函数
  66. x = Activation('relu')(x)
  67. # 再次应用深度可分离卷积
  68. x = SeparableConv2D(64, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x)
  69. x = BatchNormalization()(x)
  70. # 使用最大池化层进行下采样
  71. x = MaxPooling2D((3, 3), strides=(2, 2), padding='same)(x)
  72. # 将下采样的输出与残差连接相加
  73. x = layers.add([x, residual])
  74. # 模块4(module 4)
  75. # 创建另一个残差连接,通过1x1卷积进行下采样,将特征图的通道数进一步减半
  76. residual = Conv2D(128, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
  77. # 对残差连接的输出进行批量归一化
  78. residual = BatchNormalization()(residual)
  79. # 使用SeparableConv2D进行深度可分离卷积
  80. x = SeparableConv2D(128, (3, 3), padding='same', kernel_regularizer=regularization,
  81. use_bias=False)(x)
  82. # 对深度可分离卷积的输出进行批量归一化
  83. x = BatchNormalization()(x)
  84. # 应用ReLU激活函数
  85. x = Activation('relu')(x)
  86. # 再次应用深度可分离卷积
  87. x = SeparableConv2D(128, (3, 3), padding='same', kernel_regularizer=regularization,
  88. use_bias=False)(x)
  89. x = BatchNormalization()(x)
  90. # 使用最大池化层进行下采样
  91. x = MaxPooling2D((3, 3), strides=(2, 2), padding='same)(x)
  92. # 将下采样的输出与残差连接相加
  93. x = layers.add([x, residual])
  94. # 最后层
  95. # 使用1x1的卷积层将特征图转换为类别分数,这里没有应用正则化
  96. x = Conv2D(num_classes, (3, 3), padding='same')(x)
  97. # 全局平均池化层,将空间维度压缩为1x1
  98. x = GlobalAveragePooling2D()(x)
  99. # softmax激活函数,输出类别概率分布
  100. output = Activation('softmax', name='predictions')(x)
  101. # 创建并返回模型实例
  102. model = Model(img_input, output)
  103. return model
3.2 基于Mini-Xception的表情识别

在构建神经网络模型前,首先要对输入的图像数据进行预处理操作。由于输入的原始图像可能存在光线不均、角度偏移等问题,因此在输入卷积神经网络进行训练前,要先对图像进行人脸位置检测、归一化、数据增强等预处理。

3.2.1 数据预处理

数据集是在非实验环境下获取的,其数据量相对于CK+等其他表情数据集更大,且样本更符合自然状态下的人脸表情。该数据部分数据如图14所示,其大多图像在平面和非平面上有旋转,并且很多有手、头发和围巾等的遮挡物的遮挡。由于数据库大多是从网络爬虫下载的,存在一定的误差性,这个数据库的人为准确率是65%±5%。

图10-数据集

先需要对数据集进行图像归一化处理,归一化是减少内部类特征不匹配的重要预处理技术,线性归一化处理如式所示。                     

图像增强(Image Augmentation)技术通过对训练图像做⼀系列随机改变,来产生相似但又不同的训练样本,从而扩大训练数据集的规模。随机改变训练样本可以降低模型对某些属性的依赖,从而提高模型的泛化能力。对数据集进行数据增强,即对一张人脸采用随机裁剪、旋转、缩放、调整色彩、调节亮度进行增广。对图像进行不同方式的裁剪,使感兴趣的物体出现在不同位置,从而减轻模型对物体出现位置的依赖性,同时使用灰度化来降低模型对色彩的敏感度。本文中,数据增强运用于模型训练过程中。

3.2.2 构建网络模型

表情识别可以看成一个多分类问题,输入的数据通过卷积层提取特征,再经由池化层对提取到的特征进行降维,最终由全连接层将降维后的特征“连接”起来进行分类。前期的研究表明,适当增加网络中间的隐藏层数目,可有效提高分类精度,但与此同时其训练时间也会增加。本文构建了Mini-Xception模型,简化了卷积层的模块数量,并删除了最后的全连接层,大大提升了识别速度,使得实时表情识别成为现实。

4.实验结果与分析

4.1 模型训练

本文的研究基于 Keras 深度学习框架搭建Mini-Xception模型,采用经预处理的表情数据集进行模型训练。随机抽取测试集的20%作为验证集,剩余部分作为训练样本,且训练集与验证集的样本数据无交叉。其训练参数设置如表1所示。

表1 训练参数设置

参数

取值

Batch Size

16

Epoch

10000

Patience

50

Num Classes

7

在模型训练过程中使用数据增强对数据集进行增广,数据增强操作的参数设置如表2所示:

表2 数据增强参数设置

增广类型

图片随机转动/

水平偏移

竖直偏移

水平翻转

缩放

参数

[-10, 10]

0.1

0.1

0.1

使用Adam优化器[12]进行网络参数优化,Adam算法具有梯度对角缩放的不变性,适用于处理含有大量参数的问题,且在训练过程中只需要进行少量的手动调整。

基于Keras框架编写了模型训练部分的代码,利用ImageDataGenerator()的图片生成器方法对数据进行增强,扩充数据集大小,以增强模型的泛化能力。模型训练部分的代码如下:

代码中设置了训练时的结果输出,在训练结束后会将训练的模型保存为hdf5文件到指定文件夹下,训练过程结果输出如图11所示。

图11-运行结果

4.2 结果分析

随着训练的不断进行,尽管其训练曲线不断波动,但训练集和验证集的准确率保持逐渐提升,最终两条曲线均达到平稳状态,得到的训练曲线如图12所示:

图12- 训练曲线

训练完成后,选取验证集准确率最佳的模型参数,最终在测试集进行测试验证。本文利用混淆矩阵对模型在测试集上的效果进行评估,其混淆矩阵的结果如图13所示。Mini-Xception 对Happy的识别率可达92%,而对Scared的识别度最低仅为56%,可能是因为不同表情的数量不均衡导致。在识别过程中可以观察到,Sad和Scared, Angry和Disgust 的识别难度较大。

图13-测试集混淆矩阵结果

从混淆矩阵中可以看出,生气(Angry)、厌恶(Disgust)、恐惧(Fear)、高兴(Happiness)、悲伤(Sadness)、惊讶(Surprise)及正常(Neutral)这7种表情在测试集的准确率依次为67%、67%、56%、92%、61%、82%及73%,最终可以计算出在整个测试集上Mini-Xception模型的准确率为71.14%,具有更加准确的效果。

4.3 应用测试

为了更好应用于日常的表情识别场景,检测实际的表情识别性能,结合前面章节介绍的人脸检测和表情识别算法,设计了实际场景下的表情识别过程,其识别过程如图14所示。

图14-实际场景表情识别过程

首先获取图像并进行预处理,然后利用Haar级联分类器检测人脸位置,对人脸位置区域利用Mini-Xception进行表情识别,最终将表情识别的结果显示并输出。根据以上流程,本文基于PyQt5设计了表情识别系统界面。该系统界面如图19所示,其大致功能如下:

(1)可选择模型文件后基于该模型进行识别;

(2)打开摄像头识别实时画面中的人脸表情;

(3)选择一张人脸图片,对其中的表情进行识别。

结合该系统软件对更多实际生活中的表情图片进行测试,如图15所示为日常生活中包含有开心和吃惊表情的图片,从图中可以看出该系统能够准确、快速地进行检测和识别。

图15-开心和吃惊

CSDN质量分数

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/787232
推荐阅读
相关标签
  

闽ICP备14008679号