1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 人脸表情识别和情绪分类 | Python+TensorFlow(框架)+Keras+PyQt5

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

时间:2019-02-20 15:45:03

相关推荐

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

人脸表情识别 | 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面部表情识别竞赛所使用的fer人脸表情数据库,图片统一以csv的格式存储,利用python可将csv文件转为单通道灰度图片,并根据标签将其分类在不同的文件夹中。

(2)数据集格式转换

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

# -*- coding = utf-8 -*-# @Time : /8/7 09:12# @Author : 西兰花# @File : convert_fer.py# @Software : PyCharm"""根据用途label分成三个csv(分别是训练集(train)、测试集(test)、验证集(val));"""import csvdatabase_path = 'F:/test05/表情识别/表情识别/emotion_classifier-master/fer/'datasets_path = './fer/'csv_file = database_path+'fer.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 : /8/7 09:18# @Author : 西兰花# @File : convert_csv2gray.py# @Software : PyCharm"""将图像转换为单通道灰度图"""import csvimport osfrom PIL import Imageimport numpy as npdatasets_path = r'.\fer'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,199Trainable params: 6,912,199Non-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)# 指定损失函数和优化器pile(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 : /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 sysfrom PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialogfrom PyQt5.QtCore import QTimer, QCoreApplicationfrom PyQt5.QtGui import QPixmap# import cv2import qimage2ndarrayimport time# 人脸表情识别+情绪分类部分import cv2import sysimport numpy as npfrom keras.models import model_from_jsonroot_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 modeljson_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_modelmodel = load_model('model.h5')载入权重:# load weights into new modelloaded_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_())

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。