基於pyqt+OpenCV設計的用戶密碼或人臉識別登錄GUI程序設計

開發環境:

  • Windows7 64位
  • python3.7
  • pyqt5
  • pycharm
  • OpenCV3.4
  • QT Designer
  • PyUIC

目錄

 功能介紹

程序代碼

軟件截圖


 功能介紹

該程序主要在pycharm中開發,導入至pycharm裏的外部工具有QT Designer和PyUIC。其中QT Designer用於GUI佈局,PyUIC用於將ui文件轉換爲.py可執行文件。完整的程序包可點擊資料包下載。在這裏簡單介紹程序的執行步驟或功能,並附上相關截圖。

首先啓動程序,進入登錄界面,包括用戶名密碼登錄方式和人臉識別登錄方式。關於用戶名登錄方式,用戶名來自人臉識別信息錄入的人名,密碼是存儲在一個password.txt文本中。這種登錄方式會有用戶名不存在提示、密碼錯誤提示,若登錄成功,則會彈出“請編寫主程序的對話框”,當然讀者也可以編寫自定義程序。

而關於人臉識別登錄,有兩個按鈕:“人臉信息錄入按鈕”和“人臉識別登錄”按鈕。進入“人臉信息錄入按鈕”後,要求輸入用戶名,然後點擊“確認”按鈕,進行人臉數據採集、人臉模型訓練、最後彈出“人臉信息錄入成功”消息框。

溫馨提示:

輸入的用戶名將保存在user_names.txt文本中,並以逗號隔開。人臉數據採集,小編設置的爲150張圖片。

點擊“人臉識別登錄”按鈕,則會彈出人臉識別窗口,並在人臉框的左上角顯示識別到的人物所對應的序號(由於OpenCV顯示漢字比較麻煩,所以這裏選擇人名所對應的序號作爲識別結果),在人臉框的左下角顯示識別結果的置信度。

人臉識別程序設計:

如果識別置信度大於60%,則爲識別成功,並退出人臉識別界面,彈出“歡迎您:人名”對話框。如果識別不出來,則等待10秒左右退出識別界面,並彈出“人臉識別失敗”對話框。

注意:

登錄界面的佈局設計是在QT Designer中完成,在轉成.py文件後,需要對程序作一些修改和補充,以滿足實際開發需求,比如:類申明中,object需要改成QWidget,否則不能彈出QMessageBox消息對話框。

程序代碼

下面給出完整的程序,主要由三個程序組成:login.py、faces_input_frame.py和face_recognize.py。

# -*- coding: utf-8 -*-
#login.py程序
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QMessageBox,QWidget
from faces_input_frame import Ui_Dialog
import os


