开发环境:
- 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”
欢迎关注微信公众号“Py生活”,学知识,享生活!