书接上文,得到了训练好的模型后,就可以使用这个模型做人脸识别了。当然,范围只限于被我拍照的几个人。
另外,我做了一个简单的界面,这个系统是用在windows下,和之前的训练模型在Ubuntu下不一样,所以我重新建立了一个工程。并使用了 Keras2.2.4 ,OpenCV4.1, Python3.6.7,Pyqt5.0。
好了。开始干活
1. 画界面。
这个没啥好说的,我用QtDesigner画的界面,大致是下面这个样子,左边放了一个QLabel放摄像头捕获的图形,右边三个按钮
QtDesigner自动生成的代码如下:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'D:\exceise\main_window.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1024, 768)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.FaceCollect = QtWidgets.QPushButton(self.centralwidget)
self.FaceCollect.setGeometry(QtCore.QRect(790, 130, 151, 51))
self.FaceCollect.setObjectName("FaceCollect")
self.OpenCamera = QtWidgets.QPushButton(self.centralwidget)
self.OpenCamera.setGeometry(QtCore.QRect(790, 40, 151, 51))
self.OpenCamera.setObjectName("OpenCamera")
self.FaceIdentify = QtWidgets.QPushButton(self.centralwidget)
self.FaceIdentify.setGeometry(QtCore.QRect(790, 220, 151, 51))
self.FaceIdentify.setObjectName("FaceIdentify")
self.ImageView = QtWidgets.QLabel(self.centralwidget)
self.ImageView.setGeometry(QtCore.QRect(30, 20, 711, 681))
self.ImageView.setObjectName("ImageView")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1024, 26))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "人脸识别"))
self.FaceCollect.setText(_translate("MainWindow", "采集人脸"))
self.OpenCamera.setText(_translate("MainWindow", "打开摄像头"))
self.FaceIdentify.setText(_translate("MainWindow", "人脸识别"))
self.ImageView.setText(_translate("MainWindow", ""))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
我不想直接改动QtDesigner直接生成的代码,所以自己写一个窗口类,继承在自动生成的这个窗口。
下面代码中center_window函数是让窗口自动居中,closeEvent是窗口关闭事件。slot_init是初始化槽函数
import sys
import cv2
from PyQt5 import QtGui, QtWidgets
from PyQt5.QtCore import *
from keras.models import load_model
from windows.main_window import Ui_MainWindow # 导入创建的GUI类
class Window1(QtWidgets.QMainWindow, Ui_MainWindow):
color = (0, 255, 0) # 人脸矩形框的颜色
model = load_model("model\CNN.model")
def __init__(self):
super(Window1, self).__init__()
self.setupUi(self)
self.center_window()
self.timer_camera = QTimer()
self.cap = cv2.VideoCapture()
self.CAM_NUM = 0
self.slot_init()
def closeEvent(self, event):
ok = QtWidgets.QPushButton()
cacel = QtWidgets.QPushButton()
msg = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Warning, u"关闭", u"是否关闭!")
msg.addButton(ok,QtWidgets.QMessageBox.ActionRole)
msg.addButton(cacel, QtWidgets.QMessageBox.RejectRole)
ok.setText(u'确定')
cacel.setText(u'取消')
# msg.setDetailedText('sdfsdff')
if msg.exec_() == QtWidgets.QMessageBox.RejectRole:
event.ignore()
else:
# self.socket_client.send_command(self.socket_client.current_user_command)
if self.cap.isOpened():
self.cap.release()
if self.timer_camera.isActive():
self.timer_camera.stop()
event.accept()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window1()
window.show()
sys.exit(app.exec_())
然后解释把摄像头在QT窗口上显示的原理,理解了这个原理基本上就明白代码怎么写了。这个原理就是通过OpenCV打开摄像头,读取每一帧图像,然后输出到QLabel上。所以要有一个Timer定时器,每隔一段时间读一帧摄像头信息,然后输出给QLabel。代码如下:
def show_camera(self):
# 加载分类器
classfier = cv2.CascadeClassifier("..\haarcascade_frontalface_alt2.xml")
# 读取一帧数据,flag表示摄像头读取状态,self.image表示摄像头读取的图像矩阵mat类型
flag, self.image = self.cap.read()
# 图像灰度化,灰度化在后面检测时可以降低计算量
show = cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB)
# detectMultiScale完成人脸探测工作,returns the positions of detected faces as Rect(x,y,w,h),x、y是左上角起始坐标,h、w是高和宽
# grey是要识别的图像数据,scaleFactor图像缩放比例,可以理解为同一个物体与相机距离不同,其大小亦不同,必须将其缩放到一定大小才方便识别,该参数指定每次缩放的比例
Rects = classfier.detectMultiScale(show, scaleFactor=1.2, minNeighbors=3, minSize=(32, 32))
if len(Rects) > 0:
for Rect in Rects:
x, y, w, h = Rect
# 如果监测到人脸,在人脸范围画绿色的框,其中self.color = (0, 255, 0)
cv2.rectangle(show, (x, y), (x + w, y + h), self.color, 2) # 画出矩形框
# 将监测到的人脸送给之前的模型进行人脸识别
img = cv2.resize(show, (128, 128))
img = img.reshape(1, 128, 128, 3).astype('float32')
predicted = self.model.predict(img)
# 由于QLabel不能直接显示img类型,需要转化成QImage类型
showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0], QtGui.QImage.Format_RGB888)
self.ImageView.setPixmap(QtGui.QPixmap.fromImage(showImage))
上面的代码里就实现了人脸检测,没错就是这段代码。通过调试predicted你会发现predicted[4]=1,没错,记得上篇文章吗,我就是4号。可能有朋友要问,为什么不做个QMessageBox之类的东西,发现4号弹一个有名字的消息框,答案是我懒病犯了,不想弄。这个理由充足不!
# 将监测到的人脸送给之前的模型进行人脸识别
img = cv2.resize(show, (128, 128))
img = img.reshape(1, 128, 128, 3).astype('float32')
predicted = self.model.predict(img)
同样你也要实现按钮的按下事件
def OpenCameraButtonClick(self):
if self.timer_camera.isActive() == False:
flag = self.cap.open(self.CAM_NUM)
if flag == False:
msg = QtWidgets.QMessageBox.warning(self, u"Warning", u"请检测相机与电脑是否连接正确", buttons=QtWidgets.QMessageBox.Ok,
defaultButton=QtWidgets.QMessageBox.Ok)
else:
self.timer_camera.start(30)
self.OpenCamera.setText(u'关闭相机')
else:
self.timer_camera.stop()
self.cap.release()
self.ImageView.clear()
self.OpenCamera.setText(u'打开相机')
整体的代码:
import sys
import cv2
from PyQt5 import QtGui, QtWidgets
from PyQt5.QtCore import *
from keras.models import load_model
from windows.main_window import Ui_MainWindow # 导入创建的GUI类
class Window1(QtWidgets.QMainWindow, Ui_MainWindow):
color = (0, 255, 0) # 人脸矩形框的颜色
model = load_model("..\model\CNN.model")
def __init__(self):
super(Window1, self).__init__()
self.setupUi(self)
self.center_window()
self.timer_camera = QTimer()
self.cap = cv2.VideoCapture()
self.CAM_NUM = 0
self.slot_init()
def center_window(self):
desktop_geometry = QtWidgets.QApplication.desktop() # 获取屏幕大小
main_window_width = desktop_geometry.width() # 屏幕的宽
main_window_height = desktop_geometry.height() # 屏幕的高
rect = self.geometry() # 获取窗口界面大小
window_width = rect.width() # 窗口界面的宽
window_height = rect.height() # 窗口界面的高
x = (main_window_width - window_width) // 2 # 计算窗口左上角点横坐标
y = (main_window_height - window_height) // 2 # 计算窗口左上角点纵坐标
self.setGeometry(x, y, window_width, window_height) # 设置窗口界面在屏幕上的位置
def slot_init(self):
self.OpenCamera.clicked.connect(self.OpenCameraButtonClick)
self.timer_camera.timeout.connect(self.show_camera)
def OpenCameraButtonClick(self):
if self.timer_camera.isActive() == False:
flag = self.cap.open(self.CAM_NUM)
if flag == False:
msg = QtWidgets.QMessageBox.warning(self, u"Warning", u"请检测相机与电脑是否连接正确", buttons=QtWidgets.QMessageBox.Ok,
defaultButton=QtWidgets.QMessageBox.Ok)
else:
self.timer_camera.start(30)
self.OpenCamera.setText(u'关闭相机')
else:
self.timer_camera.stop()
self.cap.release()
self.ImageView.clear()
self.OpenCamera.setText(u'打开相机')
def show_camera(self):
# 加载分类器
classfier = cv2.CascadeClassifier("..\haarcascade_frontalface_alt2.xml")
# 读取一帧数据,flag表示摄像头读取状态,self.image表示摄像头读取的图像矩阵mat类型
flag, self.image = self.cap.read()
# 图像灰度化,灰度化在后面检测时可以降低计算量
show = cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB)
# detectMultiScale完成人脸探测工作,returns the positions of detected faces as Rect(x,y,w,h),x、y是左上角起始坐标,h、w是高和宽
# grey是要识别的图像数据,scaleFactor图像缩放比例,可以理解为同一个物体与相机距离不同,其大小亦不同,必须将其缩放到一定大小才方便识别,该参数指定每次缩放的比例
Rects = classfier.detectMultiScale(show, scaleFactor=1.2, minNeighbors=3, minSize=(32, 32))
if len(Rects) > 0:
for Rect in Rects:
x, y, w, h = Rect
# 如果监测到人脸,在人脸范围画绿色的框,其中self.color = (0, 255, 0)
cv2.rectangle(show, (x, y), (x + w, y + h), self.color, 2) # 画出矩形框
# 将监测到的人脸送给之前的模型进行人脸识别
img = cv2.resize(show, (128, 128))
img = img.reshape(1, 128, 128, 3).astype('float32')
predicted = self.model.predict(img)
# 由于QLabel不能直接显示img类型,需要转化成QImage类型
showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0], QtGui.QImage.Format_RGB888)
self.ImageView.setPixmap(QtGui.QPixmap.fromImage(showImage))
def closeEvent(self, event):
ok = QtWidgets.QPushButton()
cacel = QtWidgets.QPushButton()
msg = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Warning, u"关闭", u"是否关闭!")
msg.addButton(ok,QtWidgets.QMessageBox.ActionRole)
msg.addButton(cacel, QtWidgets.QMessageBox.RejectRole)
ok.setText(u'确定')
cacel.setText(u'取消')
# msg.setDetailedText('sdfsdff')
if msg.exec_() == QtWidgets.QMessageBox.RejectRole:
event.ignore()
else:
# self.socket_client.send_command(self.socket_client.current_user_command)
if self.cap.isOpened():
self.cap.release()
if self.timer_camera.isActive():
self.timer_camera.stop()
event.accept()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window1()
window.show()
sys.exit(app.exec_())