class Ui_Form(QWidget):  #將object改爲QWidget,才能彈出消息對話框
    def __init__(self):
        super(Ui_Form,self).__init__() #用戶添加代碼
    def setupUi(self, Form):
        self.form=Form  #用戶添加代碼
        Form.setObjectName("Form")
        Form.setMinimumSize(QtCore.QSize(329, 230))
        Form.setMaximumSize(QtCore.QSize(400, 230))
        Form.setStyleSheet("")
        self.label = QtWidgets.QLabel(Form)
        self.label.setGeometry(QtCore.QRect(63, 43, 64, 16))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.label.setFont(font)
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(Form)
        self.label_2.setGeometry(QtCore.QRect(63, 80, 48, 16))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.label_2.setFont(font)
        self.label_2.setObjectName("label_2")
        self.lineEdit_2 = QtWidgets.QLineEdit(Form)
        self.lineEdit_2.setGeometry(QtCore.QRect(121, 80, 133, 20))
        self.lineEdit_2.setEchoMode(QtWidgets.QLineEdit.Password)
        self.lineEdit_2.setCursorPosition(0)
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.pushButton = QtWidgets.QPushButton(Form)
        self.pushButton.setGeometry(QtCore.QRect(70, 150, 75, 23))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.pushButton.setFont(font)
        self.pushButton.setObjectName("pushButton")
        self.pushButton_2 = QtWidgets.QPushButton(Form)
        self.pushButton_2.setGeometry(QtCore.QRect(170, 150, 75, 23))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.pushButton_2.setFont(font)
        self.pushButton_2.setObjectName("pushButton_2")
        self.checkBox = QtWidgets.QCheckBox(Form)
        self.checkBox.setGeometry(QtCore.QRect(63, 110, 151, 20))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.checkBox.setFont(font)
        self.checkBox.setObjectName("checkBox")
        self.lineEdit_3 = QtWidgets.QLineEdit(Form)
        self.lineEdit_3.setGeometry(QtCore.QRect(121, 41, 133, 20))
        self.lineEdit_3.setObjectName("lineEdit_3")
        self.pushButton_face_pass = QtWidgets.QPushButton(Form)
        self.pushButton_face_pass.setGeometry(QtCore.QRect(279, 100, 104, 41))
        self.pushButton_face_pass.setMaximumSize(QtCore.QSize(16777215, 16777213))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.pushButton_face_pass.setFont(font)
        self.pushButton_face_pass.setObjectName("pushButton_face_pass")
        self.pushButton_face_input = QtWidgets.QPushButton(Form)
        self.pushButton_face_input.setGeometry(QtCore.QRect(280, 31, 104, 41))
        self.pushButton_face_input.setMaximumSize(QtCore.QSize(16777215, 16777213))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.pushButton_face_input.setFont(font)
        self.pushButton_face_input.setObjectName("pushButton_face_input")

        self.retranslateUi(Form)
        self.pushButton.clicked.connect(self.close)
        self.pushButton_2.clicked.connect(self.open)
        self.pushButton_face_input.clicked.connect(self.faceinput)
        self.pushButton_face_pass.clicked.connect(self.facepass)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.label.setText(_translate("Form", "用戶名:"))
        self.label_2.setText(_translate("Form", "密碼:"))
        self.pushButton.setText(_translate("Form", "取消"))
        self.pushButton_2.setText(_translate("Form", "確認"))
        self.checkBox.setText(_translate("Form", "記住用戶名和密碼"))
        self.pushButton_face_pass.setText(_translate("Form", "人臉識別登錄"))
        self.pushButton_face_input.setText(_translate("Form", "人臉信息錄入"))

    def open(self):
        #--------判斷用戶是否存在--------------
        fl = open('user_names.txt', 'r+')
        pre_name = fl.read()
        names = pre_name.split(',')
        fl.close()
        if self.lineEdit_3.text() in names:
            fl = open('password.txt', 'r+')
            password= fl.read()
            if self.lineEdit_2.text() ==password:
                reply=QMessageBox.information(self,'提示','請編寫主程序',QMessageBox.Close)
            else:
                reply=QMessageBox.information(self,'提示','密碼錯誤',QMessageBox.Close)


        else:
            reply=QMessageBox.information(self,'提示','用戶不存在',QMessageBox.Close)


    def close(self, event):
        self.close()
    def faceinput(self,event):
        self.form.hide()
        Form1=QtWidgets.QDialog()
        ui=Ui_Dialog()
        ui.setupUi(Form1)
        Form1.show()
        Form1.exec_()
        self.form.show()   #子窗口關閉後,主窗口顯示


    def facepass(self,event):
        import face_recognize
        get_name=face_recognize.recognize_face()#返回識別的人名
        if get_name=="unknown":
            reply = QMessageBox.information(self, '提示', '人臉識別失敗', QMessageBox.Close)
        else:
            reply = QMessageBox.information(self, '提示', "歡迎您:"+get_name, QMessageBox.Ok)
            print("編寫其他程序")


if __name__=="__main__":
    import sys
    app=QtWidgets.QApplication(sys.argv)
    widget=QtWidgets.QWidget()
    ui=Ui_Form()
    ui.setupUi(widget)
    widget.show()
    sys.exit(app.exec_())
