人脸表情识别系统

目 录

1. 背景

2. 人脸检测

2.1 Haar特征

2.2 级联分类器

2.3 OpenCV人脸检测

3. 人脸表情识别

3.1 Mini-Xception网络

3.1.1 深度可分离卷积

3.1.2 批量归一化层

3.1.3 ReLU激活函数

3.1.4 Softmax层

3.1.4 算法代码实现

3.2 基于Mini-Xception的表情识别

3.2.1 数据预处理

3.2.2 构建网络模型

4. 实验结果与分析

4.1 模型训练

4.2 结果分析

4.3 应用测试

参考文献


1.背景:

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

图1 常见的几种表情

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

图2 人脸表情识别步骤

        图片预处理实现了图片大小及色彩的调整,使计算机读入的图片更易被处理。通过图像的预处理,可以尽量消除光照、角度等无关因素对模型的影响。图片经处理后再输入模型进行训练,可大大提高模型识别的精确度。为了提高表情识别效果,首先需要确定人脸位置,人脸检测就是利用人脸检测算法,对图片进行多区域、多尺度的检测,最终得到一个或多个人脸所在的位置,以方便对该区域进行识别。

        在表情识别的早期研究中,首先需要进行特征工程处理,然后利用分类算法进行表情分类。传统的特征提取方法,主要有局部二值模式(LBP)[3]、梯度方向直方图(HOG)[4]、Haar-like特征(Haar)[5]等。手工提取特征的方法对于简单问题能够快速解决,而对于复杂情况则有人工成本高、适应性差等问题。本文采用深度学习的方法,通过训练卷积神经网络构建表情分类模型,实现快速、准确的表情识别。

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特征值反映了图像的灰度变化情况。例如:脸部的一些特征能由矩形特征简单的描述,如:眼睛要比脸颊颜色要深,鼻梁两侧比鼻梁颜色要深,嘴巴比周围颜色要深等。但矩形特征只对一些简单的图形结构,如边缘、线段较敏感,所以只能描述特定走向(水平、垂直、对角)的结构。图4示出了Haar特征提取采用的若干模板,模板中有黑色和白色两个区域,将模板中黑色区域与白色区域内像素点的灰度值之和作差作为该模板提取到的特征。

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

        这类矩形特征模板由两个或多个全等的黑白矩形相邻组合而成,而矩形特征值是白色矩形的灰度值的和减去黑色矩形的灰度值的和,矩形特征对一些简单的图形结构,如线段、边缘比较敏感。如果把这样的矩形放在一个非人脸区域,那么计算出的特征值应该和人脸特征值不一样,所以这些矩形就是为了把人脸特征量化,以区分人脸和非人脸。在图像中不同区域使用模板进行特征提取,将得到大量数据,如图5所示演示了采用Haar特征对人脸图片进行特征提取的过程。

图5 Haar特征提取过程演示

2.2 级联分类器

        OpenCV在进行人脸检测时,除了需要对检测区域的图像求Haar特征值,在得到区域特征值后,分类器会判断该区域内是否存在人脸,这里通过AdaBoost算法实现。AdaBoost算法是一种用作分类的算法,通过组合若干个弱分类器,从而构成一个强分类器。

        在OpenCV中,为了得到最佳的检测效果,采用了将若干个基于AdaBoost算法实现的强分类器串联起来的方式,从而构成了一个串联的强分类器。在进行人脸检测时,若果全部分类器都表明该区域存在人脸,则判定该区域存在人脸,否则标记为不存在人脸。基于级联分类器的人脸检测流程如图6所示。

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

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

2.3 OpenCV人脸检测

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

# encoding:utf-8
import cv2
import numpy as np
 
# 加载人脸检测器
face_cascade = cv2.CascadeClassifier('haarcascade_files/haarcascade_frontalface_default.xml')
# 加载眼睛检测器
eye_cascade = cv2.CascadeClassifier('haarcascade_files/haarcascade_eye.xml')
 
# 读取图片
img = cv2.imread('lovers.jpg')
# 将图片转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
 
# 使用人脸检测器检测人脸
faces = face_cascade.detectMultiScale(gray,
                           scaleFactor=1.1,
                           minNeighbors=5,
                           minSize=(30, 30),
                            flags=cv2.CASCADE_SCALE_IMAGE)
 
# 输出检测到的人脸数量
print('Detected ', len(faces), " face")
 
