玩转Jetson Nano(八)人脸识别(二)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/beckhans/article/details/89548711

书接上文,得到了训练好的模型后,就可以使用这个模型做人脸识别了。当然,范围只限于被我拍照的几个人。

另外,我做了一个简单的界面,这个系统是用在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_())

 

展开阅读全文

没有更多推荐了,返回首页