这是个人脸表情识别的UI界面,麻烦给个详细的注释,最好是行注释,因为对这些库都不太熟悉
import operator
import os
import time
import cv2
from PySide2 import QtGui
from PySide2.QtWidgets import QFileDialog, QApplication
from PySide2.QtUiTools import QUiLoader
import numpy as np
import torch
import torch.nn as nn
from torchvision import models, transforms
from PIL import Image
def cvImgtoQtImg(cvImg, isConvertToGray=False):
if isConvertToGray:
QtImgBuf = cv2.cvtColor(cvImg, cv2.COLOR_BGR2GRAY)
QtImg = QtGui.QImage(QtImgBuf.data, QtImgBuf.shape[1], QtImgBuf.shape[0], QtGui.QImage.Format_Grayscale8)
else:
QtImgBuf = cv2.cvtColor(cvImg, cv2.COLOR_BGR2RGBA)
QtImg = QtGui.QImage(QtImgBuf.data, QtImgBuf.shape[1], QtImgBuf.shape[0], QtGui.QImage.Format_RGBA8888)
return QtImg
class Stats:
def __init__(self):
self.open = False
self.ui_face = QUiLoader().load('ui/demo.ui')
self.ui_face.setFixedSize(1239, 824)
self.ui_face.btn_open_cap.clicked.connect(self.opt_cap)
self.ui_face.btn_predict.clicked.connect(self.cap)
self.ui_face.btn_open_res.clicked.connect(self.load_pic)
self.model, self.model_ft = self.load_model()
def load_pic(self):
filePaths, _ = QFileDialog.getOpenFileName(
self.ui_face,
"请选择将要转换的文件",
os.path.join(os.path.expanduser('~'), "Desktop"),
"文件类型 (*.jpg)"
)
self.ui_face.edt_res.setText(filePaths)
self.img = cv2.imread(filePaths)
show = cv2.resize(self.img, (640, 480))
show = cv2.cvtColor(show, cv2.COLOR_BGR2RGB)
showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0], QtGui.QImage.Format_RGB888)
self.ui_face.ImgDisp.setPixmap(QtGui.QPixmap.fromImage(showImage))
def opt_cap(self):
if self.open == True:
self.open = False
self.ui_face.edt_cap.setText('摄像头已关闭')
else:
self.open = True
self.ui_face.edt_cap.setText('摄像头已打开')
self.start()
def start(self):
self.cap = cv2.VideoCapture(0)
self.cap.set(3, 640)
self.cap.set(4, 480)
self.cap.set(10, 100)
while True:
success, self.img = self.cap.read()
self.img = cv2.flip(self.img, 1)
show = cv2.resize(self.img, (640, 480))
show = cv2.cvtColor(show, cv2.COLOR_BGR2RGB)
showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0], QtGui.QImage.Format_RGB888)
self.ui_face.ImgDisp.setPixmap(QtGui.QPixmap.fromImage(showImage))
cv2.waitKey(0)
if self.open == False:
break
print('展示图片')
def cap(self):
try:
image = Image.fromarray(cv2.cvtColor(self.img, cv2.COLOR_BGR2RGB))
output = self.predict(image, self.model_ft)
ret = []
emo = ['surprized', 'happy', 'disgust', 'normal', 'fear', 'anger', 'sad']
for index, value in enumerate(self.model):
dis = np.linalg.norm(value - output) # 欧氏距离
ret.append({'category': emo[index], 'dis': dis})
ret = sorted(ret, key=operator.itemgetter('dis'), reverse=False)
print(ret)
self.ui_face.label_ret.setText('识别结果为:' + ret[0]['category'])
self.ui_face.label_ret_0.setText('0:' + ret[0]['category'])
self.ui_face.label_ret_1.setText('1:' + ret[1]['category'])
self.ui_face.label_ret_2.setText('2:' + ret[2]['category'])
self.ui_face.label_ret_3.setText('3:' + ret[3]['category'])
self.ui_face.label_ret_4.setText('4:' + ret[4]['category'])
self.ui_face.label_ret_5.setText('5:' + ret[5]['category'])
self.ui_face.label_ret_6.setText('6:' + ret[6]['category'])
except:
pass
def load_model(self):
# 这一块是对图片特征进行提取
model_path = 'model/weights.pth'
# build model
model_ft = models.resnet34(pretrained=False)
num_ftrs = model_ft.fc.in_features
model_ft.fc = nn.Sequential(
nn.Dropout(0.5),
nn.Linear(num_ftrs, 7),
nn.Softmax(dim=1)
)
model_ft.load_state_dict(torch.load(model_path))
model_ft.eval()
# 参数写到这里,得到的中心点遍历一下 然后写到这里
model = [
[2.0667151e-04, 3.4240412e-04, 1.4473200e-02, 8.0134422e-03, 6.0332119e-03,
7.7563822e-03, 9.6317458e-01],
[2.5990081e-04, 2.7968729e-04, 1.8215105e-02, 9.3163711e-01, 5.1174462e-03,
6.0818493e-03, 3.8408846e-02],
[0.00336622, 0.00619731, 0.10314032, 0.20358741, 0.27171963, 0.26114,
0.1508491],
[2.0508033e-04, 3.2301957e-04, 8.1134737e-03, 5.8690608e-03, 9.5963997e-01,
1.0704219e-02, 1.5145153e-02],
[4.1064431e-04, 1.2989613e-03, 8.9172471e-01, 2.3929298e-02, 1.7944381e-02,
2.8446108e-02, 3.6245927e-02],
[0.0014531, 0.00288311, 0.21803668, 0.1291624, 0.06903042, 0.04348047,
0.5359538],
[2.0752930e-04, 4.1509242e-04, 8.1426501e-03, 7.6724142e-03, 8.2466751e-03,
9.6485263e-01, 1.0462716e-02]
]
return model, model_ft
def predict(self, image, model):
time_s = time.time()
transform = transforms.Compose([
transforms.Resize(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])
img = transform(image)
img = torch.unsqueeze(img, 0)
output = model(img)[0].data.numpy()
time_e = time.time() - time_s
self.ui_face.label_time.setText('用时:' + ('%.3f' % time_e) + 's')
return output
if __name__ == '__main__':
app = QApplication([])
stats = Stats()
stats.ui_face.show()
app.exec_()
#import 要用到的库
import operator
import os
import time
import cv2
from PySide2 import QtGui
from PySide2.QtWidgets import QFileDialog, QApplication
from PySide2.QtUiTools import QUiLoader
import numpy as np
import torch
import torch.nn as nn
from torchvision import models, transforms
from PIL import Image
def cvImgtoQtImg(cvImg, isConvertToGray=False): #opencv图转成qt图
if isConvertToGray: #是否转成灰度图
QtImgBuf = cv2.cvtColor(cvImg, cv2.COLOR_BGR2GRAY) #转换颜色空间
QtImg = QtGui.QImage(QtImgBuf.data, QtImgBuf.shape[1], QtImgBuf.shape[0], QtGui.QImage.Format_Grayscale8) #返回QTimg格式
else:
QtImgBuf = cv2.cvtColor(cvImg, cv2.COLOR_BGR2RGBA) #转换颜色空间
QtImg = QtGui.QImage(QtImgBuf.data, QtImgBuf.shape[1], QtImgBuf.shape[0], QtGui.QImage.Format_RGBA8888) #返回QTimg格式
return QtImg
class Stats: #Stats类定义
def __init__(self): #初始化函数,创建类时自动调用,以下皆为参数
self.open = False #open参数定义
self.ui_face = QUiLoader().load('ui/demo.ui') #加载ui文件
self.ui_face.setFixedSize(1239, 824) #窗口设置固定的尺寸
self.ui_face.btn_open_cap.clicked.connect(self.opt_cap) #设置btn_open_cap按钮点击函数opt_cap,鼠标点击触发此函数
self.ui_face.btn_predict.clicked.connect(self.cap) #设置btn_predict按钮点击函数cap
self.ui_face.btn_open_res.clicked.connect(self.load_pic) #设置btn_open_res按钮点击函数load_pic
self.model, self.model_ft = self.load_model() #加载模型
#可回到147行
def load_pic(self): #加载图片函数
filePaths, _ = QFileDialog.getOpenFileName( #打开一个对话框,给用户选择文件,通过
self.ui_face, #此句获取打开的文件路径
"请选择将要转换的文件",
os.path.join(os.path.expanduser('~'), "Desktop"), #格式化路径
"文件类型 (*.jpg)" #格式化文件类型
)
self.ui_face.edt_res.setText(filePaths) #edt_res设置文本内容为文件路径
self.img = cv2.imread(filePaths) #opencv读取图片
show = cv2.resize(self.img, (640, 480)) #调整图片大小为640 480
show = cv2.cvtColor(show, cv2.COLOR_BGR2RGB) #从一种颜色空间BGR转换为另一种颜色空间RGB
showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0], QtGui.QImage.Format_RGB888) #显示图片,括号内图像参数
self.ui_face.ImgDisp.setPixmap(QtGui.QPixmap.fromImage(showImage)) #设置显示图片的位置
def opt_cap(self): #摄像头控制
if self.open == True: #如果已经打开
self.open = False #调整为关闭
self.ui_face.edt_cap.setText('摄像头已关闭') #输出”摄像头已关闭“
else:
self.open = True #如果已经关闭,调整为打开
self.ui_face.edt_cap.setText('摄像头已打开') #输出”摄像头已打开“
self.start() #调用start函数
def start(self): #shart函数
self.cap = cv2.VideoCapture(0) #VideoCapture()中参数是0,表示打开笔记本的内置摄像头
self.cap.set(3, 640) #设置分辨率
self.cap.set(4, 480) #设置分辨率
self.cap.set(10, 100) #设置分辨率
while True: #循环
success, self.img = self.cap.read() #图像进行翻转
self.img = cv2.flip(self.img, 1) #读取摄像头内容
show = cv2.resize(self.img, (640, 480)) #调整摄像大小
show = cv2.cvtColor(show, cv2.COLOR_BGR2RGB) #转换颜色空间
showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0], QtGui.QImage.Format_RGB888) #展示图片
self.ui_face.ImgDisp.setPixmap(QtGui.QPixmap.fromImage(showImage)) #设置图片位置
cv2.waitKey(0) #图片停留在界面
if self.open == False: #如果open未打开,则跳出循环
break
print('展示图片')
def cap(self): #cap函数
try: #try except语句
image = Image.fromarray(cv2.cvtColor(self.img, cv2.COLOR_BGR2RGB)) #调整图片格式
output = self.predict(image, self.model_ft) #调用predict函数
ret = [] #定义ret列表
emo = ['surprized', 'happy', 'disgust', 'normal', 'fear', 'anger', 'sad'] #定义表情库
for index, value in enumerate(self.model): #遍历model函数的结果
dis = np.linalg.norm(value - output) # 欧氏距离 #计算欧式距离
ret.append({'category': emo[index], 'dis': dis}) #将表情的种类和欧氏距离写入列表
ret = sorted(ret, key=operator.itemgetter('dis'), reverse=False) #ret根据欧氏距离排序
print(ret) #打印ret
self.ui_face.label_ret.setText('识别结果为:' + ret[0]['category']) #ui展示打印结果
self.ui_face.label_ret_0.setText('0:' + ret[0]['category']) #ui展示打印第一个结果
self.ui_face.label_ret_1.setText('1:' + ret[1]['category']) #ui展示打印第二个结果 #ui展示打印第一个结果
self.ui_face.label_ret_2.setText('2:' + ret[2]['category']) #ui展示打印第三个结果
self.ui_face.label_ret_3.setText('3:' + ret[3]['category']) #ui展示打印第四个结果
self.ui_face.label_ret_4.setText('4:' + ret[4]['category']) #ui展示打印第五个结果
self.ui_face.label_ret_5.setText('5:' + ret[5]['category']) #ui展示打印第六个结果
self.ui_face.label_ret_6.setText('6:' + ret[6]['category']) #ui展示打印第七个结果
except: #如果代码出现问题,执行pass
pass
def load_model(self): #总结,这个函数所有语句都是为了加载深度学习模型
# 这一块是对图片特征进行提取
model_path = 'model/weights.pth'
# build model
model_ft = models.resnet34(pretrained=False)
num_ftrs = model_ft.fc.in_features
model_ft.fc = nn.Sequential(
nn.Dropout(0.5),
nn.Linear(num_ftrs, 7),
nn.Softmax(dim=1)
)
model_ft.load_state_dict(torch.load(model_path))
model_ft.eval()
# 参数写到这里,得到的中心点遍历一下 然后写到这里
model = [
[2.0667151e-04, 3.4240412e-04, 1.4473200e-02, 8.0134422e-03, 6.0332119e-03,
7.7563822e-03, 9.6317458e-01],
[2.5990081e-04, 2.7968729e-04, 1.8215105e-02, 9.3163711e-01, 5.1174462e-03,
6.0818493e-03, 3.8408846e-02],
[0.00336622, 0.00619731, 0.10314032, 0.20358741, 0.27171963, 0.26114,
0.1508491],
[2.0508033e-04, 3.2301957e-04, 8.1134737e-03, 5.8690608e-03, 9.5963997e-01,
1.0704219e-02, 1.5145153e-02],
[4.1064431e-04, 1.2989613e-03, 8.9172471e-01, 2.3929298e-02, 1.7944381e-02,
2.8446108e-02, 3.6245927e-02],
[0.0014531, 0.00288311, 0.21803668, 0.1291624, 0.06903042, 0.04348047,
0.5359538],
[2.0752930e-04, 4.1509242e-04, 8.1426501e-03, 7.6724142e-03, 8.2466751e-03,
9.6485263e-01, 1.0462716e-02]
]
return model, model_ft
def predict(self, image, model): #根据模型预测结果函数
time_s = time.time() #获取当前时间
transform = transforms.Compose([ #图像预处理,包含多个步骤:调整大小,变成张量,标准化
transforms.Resize(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])
img = transform(image) #预处理图像
img = torch.unsqueeze(img, 0) #作用:扩展维度,返回一个新的张量,对输入的既定位置插入维度 1
output = model(img)[0].data.numpy() #将图片输入到模型,进行预测
time_e = time.time() - time_s #得出处理时间
self.ui_face.label_time.setText('用时:' + ('%.3f' % time_e) + 's') #输出处理时间
return output #返回输出结果
#从这里开始看
if __name__ == '__main__':
app = QApplication([]) #初始化,基于QWidget,用于处理QWidget特有的初始化和结束收尾工作。
stats = Stats() #创建Stats类并初始化,命名为stats,可以跳转到27行
stats.ui_face.show() #展示Stats类的ui_face,也就是展示界面
app.exec_() #运行程序