# 遍历检测到的人脸
for (x, y, w, h) in faces:
    # 在原图上画出人脸矩形框
    img = cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 1)
    # 提取人脸区域的灰度图和彩色图
    roi_gray = gray[y: y + h, x: x + w]
    roi_color = img[y: y + h, x: x + w]
    
    # 使用眼睛检测器检测眼睛
    eyes = eye_cascade.detectMultiScale(roi_gray)
    
    # 遍历检测到的眼睛
    for (ex, ey, ew, eh) in eyes:
        # 在人脸区域画出眼睛矩形框
        cv2.rectangle(roi_color, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 1)
 
# 在图片上添加文字标签
label = 'Result: Detected ' + str(len(faces)) +" faces !"
cv2.putText(img, label, (10, 20),
                        cv2.FONT_HERSHEY_SCRIPT_COMPLEX, 
                        0.8, (0, 0, 0), 1)
 
# 显示图片
cv2.imshow('img', img)
# 等待按键,关闭窗口
cv2.waitKey(0)
cv2.destroyAllWindows()

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

图7-人脸检测结果 

3.人脸表情识别

        表情识别(Facial Expression Recognition, FER)是计算机理解人类情感的一个重要方向,是指从静态照片或视频序列中识别出表情状态,从而确定对人物的情绪与心理变化。传统人脸表情识别的实现过程主要由人脸图像获取、人脸检测、特征提取、特征分类四部分组成,其研究主要体现在特征提取和特征分类上

        传统的表情识别主要采用主元分析法(PCA)、独立分量分析法(ICA)、线性判别分析法(LDA)、LBP算子法等进行特征提取,利用贝叶斯网络(贝叶斯网络分类、隐马尔科夫模型)及距离度量方法(近邻法、支持向量机)等方法进行特征分类处理。人为设计的特征适用于小样本,在不受控制的新环境中鲁棒性较差,结果受制于设计的算法,耗费人力。另外,特征提取与分类是两个分开的过程,不能将其融合到一个End-to-End的模型中。

        卷积神经网络是受到生物学视觉系统的感受野机制的启发而提出的,即一个神经元只接受其所支配的刺激区域内的信号。经过近半个世纪的研究,卷积神经网络已从早期的理论原型发展成为可投入到实际应用的网络模型。标准的卷积神经网络由输入层、数个卷积层、池化层和全连接层堆叠而成,并通过反向传播来揭示海量数据中的复杂关系。其具有局部连接、子采样和权重共享的特征,这些特征使得神经网络能够在平移的过程中维持高度不变,并在缩放和旋转的过程中具有一定的不变性。

        卷积神经网络由于其自学习能力因而得到了广泛应用,但仍存在训练时间过长、参数量过大等问题。本文针对以上问题,在Xception神经网络的基础上简化了模型的网络层级,删除了传统神经网络的全连接层并使用深度可分离卷积替代传统的卷积层,构造了 mini-Xception 网络模型进行表情分类

3.1 Mini-Xception网络

        传统的卷积操作是将通道相关性与空间相关性进行联合映射,Szegedy等[7]假设卷积通道相关性和空间相关性可进行退耦,将二者分开映射,提出了Extreme Inception模块的方法。2016 年 Chollet 等[8]在 Inception 模型的基础上提出进一步的假设,即神经网络的通道相关性与空间相关性是可完全分离的,并使用深度可分离卷积[9]来替换Inception中的模块,由此得到Xception网络结构。Xception 与Extreme Inception极为类似但略有不同,前者先对每个信道的空间性进行常规卷积,再对每个信道进行1*1的逐点卷积。在每一次卷积操作后都加入批量归一化层(Batch Normalization, BN) [10]和激活函数ReLU。中间部分的模块则采用残差相连的方式,减少神经网络的训练难度。

        本文表情分类的网络架构采用Mini-Xception卷积神经网络,其结构如图9所示。其中包含4个残差深度可分离卷积块,每个卷积之后对卷积层进行批量归一化(BathNorm)操作及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层,对上一层输出的数据先做归一化处理再送入下一层。BN层可将每层输入的数据分布控制在均值为0,方差为1的范围内,保证数据的稳定性,可有效地避免因输入数据分布的变动导致的过拟合问题。

3.1.3算法代码实现

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

