開發環境:
- 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生態智聯”,學知識,享生活!