# -*- coding: utf-8 -*-
#faces_input_frame.py程序
# Form implementation generated from reading ui file 'faces_input_frame.ui'
#
# Created by: PyQt5 UI code generator 5.12.2
#
# WARNING! All changes made in this file will be lost!
import face_recognize
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QMessageBox,QWidget
class Ui_Dialog(QWidget):
    def setupUi(self, Dialog):
        self.form=Dialog #用戶添加代碼
        Dialog.setObjectName("Dialog")
        Dialog.resize(315, 104)
        Dialog.setMinimumSize(QtCore.QSize(315, 104))
        Dialog.setMaximumSize(QtCore.QSize(315, 104))
        Dialog.setAutoFillBackground(False)
        self.Button_Enter = QtWidgets.QPushButton(Dialog)
        self.Button_Enter.setGeometry(QtCore.QRect(221, 21, 75, 27))
        font = QtGui.QFont()
        font.setPointSize(14)
        self.Button_Enter.setFont(font)
        self.Button_Enter.setObjectName("Button_Enter")
        self.Button_Exit=QtWidgets.QPushButton(Dialog)
        self.Button_Exit.setGeometry(QtCore.QRect(221, 54, 75, 27))
        font = QtGui.QFont()
        font.setPointSize(14)
        self.Button_Exit.setFont(font)
        self.Button_Exit.setObjectName("Button_Exit")
        self.face_name=QtWidgets.QLabel(Dialog)
        self.face_name.setGeometry(QtCore.QRect(40, 20, 131, 16))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.face_name.setFont(font)
        self.face_name.setObjectName("face_name")
        self.face_name_frame=QtWidgets.QLineEdit(Dialog)
        self.face_name_frame.setGeometry(QtCore.QRect(30, 40, 167, 31))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.face_name_frame.setFont(font)
        self.face_name_frame.setText("")
        self.face_name_frame.setObjectName("face_name_frame")

        self.retranslateUi(Dialog)
        self.Button_Enter.clicked.connect(self.Enter)
        self.Button_Exit.clicked.connect(self.ext)
    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.Button_Enter.setText(_translate("Dialog", "確認"))
        self.Button_Exit.setText(_translate("Dialog", "退出"))
        self.face_name.setText(_translate("Dialog", "請輸入您的姓名:"))

    def Enter(self):
        fl = open('user_names.txt','a+')
        if self.face_name_frame.text()=="":
            #輸入爲空時
            reply = QMessageBox.information(self, '提示', '請輸入有效用戶名', QMessageBox.Ok)
        else:
            fl.write(self.face_name_frame.text()+',')
            fl.close()

            reply = QMessageBox.information(self, '提示', '正在採集人臉數據', QMessageBox.Ok)
            face_recognize.Collect_faces()
            reply = QMessageBox.information(self, '提示', '正在訓練數據', QMessageBox.Ok)
            face_recognize.Training_faces()
            reply = QMessageBox.information(self, '提示', '人臉信息錄入成功', QMessageBox.Ok)


    def ext(self,event):
        self.form.close()


if __name__ == "__main__":
    import sys
    app=QtWidgets.QApplication(sys.argv)
    Dialog=QtWidgets.QDialog()
    ui = Ui_Dialog()
    ui.setupUi(Dialog)
    Dialog.show()
    sys.exit(app.exec_())
# -*- coding: utf-8 -*-
#face_recognize.py程序
def Collect_faces():
    import cv2
    import os
    # 調用筆記本內置攝像頭,所以參數爲0,如果有其他的攝像頭可以調整參數爲1,2

    cap = cv2.VideoCapture(0)

    face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

    fl = open('user_names.txt', 'r+')
    pre_name=fl.read()
    name = pre_name.split(',')
    face_id=len(name) - 2#去掉逗號及以零開始的序號,表示某人的一些列照片
    fl.close()
    #face_id = input('\n enter user id:')  #輸入序號,表示某人的一些列照片

    print('\n Initializing face capture. Look at the camera and wait ...')

    count = 0

    while True:

        # 從攝像頭讀取圖片

        sucess, img = cap.read()

        # 轉爲灰度圖片

        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        # 檢測人臉

        faces = face_detector.detectMultiScale(gray, 1.3, 5)

        for (x, y, w, h) in faces:
            cv2.rectangle(img, (x, y), (x + w, y + w), (255, 0, 0))
            count += 1

            # 保存圖像,從原始照片中截取人臉尺寸
            cv2.imwrite("Facedata/User." +str(face_id) + '.' + str(count) + '.jpg', gray[y: y + h, x: x + w])

            cv2.imshow('image', img)

        # 保持畫面的持續。

        k = cv2.waitKey(1)

        if k == 27:  # 通過esc鍵退出攝像
            break

        elif count >=150:  # 得到150個樣本後退出攝像
            break

    # 關閉攝像頭
    cap.release()
    cv2.destroyAllWindows()