# 定义一个名为mini_XCEPTION的函数,它接受输入形状、类别数和一个可选的L2正则化参数
def mini_XCEPTION(input_shape, num_classes, l2_regularization=0.01):
    # 创建一个L2正则化对象,用于在模型训练过程中对权重进行惩罚,以防止过拟合
    regularization = l2(l2_regularization)
    
    # 基础层(base layer)
    # 创建一个输入层,用于接收指定形状的图像数据
    img_input = Input(input_shape)
    # 第一个卷积层,使用3x3的卷积核,步长为1,不使用偏置项,应用了之前定义的L2正则化
    x = Conv2D(8, (3, 3), strides=(1, 1), kernel_regularizer=regularization, use_bias=False)(img_input)
    # 对卷积层的输出进行批量归一化,这有助于规范化激活值,加速训练过程
    x = BatchNormalization()(x)
    # 应用ReLU激活函数,引入非线性,增强模型的表达能力
    x = Activation('relu')(x)
    # 第二个卷积层,与第一个卷积层类似,但作用于上一层输出的特征图
    x = Conv2D(8, (3, 3), strides=(1, 1), kernel_regularizer=regularization, use_bias=False)(x)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    
    # 模块1(module 1)
    # 创建一个残差连接,通过1x1卷积进行下采样,将特征图的通道数减半
    residual = Conv2D(16, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
    # 对残差连接的输出进行批量归一化
    residual = BatchNormalization()(residual)
    # 使用SeparableConv2D进行深度可分离卷积,这是一种高效的卷积方式,可以减少参数量
    x = SeparableConv2D(16, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x)
    # 对深度可分离卷积的输出进行批量归一化
    x = BatchNormalization()(x)
    # 应用ReLU激活函数
    x = Activation('relu')(x)
    # 再次应用深度可分离卷积,增加特征的复杂度
    x = SeparableConv2D(16, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x)
    x = BatchNormalization()(x)
    # 使用最大池化层进行下采样,减少特征图的空间尺寸
    x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)
    # 将下采样的输出与残差连接相加,这是残差学习的基本操作,有助于训练深层网络
    x = layers.add([x, residual])
    
    # 模块2(module 2)
    # 创建另一个残差连接,通过1x1卷积进行下采样,将特征图的通道数进一步减半
    residual = Conv2D(32, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
    # 对残差连接的输出进行批量归一化
    residual = BatchNormalization()(residual)
     # 继续模块2(module 2)的处理
     # 使用SeparableConv2D进行深度可分离卷积,这是一种高效的卷积方式,可以减少参数量
 x = SeparableConv2D(32, (3, 3), padding='same', kernel_regularizer=regularization, 
 use_bias=False)(x)
# 对深度可分离卷积的输出进行批量归一化
x = BatchNormalization()(x)
# 应用ReLU激活函数
x = Activation('relu')(x)
# 再次应用深度可分离卷积,增加特征的复杂度
x = SeparableConv2D(32, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x)
x = BatchNormalization()(x)
# 使用最大池化层进行下采样,减少特征图的空间尺寸
x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)
# 将下采样的输出与残差连接相加,这是残差学习的基本操作,有助于训练深层网络
x = layers.add([x, residual])
 
