人脸表情识别 | Python+Keras+PyQt5

参考学习文章:
Keras|基于深度学习的人脸表情识别系统
PyQt5+QtDesigner编写摄像头界面程序(一)——pyqt5、qtdesigner安装和环境设置
本次设计参考以上两篇文章,非常感谢博主们的分享,我收获良多!

目录

  • 人脸表情识别 | Python+Keras+PyQt5
    • 一、前言
      • (一)本设计简介
      • (二)语言选择
      • (三)环境选择
        • 1.TensorFlow简介
        • 2.Keras简介
      • (三)本设计相关知识学习
      • (四)本设计环境搭建步骤
    • 二、本设计成果展示
      • (一)无PyQt5界面:
      • (二)与PyQt5界面结合:
    • 三、本设计主要代码结构讲解
      • (一)人脸表情识别和情绪分类部分
        • 1.卷积神经网络模型的训练
        • 1.1数据集的获取
          • (1)数据集下载
          • (2)数据集格式转换
        • 1.2搭建卷积神经网络模型
        • 1.3训练模型
        • 1.4保存训练模型
        • 2.面部表情的识别
        • 2.1加载pre-model网络与权重;
        • 2.2利用opencv对图像预处理;
          • 1.打开系统摄像头
          • 2.人脸识别
          • 3.灰度处理、裁切、翻转、几何归一化等处理
        • 2.3人脸表情识别
        • 2.4表情分类器检测
      • (二)PyQt5界面部分
        • 1.PyQt+QtDesigner等工具的安装与设置;
        • 2.基于QtDesigner的界面设计;
        • 3.各部分程序的编写;
        • 4.笔记本摄像头的读取、显示和参数控制;
    • 四、主代码展示

一、前言

(一)本设计简介

本设计是基于Python的人脸表情识别和情绪分类,在TensorFlow框架下,使用其内部高级API——Keras搭建训练模型,并利用OpenCV库中的相关函数共同实现人脸识别、人脸表情识别、情绪分类的目的,最后借助PyQt5增加界面,通过界面可对输入的画面进行调整颜色、调整曝光度、亮度等操作,还可以通过“开始”、“暂停”、“结束”功能控制识别过程的通断,通过“录像”功能保存所需的画面,从而使整个设计更友好、更加人性化。

(二)语言选择

本设计选用相对简单易上手的Python语言,其具体的介绍可查看Python百度百科,此处不做过多陈述。

(三)环境选择

1.TensorFlow简介

具体内容请查看TensorFlow官网。TensorFlow是Google开源的基于数据流图的机器学习框架,支持python和c++程序开发语言。TensorFlow支持卷积神经网络(CNN)和循环卷积网络(RNN),以及RNN的一个特例长短期记忆网络(LSTM),以上都是目前在计算机视觉、语音识别、自然语言处理方面最流行的深度神经网络模型。

在TensorFlow官网中介绍了TensorFlow的以下六大优势:
●高度灵活性
●真正的可移植性
●将科研和产品结合在一起
●自动求微分
●多语言支持
●最优化性能
因为本设计仅使用TensorFlow框架作为程序运行环境,主要是使用其高级API——Keras,因此不过多介绍。

2.Keras简介

具体内容请查看Keras官网。Keras是一个高级的Python神经网络框架。Keras已经被添加到TensorFlow中,成为其默认的框架,作为TensorFlow高级API之一。Keras作为TensorFlow的高层封装,可以与TensorFlow联合使用,用它快速搭建原型。
Keras是高度封装的,非常适合新手使用,代码更新速度较快,有大量公开示例代码,文档和讨论区也比较完善。
在Keras官网描述了其以下几个有点:
●模块化:模型的各部分,如神经层、成本函数、优化器、初始化、激活函数、规范化都是独立的模块,可以组合在一起来创建模型。
●极简主义:每个模块都保持简短和简单。
●易扩展性:很容易添加新模块,因此Keras更适合做进一步的高级研究。
●使用Python语言:模型使用Python实现,非常易于调试和扩展。

(三)本设计相关知识学习

Python学习笔记(一)
Python+OpenCV(一)——基础操作
Python+Tensorflow学习(二)——初试keras

(四)本设计环境搭建步骤

Win10+Python3.6.5+Anaconda3-5.2.0+Tensorflow安装

二、本设计成果展示

(一)无PyQt5界面:

(二)与PyQt5界面结合:

三、本设计主要代码结构讲解

本设计主要代码结构整体上分为两大部分,在各部分再细分以下几点:
代码主要结构主要分为两大部分:
一、人脸表情识别和情绪分类部分
(一)卷积神经网络模型的训练
1数据集的获取
2.加载pre-model网络与权重;
3.训练模型
4.保存训练模型
(二)面部表情识别
1.打开摄像头
2.人脸识别
3.图像预处理
4.人脸表情识别
5.情绪分类
二、PyQt5界面创建
1.PyQt+QtDesigner及opencv等工具的安装与设置;
2.基于QtDesigner的界面设计;
3.各部分程序的编写;
4.笔记本摄像头的读取、显示和参数控制;
以下逐点介绍。

(一)人脸表情识别和情绪分类部分

在人脸表情识别和情绪分类部分分为过程:卷积神经网络模型的训练与面部表情的识别。

1.卷积神经网络模型的训练

1.1数据集的获取

(1)数据集下载