def Training_faces():
    import numpy as np
    from PIL import Image
    import os
    import cv2
    # 人臉數據路徑
    path = 'Facedata'

    recognizer = cv2.face.LBPHFaceRecognizer_create()
    detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")

    def getImagesAndLabels(path):
        imagePaths = [os.path.join(path, f) for f in os.listdir(path)]  # join函數的作用?
        faceSamples = []
        ids = []
        for imagePath in imagePaths:
            PIL_img = Image.open(imagePath).convert('L')  # convert it to grayscale
            img_numpy = np.array(PIL_img, 'uint8')
            id = int(os.path.split(imagePath)[-1].split(".")[1])
            faces = detector.detectMultiScale(img_numpy)
            for (x, y, w, h) in faces:
                faceSamples.append(img_numpy[y:y + h, x: x + w])
                ids.append(id)
        return faceSamples, ids

    print('Training faces. It will take a few seconds. Wait ...')
    faces, ids = getImagesAndLabels(path)
    recognizer.train(faces, np.array(ids))

    recognizer.write(r'face_trainer\trainer.yml')
    print("{0} faces trained. Exiting Program".format(len(np.unique(ids))))

def recognize_face():
    #識別時間10秒;如果置信度大於60%,則識別成功並退出界面;否則至10秒後識別失敗並退出
    import cv2
    recognizer = cv2.face.LBPHFaceRecognizer_create()
    recognizer.read('face_trainer/trainer.yml')
    cascadePath = "haarcascade_frontalface_default.xml"
    faceCascade = cv2.CascadeClassifier(cascadePath)
    font = cv2.FONT_HERSHEY_SIMPLEX
    idnum =None #初始化識別序號
    fl = open('user_names.txt', 'r+')
    pre_name = fl.read()
    names = pre_name.split(',')

    cam = cv2.VideoCapture(0)
    minW = 0.1 * cam.get(3)
    minH = 0.1 * cam.get(4)
    time=0
    while True:
        result = "unknown"   #初始化識別失敗
        time+=1
        ret, img = cam.read()
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        faces = faceCascade.detectMultiScale(
            gray,
            scaleFactor=1.2,
            minNeighbors=5,
            minSize=(int(minW), int(minH))
        )
        face_num=None  #初始化人臉序號

        for (x, y, w, h) in faces:
            cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
            idnum, confidence = recognizer.predict(gray[y:y + h, x:x + w])
            if confidence>60: #60%的識別置信度
                face_num=idnum
                result= names[idnum]
                confidence = "{0}%".format(round(100 - confidence))
                cam.release()
                cv2.destroyAllWindows()  #退出攝像頭
                return result
            else:
                confidence = "{0}%".format(round(100 - confidence))
            cv2.putText(img, str(face_num), (x + 5, y - 5), font, 1, (0, 0, 255), 1)
            cv2.putText(img, str(confidence), (x + 5, y + h - 5), font, 1, (0, 0, 0), 1)
        cv2.imshow('camera', img)#彈出攝像頭與否
        k = cv2.waitKey(1)
        if k == 27:
            break
        elif time>100:  # 大約10秒識別時間
            break
    cam.release()
    cv2.destroyAllWindows()
    return result   #返回識別結果:人名或“unknown”

軟件截圖

 歡迎關注微信公衆號“Python生態智聯”,學知識,享生活!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章