# 模块3(module 3)
# 创建另一个残差连接,通过1x1卷积进行下采样,将特征图的通道数进一步减半
residual = Conv2D(64, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
# 对残差连接的输出进行批量归一化
residual = BatchNormalization()(residual)
# 使用SeparableConv2D进行深度可分离卷积
x = SeparableConv2D(64, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x)
# 对深度可分离卷积的输出进行批量归一化
x = BatchNormalization()(x)
# 应用ReLU激活函数
x = Activation('relu')(x)
# 再次应用深度可分离卷积
x = SeparableConv2D(64, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x)
x = BatchNormalization()(x)
# 使用最大池化层进行下采样
x = MaxPooling2D((3, 3), strides=(2, 2), padding='same)(x)
  # 将下采样的输出与残差连接相加
  x = layers.add([x, residual])
 # 模块4(module 4)
 # 创建另一个残差连接,通过1x1卷积进行下采样,将特征图的通道数进一步减半
 residual = Conv2D(128, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
 # 对残差连接的输出进行批量归一化
 residual = BatchNormalization()(residual)
 # 使用SeparableConv2D进行深度可分离卷积
 x = SeparableConv2D(128, (3, 3), padding='same', kernel_regularizer=regularization, 
 use_bias=False)(x)
 # 对深度可分离卷积的输出进行批量归一化
 x = BatchNormalization()(x)
 # 应用ReLU激活函数
 x = Activation('relu')(x)
 # 再次应用深度可分离卷积
 x = SeparableConv2D(128, (3, 3), padding='same', kernel_regularizer=regularization, 
 use_bias=False)(x)
 x = BatchNormalization()(x)
 # 使用最大池化层进行下采样
 x = MaxPooling2D((3, 3), strides=(2, 2), padding='same)(x)
 # 将下采样的输出与残差连接相加
 x = layers.add([x, residual])
 
 # 最后层
 # 使用1x1的卷积层将特征图转换为类别分数,这里没有应用正则化
 x = Conv2D(num_classes, (3, 3), padding='same')(x)
 # 全局平均池化层,将空间维度压缩为1x1
 x = GlobalAveragePooling2D()(x)
 # softmax激活函数,输出类别概率分布
 output = Activation('softmax', name='predictions')(x)
 # 创建并返回模型实例
 model = Model(img_input, output)
 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模型,采用经预处理的Fer2013表情数据集进行模型训练。随机抽取测试集的20%作为验证集,剩余部分作为训练样本,且训练集与验证集的样本数据无交叉。其训练参数设置如表1所示。

表1 训练参数设置

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

表2 数据增强参数设置 

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

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

 代码中设置了训练时的结果输出,在训练结束后会将训练的模型保存为hdf5文件到指定文件夹下,训练过程结果输出如图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设计了表情识别系统界面。该系统界面如图15所示,其大致功能如下:

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

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

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

图15 表情识别系统界面 

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

图16 表情识别系统图片测试 

在开启实时视频场景下,其检测结果如图17所示,可以看出系统在保持准确率的同时每帧用时为0.02s左右,使得表情识别在低配置硬件上的实时检测成为现实。

图17 实时视频中的表情识别 

        更多的实验可以看出,模型提取到了能被理解的人脸表情特征信息,这些信息帮助对捕获的人脸的情绪进行预测,表明该表情识别系统具有良好的识别效果。然而,Angry和Disgust两类表情具有相似的眉毛特征和皱起的嘴角,易产生错误分类。戴眼镜的人常被错误地分类为Angry或Scare, 因为深色的眼镜框常与这两种表情特征下的皱眉混淆;另外,由于眉毛上扬角度相似,Happy和Surprise也常被混淆。这也表明,人类的表情非常复杂,表情识别是一项复杂且模糊的研究,其模型尚需更多的完善。

  • 35
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
首先需要了解得物网站的数据结构和爬取方式,得物网站比较复杂,需要使用Selenium+BeautifulSoup进行爬取。 以下是一个简单的得物爬虫Python代码实现(注:仅供学习参考,请勿用于商业用途): ```python import time from selenium import webdriver from selenium.webdriver.chrome.options import Options from bs4 import BeautifulSoup options = Options() options.add_argument('--no-sandbox') # 解决DevToolsActivePort文件不存在报错的问题 options.add_argument('window-size=1920x3000') # 指定浏览器分辨率 options.add_argument('--disable-gpu') # 谷歌文档提到需要加上这个属性来规避bug options.add_argument('--hide-scrollbars') # 隐藏滚动条, 应对一些特殊页面 options.add_argument('blink-settings=imagesEnabled=false') # 不加载图片, 提升速度 options.add_argument('--headless') # 无界面 driver = webdriver.Chrome(options=options) url = 'https://www.dewu.com/' driver.get(url) # 等待页面加载完成 time.sleep(3) # 模拟鼠标点击,展开商品列表 driver.find_element_by_xpath('//div[text()="全部商品"]').click() # 等待页面加载完成 time.sleep(3) # 获取页面源代码 html = driver.page_source # 解析页面 soup = BeautifulSoup(html, 'html.parser') # 获取商品列表 items = soup.find_all('div', {'class': 'item-card'}) for item in items: # 获取商品标题 title = item.find('div', {'class': 'title'}).text.strip() # 获取商品价格 price = item.find('div', {'class': 'price'}).text.strip() # 获取商品链接 link = item.find('a', {'class': 'item-link'})['href'] print(title, price, link) # 关闭浏览器 driver.quit() ``` 这里的代码仅仅是一个简单的爬虫示例,如果想要更加深入地了解得物网站的数据结构和爬取方式,需要结合具体的需求进行更加详细的分析和实现。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值