为了节约素材收集时间,同时也为更公平的评价模型以及人脸表情识别分类器的性能,我们采用使用公开的数据集。
本次设计使用了kaggle面部表情识别竞赛所使用的fer2013人脸表情数据库,图片统一以csv的格式存储,利用python可将csv文件转为单通道灰度图片,并根据标签将其分类在不同的文件夹中。

(2)数据集格式转换

首先根据用途label分成三个csv(分别是训练集(train)、测试集(test)、验证集(val));

# -*- coding = utf-8 -*-
# @Time : 2021/8/7 09:12
# @Author : 西兰花
# @File : convert_fer2013.py
# @Software : PyCharm"""
根据用途label分成三个csv(分别是训练集(train)、测试集(test)、验证集(val));
"""import csvdatabase_path = 'F:/test05/表情识别/表情识别/emotion_classifier-master/fer2013/'
datasets_path = './fer2013/'
csv_file = database_path+'fer2013.csv'
train_csv = datasets_path+'train.csv'
val_csv = datasets_path+'val.csv'
test_csv = datasets_path+'test.csv'with open(csv_file) as f:csvr = csv.reader(f)header = next(csvr)print(header)rows = [row for row in csvr]trn = [row[:-1] for row in rows if row[-1] == 'Training']csv.writer(open(train_csv, 'w+'), lineterminator='\n').writerows([header[:-1]] + trn)print(len(trn))val = [row[:-1] for row in rows if row[-1] == 'PublicTest']csv.writer(open(val_csv, 'w+'), lineterminator='\n').writerows([header[:-1]] + val)print(len(val))        tst = [row[:-1] for row in rows if row[-1] == 'PrivateTest']csv.writer(open(test_csv, 'w+'), lineterminator='\n').writerows([header[:-1]] + tst)print(len(tst))

文件夹“test”存放测试集数据;
文件夹“train”存放训练集数据;
文件夹“valt”存放验证集数据;

各文件夹中将图片分为七种,并存放在相应标签(label)中,标签“0”至“7”分别对应情绪“angry”、 “disgust”、“fear”、“happy”、“sad”、“surprise”、“neutral”。

将图像转换为单通道灰度图:

# -*- coding = utf-8 -*-
# @Time : 2021/8/7 09:18
# @Author : 西兰花
# @File : convert_csv2gray.py
# @Software : PyCharm"""
将图像转换为单通道灰度图
"""
import csv
import os
from PIL import Image
import numpy as npdatasets_path = r'.\fer2013'
train_csv = os.path.join(datasets_path, 'train.csv')
val_csv = os.path.join(datasets_path, 'val.csv')
test_csv = os.path.join(datasets_path, 'test.csv')train_set = os.path.join(datasets_path, 'train')
val_set = os.path.join(datasets_path, 'val')
test_set = os.path.join(datasets_path, 'test')for save_path, csv_file in [(train_set, train_csv), (val_set, val_csv), (test_set, test_csv)]:if not os.path.exists(save_path):os.makedirs(save_path)num = 1with open(csv_file) as f:csvr = csv.reader(f)header = next(csvr)for i, (label, pixel) in enumerate(csvr):pixel = np.asarray([float(p) for p in pixel.split()]).reshape(48, 48)subfolder = os.path.join(save_path, label)if not os.path.exists(subfolder):os.makedirs(subfolder)im = Image.fromarray(pixel).convert('L')image_name = os.path.join(subfolder, '{:05d}.jpg'.format(i))# print(image_name)im.save(image_name)

单通道灰度图:

1.2搭建卷积神经网络模型

数据集已成功获取,并按照label进行分类,第二步是建立卷积神经网络模型(CNN),本步骤是实现人脸表情识别关键一步。

在前人的基础上,本设计在输入层后加入了1*1的卷积层,使输入增加了非线性的表示、加深了网络、提升了模型的表达能力,同时基本不增加计算量。
模型代码如下:

 def build_model(self):self.model = Sequential()   # Sequential模型是keras两种模型之一,另一种是model模型"""构建模型"""# 第一层卷积,需要指定input_shape的参数self.model.add(Conv2D(32, (1, 1), strides=1, padding='same', input_shape=(img_size, img_size, 1)))self.model.add(Activation('relu'))  # 激活函数self.model.add(Conv2D(32, (5, 5), padding='same'))self.model.add(Activation('relu'))self.model.add(MaxPooling2D(pool_size=(2, 2)))  # 最大池化self.model.add(Conv2D(32, (3, 3), padding='same'))self.model.add(Activation('relu'))self.model.add(MaxPooling2D(pool_size=(2, 2)))self.model.add(Conv2D(64, (5, 5), padding='same'))self.model.add(Activation('relu'))self.model.add(MaxPooling2D(pool_size=(2, 2)))self.model.add(Flatten())self.model.add(Dense(2048))     # 全连接层self.model.add(Activation('relu'))self.model.add(Dropout(0.5))self.model.add(Dense(1024))self.model.add(Activation('relu'))self.model.add(Dropout(0.5))self.model.add(Dense(num_classes))self.model.add(Activation('softmax'))self.model.summary()    # 显示训练模型结构

通过 self.model.summary() 函数查看训练模型结构;训练模型结构如下:

模型:Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
conv2d_1 (Conv2D)            (None, 48, 48, 32)        64
_________________________________________________________________
activation_1 (Activation)    (None, 48, 48, 32)        0
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 48, 48, 32)        25632
_________________________________________________________________
activation_2 (Activation)    (None, 48, 48, 32)        0
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 24, 24, 32)        0
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 24, 24, 32)        9248
_________________________________________________________________
activation_3 (Activation)    (None, 24, 24, 32)        0
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 12, 12, 32)        0
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 12, 12, 64)        51264
_________________________________________________________________
activation_4 (Activation)    (None, 12, 12, 64)        0
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 6, 6, 64)          0
_________________________________________________________________
flatten_1 (Flatten)          (None, 2304)              0
_________________________________________________________________
dense_1 (Dense)              (None, 2048)              4720640
_________________________________________________________________
activation_5 (Activation)    (None, 2048)              0
_________________________________________________________________
dropout_1 (Dropout)          (None, 2048)              0
_________________________________________________________________
dense_2 (Dense)              (None, 1024)              2098176
_________________________________________________________________
activation_6 (Activation)    (None, 1024)              0
_________________________________________________________________
dropout_2 (Dropout)          (None, 1024)              0
_________________________________________________________________
dense_3 (Dense)              (None, 7)                 7175
_________________________________________________________________
activation_7 (Activation)    (None, 7)                 0
=================================================================
Total params: 6,912,199
Trainable params: 6,912,199
Non-trainable params: 0

1.3训练模型

在训练过程中使用ImageDataGenerator()函数实现数据增强,并通过flow_from_directory()函数根据文件名划分label;优化算法选择SGD,损失函数选择categorical_crossentropy;

    def train_model(self):sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)# 指定损失函数和优化器self.model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])# 自动扩充训练样本train_datagen = ImageDataGenerator(rescale=1./255,shear_range=0.2,zoom_range=0.2,horizontal_flip=True)# 归一化验证集val_datagen = ImageDataGenerator(rescale=1./255)eval_datagen = ImageDataGenerator(rescale=1./255)# 以文件分类名划分labeltrain_generator = train_datagen.flow_from_directory(root_path+'/train',target_size=(img_size, img_size),color_mode='grayscale',batch_size=batch_siz,class_mode='categorical')val_generator = val_datagen.flow_from_directory(root_path+'/val',target_size=(img_size,img_size),color_mode='grayscale',batch_size=batch_siz,class_mode='categorical')eval_generator = eval_datagen.flow_from_directory(root_path+'/test',target_size=(img_size,img_size),color_mode='grayscale',batch_size=batch_siz,class_mode='categorical')# early_stopping = EarlyStopping(monitor='loss',patience=3)# 用model.fit()函数来训练模型,输入训练集和测试数据history_fit = self.model.fit_generator(train_generator,steps_per_epoch=800/(batch_siz/32),     # 28709nb_epoch=nb_epoch,validation_data=val_generator,validation_steps=2000,# callbacks=[early_stopping])# history_eval=self.model.evaluate_generator(eval_generator, steps=2000)    # 用model.evaluate_generator()函数来评估模型history_predict=self.model.predict_generator(eval_generator, steps=2000)    # 训练模型预测

1.4保存训练模型

    def save_model(self):   # 存储训练模型数据# 使用model.to_json()函数只保存模型的结构,而不包含其权重及训练的配置(损失函数、优化器)model_json = self.model.to_json()with open(root_path+"/model_json.json", "w") as json_file:json_file.write(model_json)self.model.save_weights(root_path+'/model_weight.h5')self.model.save(root_path+'/model.h5')print('model saved')

到此,人脸表情识别训练模型已构建完毕。

2.面部表情的识别

2.1加载pre-model网络与权重;

keras模型分为model和weight两部分
保存model方法:通过json文件或yaml文件
json文件:
model_json = model.to_json()
with open(“model.json”, “w”) as json_file:
json_file.write(model_json)
yaml文件:
yaml_string = model.to_yaml()
保存权重的方法:通过保存权重(系数)
HDF5文件:
model.save_weights(“model.h5”)
print(“Saved model to disk”)

载入model的方法
json & hdf5:
#load json and create model
json_file = open(‘model.json’, ‘r’)
loaded_model_json = json_file.read()
json_file.close()
loaded_model = model_from_json(loaded_model_json)
from keras.models import load_model
model = load_model(‘model.h5’)
载入权重:
#load weights into new model
loaded_model.load_weights(“model.h5”)
print(“Loaded model from disk”)

emo_labels = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral']
num_class = len(emo_labels)
# 使用json文件打开keras中model部分
json_file = open(model_path+'model_json.json')
loaded_model_json = json_file.read()
json_file.close()
model = model_from_json(loaded_model_json)
# keras.models.load_model()读取网络、权重
# keras.models.load_weights()仅读取权重
# 打开hdf5文件,即权重存放的文件
model.load_weights(model_path+'model_weight.h5')

2.2利用opencv对图像预处理;

在Python中提供强大的视觉处理库——OpenCV,我们可以里OpenCV库中提供的函数实现人脸识别,进而对识别到的人脸进行灰度处理、裁切、翻转、几何归一化等处理,并通过双线内插值算法(cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]]))将图像统一重塑为48*48像素。

1.打开系统摄像头

通过 cv2.VideoCapture()函数调用系统摄像头。值为0表示调取系统摄像头,值为路径+文件名(仅限视频/图片)表示打开视频/图片文件;

# 捕获指定摄像头的实时视频流cap = cv2.VideoCapture(0)
2.人脸识别

使用haarcascade_frontalface_alt.xml级联器进行人脸识别,或者使用lbpcascade_frontalcatface.xml级联器;之前笔者分别使用这两个级联器进行人脸识别,两者识别率不相上下,也可能是跟环境有关,因此笔者认为二者都适用,具体测试可查看Python+OpenCV(十七)——人脸识别。

 # 人脸识别分类器本地存储路径cascade_path = root_path+"haarcascade_frontalface_alt.xml"    # 哈尔级联器
3.灰度处理、裁切、翻转、几何归一化等处理
# 图像灰化,降低计算复杂度frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)# 使用人脸识别分类器,读入分类器cascade = cv2.CascadeClassifier(cascade_path)                # 利用分类器识别出哪个区域为人脸faceRects = cascade.detectMultiScale(frame_gray, scaleFactor=1.1, minNeighbors=1, minSize=(120, 120))if len(faceRects) > 0:                 for faceRect in faceRects: x, y, w, h = faceRectimages = []rs_sum = np.array([0.0]*num_class)# 截取脸部图像提交给模型识别表情image = frame_gray[y: y + h, x: x + w]  # 灰度处理# cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])# src:[必需]原图像# dsize:[必需]输出图像所需大小# fx:[必需]沿水平轴的比例因子# fy:[必需]沿垂直轴的比例因子# interpolation:[必需]插值方式image = cv2.resize(image, (img_size, img_size))     # 将灰度处理后的图像按比例调整为像素大小48*48image = image*(1./255)images.append(image)    # 在末尾添加新的图片images.append(cv2.flip(image, 1))images.append(cv2.resize(image[2:45, :], (img_size, img_size)))

2.3人脸表情识别

使用之前训练好的模型进行预测,对多个处理过的脸部预测结果进行线性加权融合,最后得出预测结果;

def predict_emotion(face_img):face_img = face_img * (1. / 255)resized_img = cv2.resize(face_img, (img_size, img_size))  # ,interpolation=cv2.INTER_LINEARrsz_img = []rsh_img = []results = []# print (len(resized_img[0]),type(resized_img))rsz_img.append(resized_img[:, :])  # resized_img[1:46,1:46]rsz_img.append(resized_img[2:45, :])rsz_img.append(cv2.flip(rsz_img[0], 1))# rsz_img.append(cv2.flip(rsz_img[1],1))'''rsz_img.append(resized_img[0:45,0:45])rsz_img.append(resized_img[2:47,0:45])rsz_img.append(resized_img[2:47,2:47])rsz_img.append(cv2.flip(rsz_img[2],1))rsz_img.append(cv2.flip(rsz_img[3],1))rsz_img.append(cv2.flip(rsz_img[4],1))'''i = 0for rsz_image in rsz_img:rsz_img[i] = cv2.resize(rsz_image, (img_size, img_size))# =========================# cv2.imshow('%d'%i,rsz_img[i])i += 1# why 4 parameters here, what's it means?for rsz_image in rsz_img:rsh_img.append(rsz_image.reshape(1, img_size, img_size, 1))i = 0for rsh_image in rsh_img:list_of_list = model.predict_proba(rsh_image, batch_size=32, verbose=1)  # predictresult = [prob for lst in list_of_list for prob in lst]results.append(result)return results

2.4表情分类器检测

predict_proba()函数:模型预测输入样本属于每种类别的概率,概率和为1,每个位置的概率分别对应classes_中对应位置的类别标签。predict_proba输出概率最大值索引位置对应的classes_元素就是样本所属的类别。

list_of_list = model.predict_proba(image, batch_size=32, verbose=1)     # predictresult = [prob for lst in list_of_list for prob in lst]rs_sum += np.array(result)print(rs_sum)label = np.argmax(rs_sum)emo = emo_labels[label]print('Emotion : ', emo)    # 输出情绪分类结果

(二)PyQt5界面部分

(具体操作请参考本文章开头的参考文章)

1.PyQt+QtDesigner等工具的安装与设置;

2.基于QtDesigner的界面设计;

3.各部分程序的编写;

4.笔记本摄像头的读取、显示和参数控制;

四、主代码展示

由于工程庞大,以下仅展示主要代码:
(代码中主要功能基本上附上了注释,如有疑惑部分可查看本文章开头列出的参考文章,或者评论本文章皆可)

# -*- coding = utf-8 -*-
# @Time : 2021/8/19 19:45
# @Author : 西兰花
# @File : QtOpenCV.py
# @Software : PyCharm"""
代码主要结构主要分为两大部分:
一、人脸表情识别和情绪分类部分
(一)卷积神经网络模型的训练
1数据集的获取
2.加载pre-model网络与权重;
3.训练模型
4.保存训练模型
(二)面部表情识别
1.打开摄像头
2.人脸识别
3.图像预处理
4.人脸表情识别
5.情绪分类
二、PyQt5界面创建
1.PyQt+QtDesigner及opencv等工具的安装与设置;
2.基于QtDesigner的界面设计;
3.各部分程序的编写;
4.笔记本摄像头的读取、显示和参数控制;
"""# PyQt界面部分
from OboardCamDisp import Ui_MainWindow
# import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog
from PyQt5.QtCore import QTimer, QCoreApplication
from PyQt5.QtGui import QPixmap
# import cv2
import qimage2ndarray
import time
# 人脸表情识别+情绪分类部分
import cv2
import sys
import numpy as np
from keras.models import model_from_json
root_path = './pic/'
model_path = root_path+'/model/'
img_size = 48   # 图像像素大小48*48
# load json and create model arch
"""
keras模型分为model和weight两部分
保存model方法:通过json文件或yaml文件
json文件:
model_json = model.to_json()
with open("model.json", "w") as json_file:json_file.write(model_json)
yaml文件:
yaml_string = model.to_yaml()
保存权重的方法:通过保存权重(系数)
HDF5文件:
model.save_weights("model.h5")
print("Saved model to disk")载入model的方法
json & hdf5:
# load json and create model
json_file = open('model.json', 'r')
loaded_model_json = json_file.read()
json_file.close()
loaded_model = model_from_json(loaded_model_json)
from keras.models import load_model
model = load_model('model.h5')
载入权重:
# load weights into new model
loaded_model.load_weights("model.h5")
print("Loaded model from disk")
"""
emo_labels = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral']
num_class = len(emo_labels)
# 使用json文件打开keras中model部分
json_file = open(model_path+'model_json.json')
loaded_model_json = json_file.read()
json_file.close()
model = model_from_json(loaded_model_json)
# keras.models.load_model()读取网络、权重
# keras.models.load_weights()仅读取权重
# 打开hdf5文件,即权重存放的文件
model.load_weights(model_path+'model_weight.h5')# PyQt5创建界面
class CamShow(QMainWindow, Ui_MainWindow):   # 定义一个类,实现程序的主要功能def __del__(self):try:self.camera.release()  # 释放资源except:returndef __init__(self, parent=None):    # 初始化函数super(CamShow, self).__init__(parent)self.setupUi(self)self.PrepSliders()      # PrepSliders()函数实现各个slider和对应的spinbox的关联,保证两个控件的值始终相等self.PrepWidgets()      # PrepWidgets()函数初始化各个控件self.PrepParameters()   # PrepParameters()函数定义并初始化程序运行过程中会用到的变量# CallBackFunctions()函数各个控件背后的功能函数的集合,定义了在程序界面上进行某项操作后实际执行的代码self.CallBackFunctions()"""Timer = QTimer()函数、Timer.timeout.connect(self.TimerOutFun)函数计时器的定义和调用,Timer = QTimer()函数定义了一个定时器,等我们执行计时器开始的代码后,该计时器就开始计时,每次计时结束都会调用一次函数TimerOutFun,通过计时器实现对摄像头图像的循环读取和显示"""self.Timer = QTimer()self.Timer.timeout.connect(self.TimerOutFun)# Slider和SpinBoxdef PrepSliders(self):self.RedColorSld.valueChanged.connect(self.RedColorSpB.setValue)self.RedColorSpB.valueChanged.connect(self.RedColorSld.setValue)self.GreenColorSld.valueChanged.connect(self.GreenColorSpB.setValue)self.GreenColorSpB.valueChanged.connect(self.GreenColorSld.setValue)self.BlueColorSld.valueChanged.connect(self.BlueColorSpB.setValue)self.BlueColorSpB.valueChanged.connect(self.BlueColorSld.setValue)self.ExpTimeSld.valueChanged.connect(self.ExpTimeSpB.setValue)self.ExpTimeSpB.valueChanged.connect(self.ExpTimeSld.setValue)self.GainSld.valueChanged.connect(self.GainSpB.setValue)self.GainSpB.valueChanged.connect(self.GainSld.setValue)self.BrightSld.valueChanged.connect(self.BrightSpB.setValue)self.BrightSpB.valueChanged.connect(self.BrightSld.setValue)self.ContrastSld.valueChanged.connect(self.ContrastSpB.setValue)self.ContrastSpB.valueChanged.connect(self.ContrastSld.setValue)# 控件初始化def PrepWidgets(self):self.PrepCamera()self.StopBt.setEnabled(False)self.RecordBt.setEnabled(False)self.GrayImgCkB.setEnabled(False)self.RedColorSld.setEnabled(False)self.RedColorSpB.setEnabled(False)self.GreenColorSld.setEnabled(False)self.GreenColorSpB.setEnabled(False)self.BlueColorSld.setEnabled(False)self.BlueColorSpB.setEnabled(False)self.ExpTimeSld.setEnabled(False)self.ExpTimeSpB.setEnabled(False)self.GainSld.setEnabled(False)self.GainSpB.setEnabled(False)self.BrightSld.setEnabled(False)self.BrightSpB.setEnabled(False)self.ContrastSld.setEnabled(False)self.ContrastSpB.setEnabled(False)# 初始化摄像头def PrepCamera(self):try:# camera=cv2.VideoCapture(0)函数,调用OpenCV的VideoCapture函数打开摄像头# 并使用变量self.camera代表该摄像头,参数0意味着打开笔记本自带的摄像头self.camera = cv2.VideoCapture(0)print("摄像头已打开!")self.MsgTE.clear()  # 清空文本框MsgTE中的内容# 在文本框MsgTE中显示'Oboard camera connected.'# append()函数表示在现有的内容后继续添加内容# setPlainText函数,用括号中的文本覆盖原来的文本self.MsgTE.append('Oboard camera connected.')self.MsgTE.setPlainText()except Exception as e:self.MsgTE.clear()self.MsgTE.append(str(e))# 参数初始化def PrepParameters(self):# 变量self.RecordFlag,该值为0时不保存视频,为1时开始保存视频self.RecordFlag = 0# 变量self.RecordPath定义默认的文件存储路径self.RecordPath = 'F:/test05/表情识别/表情识别/emotion_classifier-master/Qt/'# self.FilePathLE.setText(self.RecordPath)将路径名显示在文本框FilePathLE中self.FilePathLE.setText(self.RecordPath)# self.Image_num定义读取图片的次数self.Image_num = 0# self.R、self.G、self.B为三个颜色通道的强度增益系数self.R = 1self.G = 1self.B = 1# 初始化摄像头参数控件的值,即读取摄像头的曝光、增益、亮度、对比度等参数,并将这些值显示在相应的控件上self.ExpTimeSld.setValue(self.camera.get(15))self.SetExposure()self.GainSld.setValue(self.camera.get(14))self.SetGain()self.BrightSld.setValue(self.camera.get(10))self.SetBrightness()self.ContrastSld.setValue(self.camera.get(11))self.SetContrast()self.MsgTE.clear()# 控件回调函数def CallBackFunctions(self):self.FilePathBt.clicked.connect(self.SetFilePath)self.ShowBt.clicked.connect(self.StartCamera)self.StopBt.clicked.connect(self.StopCamera)self.RecordBt.clicked.connect(self.RecordCamera)self.ExitBt.clicked.connect(self.ExitApp)self.GrayImgCkB.stateChanged.connect(self.SetGray)self.ExpTimeSld.valueChanged.connect(self.SetExposure)self.GainSld.valueChanged.connect(self.SetGain)self.BrightSld.valueChanged.connect(self.SetBrightness)self.ContrastSld.valueChanged.connect(self.SetContrast)self.RedColorSld.valueChanged.connect(self.SetR)self.GreenColorSld.valueChanged.connect(self.SetG)self.BlueColorSld.valueChanged.connect(self.SetB)# 实现灰度转换# 通道Rdef SetR(self):R = self.RedColorSld.value()self.R = R/255# 通道Gdef SetG(self):G = self.GreenColorSld.value()self.G = G/255# 通道Bdef SetB(self):B = self.BlueColorSld.value()self.B = B/255def SetContrast(self):contrast_toset=self.ContrastSld.value()try:self.camera.set(11,contrast_toset)self.MsgTE.setPlainText('The contrast is set to ' + str(self.camera.get(11)))except Exception as e:self.MsgTE.setPlainText(str(e))def SetBrightness(self):brightness_toset=self.BrightSld.value()try:self.camera.set(10,brightness_toset)self.MsgTE.setPlainText('The brightness is set to ' + str(self.camera.get(10)))except Exception as e:self.MsgTE.setPlainText(str(e))def SetGain(self):gain_toset=self.GainSld.value()try:self.camera.set(14,gain_toset)self.MsgTE.setPlainText('The gain is set to '+str(self.camera.get(14)))except Exception as e:self.MsgTE.setPlainText(str(e))# 摄像头参数设置def SetExposure(self):try:exposure_time_toset = self.ExpTimeSld.value()self.camera.set(15,exposure_time_toset)self.MsgTE.setPlainText('The exposure time is set to '+str(self.camera.get(15)))except Exception as e:self.MsgTE.setPlainText(str(e))# 图像显示的颜色控制def SetGray(self):if self.GrayImgCkB.isChecked():self.RedColorSld.setEnabled(False)self.RedColorSpB.setEnabled(False)self.GreenColorSld.setEnabled(False)self.GreenColorSpB.setEnabled(False)self.BlueColorSld.setEnabled(False)self.BlueColorSpB.setEnabled(False)else:self.RedColorSld.setEnabled(True)self.RedColorSpB.setEnabled(True)self.GreenColorSld.setEnabled(True)self.GreenColorSpB.setEnabled(True)self.BlueColorSld.setEnabled(True)self.BlueColorSpB.setEnabled(True)# 摄像头的读取和显示# 按键“开始”def StartCamera(self):self.ShowBt.setEnabled(False)self.StopBt.setEnabled(True)self.RecordBt.setEnabled(True)self.GrayImgCkB.setEnabled(True)if self.GrayImgCkB.isChecked() == 0:self.RedColorSld.setEnabled(True)self.RedColorSpB.setEnabled(True)self.GreenColorSld.setEnabled(True)self.GreenColorSpB.setEnabled(True)self.BlueColorSld.setEnabled(True)self.BlueColorSpB.setEnabled(True)self.ExpTimeSld.setEnabled(True)self.ExpTimeSpB.setEnabled(True)self.GainSld.setEnabled(True)self.GainSpB.setEnabled(True)self.BrightSld.setEnabled(True)self.BrightSpB.setEnabled(True)self.ContrastSld.setEnabled(True)self.ContrastSpB.setEnabled(True)self.RecordBt.setText('录像')self.Timer.start(1)  # self.Timer.start(1)用来启动计时器,计时周期为1ms,即每隔1ms程序会自动调用一次TimerOutFunself.timelb = time.clock()# 保存图片或视频def SetFilePath(self):dirname = QFileDialog.getExistingDirectory(self, "浏览", '.')if dirname:self.FilePathLE.setText(dirname)self.RecordPath = dirname+'/'# 人脸表情识别+情绪分类主要部分def TimerOutFun(self):success, frame = self.camera.read()if success:self.Image = self.ColorAdjust(frame)    # 调用图像色彩调节函数self.DispImg()      # 调用函数self.Image_num += 1if self.RecordFlag:self.video_writer.write(frame)if self.Image_num % 10 == 9:    # 计算帧频frame_rate = 10/(time.clock()-self.timelb)self.FmRateLCD.display(frame_rate)self.timelb = time.clock()self.ImgWidthLCD.display(self.camera.get(3))self.ImgHeightLCD.display(self.camera.get(4))if len(sys.argv) != 1:print("Usage:%s camera_id\r\n" % (sys.argv[0]))sys.exit(0)# 人脸识别分类器本地存储路径cascade_path = root_path + "haarcascade_frontalface_alt.xml"  # 哈尔级联器# 图像灰化,降低计算复杂度frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)# 使用人脸识别分类器,读入分类器cascade = cv2.CascadeClassifier(cascade_path)# 利用分类器识别出哪个区域为人脸faceRects = cascade.detectMultiScale(frame_gray, scaleFactor=1.1, minNeighbors=1, minSize=(120, 120))if len(faceRects) > 0:for faceRect in faceRects:x, y, w, h = faceRectimages = []rs_sum = np.array([0.0] * num_class)# 截取脸部图像提交给模型识别表情image = frame_gray[y: y + h, x: x + w]  # 灰度处理# cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])# src:[必需]原图像# dsize:[必需]输出图像所需大小# fx:[必需]沿水平轴的比例因子# fy:[必需]沿垂直轴的比例因子# interpolation:[必需]插值方式image = cv2.resize(image, (img_size, img_size))  # 将灰度处理后的图像按比例调整为像素大小48*48image = image * (1. / 255)images.append(image)  # 在末尾添加新的图片images.append(cv2.flip(image, 1))images.append(cv2.resize(image[2:45, :], (img_size, img_size)))for img in images:image = img.reshape(1, img_size, img_size, 1)"""predict_proba()函数:模型预测输入样本属于每种类别的概率,概率和为1,每个位置的概率分别对应classes_中对应位置的类别标签。predict_proba输出概率最大值索引位置对应的classes_元素就是样本所属的类别。"""list_of_list = model.predict_proba(image, batch_size=32, verbose=1)  # predictresult = [prob for lst in list_of_list for prob in lst]rs_sum += np.array(result)print(rs_sum)label = np.argmax(rs_sum)emo = emo_labels[label]print('Emotion : ', emo)  # 输出情绪分类结果# cv2.putText(frame, "Emotion: %s" % emo, (400, 400), cv2.FONT_HERSHEY_COMPLEX, 1, (255, 255, 0), 3)# rectangle()框选识别到的人脸# cv2.rectangle(frame, (x - 10, y - 10), (x + w + 10, y + h + 10), color, thickness=2)# font = cv2.FONT_HERSHEY_SIMPLEX# 文字显示该表情分类结果# cv2.putText(frame, '%s' % emo, (x + 30, y + 30), font, 1, (255, 0, 255), 4)else:self.MsgTE.clear()self.MsgTE.setPlainText('Image obtaining failed.')def ColorAdjust(self, img):try:B = img[:, :, 0]G = img[:, :, 1]R = img[:, :, 2]B = B*self.BG = G*self.GR = R*self.Rimg1 = imgimg1[:, :, 0] = Bimg1[:, :, 1] = Gimg1[:, :, 2] = Rreturn img1except Exception as e:self.MsgTE.setPlainText(str(e))# 检测人脸、色彩空间及格式转换def DispImg(self):if self.GrayImgCkB.isChecked():img = cv2.cvtColor(self.Image, cv2.COLOR_BGR2GRAY)else:img = cv2.cvtColor(self.Image, cv2.COLOR_BGR2RGB)qimg = qimage2ndarray.array2qimage(img)self.DispLb.setPixmap(QPixmap(qimg))self.DispLb.show()# 按键“暂停”def StopCamera(self):if self.StopBt.text() == '暂停':self.StopBt.setText('继续')self.RecordBt.setText('保存')self.Timer.stop()elif self.StopBt.text() == '继续':self.StopBt.setText('暂停')self.RecordBt.setText('录像')self.Timer.start(1)# 按键“录像”def RecordCamera(self):tag = self.RecordBt.text()if tag == '保存':try:image_name = self.RecordPath+'image'+time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))+'.jpg'print(image_name)cv2.imwrite(image_name, self.Image)self.MsgTE.clear()self.MsgTE.setPlainText('Image saved.')except Exception as e:self.MsgTE.clear()self.MsgTE.setPlainText(str(e))elif tag == '录像':self.RecordBt.setText('停止')video_name = self.RecordPath + 'video' + time.strftime('%Y%m%d%H%M%S', time.localtime(time.time())) + '.avi'fps = self.FmRateLCD.value()size = (self.Image.shape[1],self.Image.shape[0])fourcc = cv2.VideoWriter_fourcc('M', 'J', 'P', 'G')self.video_writer = cv2.VideoWriter(video_name, fourcc, self.camera.get(5), size)self.RecordFlag=1self.MsgTE.setPlainText('Video recording...')self.StopBt.setEnabled(False)self.ExitBt.setEnabled(False)elif tag == '停止':self.RecordBt.setText('录像')self.video_writer.release()self.RecordFlag = 0self.MsgTE.setPlainText('Video saved.')self.StopBt.setEnabled(True)self.ExitBt.setEnabled(True)# 退出程序def ExitApp(self):self.Timer.Stop()self.camera.release()self.MsgTE.setPlainText('Exiting the application..')QCoreApplication.quit()if __name__ == '__main__':app = QApplication(sys.argv)ui = CamShow()ui.show()sys.exit(app.exec_())

人脸表情识别和情绪分类 | Python+TensorFlow(框架)+Keras+PyQt5相关推荐

  1. 【人脸表情识别】情绪识别相关会议、比赛汇总(2018-2020)

    前面专栏中,我们介绍了有关基于图片/视频的人脸表情识别的相关内容,也了解了通过回归的方式来理解表情的方式--基于连续模型的人脸表情识别.在专栏的最后一篇文章中,我们将分享计算机视觉领域中围绕情绪识别主 ...

  2. 人脸表情识别系统介绍——上篇(python实现,含UI界面及完整代码)

    人脸表情识别介绍与演示视频 博客及代码详细介绍:https://www.bilibili.com/video/BV18C4y1H7mH/(欢迎关注博主B站视频) 摘要:这篇博文介绍基于深度卷积神经网络 ...

  3. 毕业设计-人脸表情识别系统、人工智能

    人脸表情识别系统 1. 前言 在这个人工智能成为超级大热门的时代,人脸表情识别已成为其中的一项研究热点,而卷积神经网络.深度信念网络和多层感知器等相关算法在人脸面部表情识别领域的运用最为广泛.面部的表 ...

  4. 【完结】如何掌握基于图像和视频的人脸表情识别,这9篇文章可以作为一个参考...

    文/编辑 | 言有三 人脸表情识别(Facial Expression Recognition,FER)作为人脸识别技术中的一个重要组成部分,近年来在人机交互.安全.机器人制造.自动化.医疗.通信和驾 ...

  5. 【杂谈】从CV小白到人脸表情识别专栏作者,我与有三AI的故事

    各位有三AI的读者朋友大家好呀~我是刚刚更新完结的[人脸表情识别]专栏的作者,一名仍然在读的研究生.在分享完我的专栏内容后,分享一下我这枚CV小白与有三 AI 的故事. 认识有三AI 我本科的专业是软 ...

  6. 人脸表情识别系统介绍——离线环境配置篇

    摘要:本文详细介绍如何使用离线方法配置前面一篇博文<人脸表情识别系统介绍--上篇(python实现,含UI界面及完整代码)>项目中代码的Python环境,能够有效避免一些可能出现的依赖包安 ...

  7. python与tensorflow实现人脸表情识别(基于CNN)

    使用fer2013数据集,卷积神经网络实现人脸表情识别 python与CNN实现,有GUI界面,支持摄像头实时识别和手动选取图片识别,GUI界面选取图片进行识别实现效果如下图 摄像头实时读取并识别表情 ...

  8. Python基于OpenCV的人脸表情识别系统[源码&部署教程]

    1.项目背景 人脸表情识别是模式识别中一个非常重要却十分复杂的课题.首先对计算机人脸表情识别技术的研究背景及发展历程作了简单回顾.然后对近期人脸表情识别的方法进行了分类综述.通过对各种识别方法的分析与 ...

  9. Python人脸表情识别QT窗体

    .Python人脸表情识别QT窗体 如需安装运行环境或远程调试,可加扣905733049, 或扣2945218359由专业技术人员远程协助! 运行结下: 主要代码: # coding:utf-8 im ...

最新文章

  1. div.php织梦自定义表判断不能为空,织梦自定义表单字段为必填项的教程
  2. mybatis中的TypeHandler设计与实现
  3. material mem
  4. Hibernate检索策略之5.4一对多单向关联检索策略——Hibernate4究竟怎么玩
  5. 关于S/4HANA里Sales Office 和Sales Organization那些事儿
  6. Exchange EMC打开出错 解决
  7. LeetCode之最大正方形
  8. Java多线程Queue_Java多线程-BlockingQueue-ArrayBlockingQueue-LinkedBlockingQueue
  9. 密码学中的一些数学基础
  10. Android 自定义车牌键盘
  11. JAVA开发的人力资源管理系统
  12. 用Python实现随机森林回归
  13. axios post方式同时传递pram和json参数
  14. 计算机基础知识测试1,计算机基础知识测试试题及答案(网络)1
  15. sigmoid和softmax
  16. Leetcode 2261. K Divisible Elements Subarrays
  17. xcode和macos对应版本参考
  18. RESTORE 还原数据库
  19. YOLOv7使用云GPU训练自己的数据集
  20. DOTA-PEG-WSW/DOTA-PEG-NGR/DOTA-PEG-R8/DOTA-PEG-YIGSR 大环配体PEG化偶联多肽

热门文章

  1. Scrapy框架采集微信公众号数据,Python大佬机智操作绕过反爬验证码
  2. 功能强大,颜值在线的个人笔记应用 - Notion
  3. 企业如何开通商户版微信支付及收款码?
  4. 六Elasticsearch之中文分词器插件es-ik的热更新词库
  5. 计算机原理学习(2)-- 存储器和I/O设备和总线
  6. 程序猿和测试媛——组合在一起的原因
  7. 【DBC专题】-4-DBC文件中的Signal信号字节顺序Motorola和Intel介绍
  8. ORACLE ODBC驱动安装
  9. 女生突然不回微信,那你首先得明白不回微信的原因
  10. c语言法定节日日历程序,C 语言写的日历