Resumen del blog: Python | Sistema de reconocimiento facial — Índice del blog
Dirección de GitHub: Su-Reconocimiento facial
Nota: consulte antes de leer este blog
Instalación de herramientas, configuración del entorno: Python | Sistema de reconocimiento facial—Introducción
Diseño de interfaz de usuario: Python | Sistema de reconocimiento facial — Diseño de interfaz de usuario
Procesamiento de eventos de interfaz de usuario: Python | Sistema de reconocimiento facial: procesamiento de eventos de interfaz de usuario
Reconocimiento facial: Python | Sistema de reconocimiento facial: reconocimiento facial
Detección de vida: Python | Sistema de reconocimiento facial - Detección de vida
1. Inicio de sesión de usuario
1. Lógica de inicio de sesión
Verificación de información (base de datos) -> detección de vida silenciosa -> detección de vida interactiva -> reconocimiento facial
Una vez que el usuario no logra iniciar sesión con éxito por más de tres veces (la detección de vida/el reconocimiento facial no tiene éxito), el sistema bloqueará al usuario actual. Los usuarios deben ser desbloqueados por un administrador.
# 登录标志
USER_LOGIN_MSG_FLAG = False # 用户信息核验成功标志
USER_LOGIN_FLAG = False # 用户登录成功标志
... ...
# 用户登录
def user_login(self):
if not self.cap.isOpened():
QMessageBox.information(self, "提示", self.tr("请先打开摄像头"))
else:
global USER_LOGIN_FLAG
if not USER_LOGIN_FLAG:
QApplication.processEvents()
login = LoginWindow(self) # 创建信息核验界面对象
login.exec_()
global USER_LOGIN_MSG_FLAG
global USER_LOGIN_NAME
if USER_LOGIN_MSG_FLAG:
# 登录信息成功,进行活体检测
QMessageBox.about(self, '提示', '登录成功,进行活体检测')
if self.detect_face():
# 活体检测成功,进行人脸识别
global ENCODING_TEMP
face_encoding = FaceEncodingUtil.decoding_FaceStr(ENCODING_TEMP)
if self.recognize_instant_face(face_encoding):
QMessageBox.about(self, '提示', '登陆成功')
self.save_record(USER_LOGIN_NAME, '使用摄像头进行登录') # 使用excel表格进行保存
USER_LOGIN_FLAG = True
else:
QMessageBox.about(self, '提示', '人脸识别失败,请重新登录')
if USER_LOGIN_NAME != "":
UserSqlUtil.add_name_warn(USER_LOGIN_NAME)
USER_LOGIN_MSG_FLAG = False
else:
QMessageBox.about(self, '提示', '活体检测失败,请重新登录')
if USER_LOGIN_NAME != "":
UserSqlUtil.add_name_warn(USER_LOGIN_NAME)
USER_LOGIN_MSG_FLAG = False
login.destroy()
else:
QMessageBox.about(self, '提示', '用户已经登录')
2. Verificación de la información
El usuario hace clic en el botón [Inicio de sesión de usuario] y la interfaz de verificación de información aparece en la interfaz principal, lo que requiere que el usuario ingrese el número de cuenta y la contraseña. Después de hacer clic en Aceptar, el sistema accede a la base de datos para determinar si la información ingresada es correcta.
Código relacionado con la interfaz de verificación de información:
# 用户登录界面
class LoginWindow(QDialog, LoginMsgUi):
def __init__(self, parent=None):
super(LoginWindow, self).__init__(parent)
self.setupUi(self)
self.minimize_button.clicked.connect(self.showMinimized)
self.close_button.clicked.connect(self.cancel_login)
self.confirm_button.clicked.connect(self.search_user)
self.cancel_button.clicked.connect(self.cancel_login)
# 点击确认,搜索用户
def search_user(self):
input_name = self.name_lineEdit.text()
input_password = self.password_lineEdit.text()
if input_name == "":
QMessageBox.about(self, '提示', '姓名不能为空')
elif input_password == "":
QMessageBox.about(self, '提示', '密码不能为空')
else:
row = UserSqlUtil.search_by_name("\"" + input_name + "\"")
if row:
result = row[0]
password = result[1]
if input_password != password:
QMessageBox.about(self, '提示', '密码输入错误')
else:
global USER_LOGIN_MSG_FLAG
count = UserSqlUtil.search_count_warn("\"" + input_name + "\"")
if count >= 3:
QMessageBox.about(self, '警告', '该账号目前已被锁定')
USER_LOGIN_MSG_FLAG = False
else:
global ENCODING_TEMP
global USER_LOGIN_NAME
USER_LOGIN_MSG_FLAG = True
ENCODING_TEMP = result[5]
USER_LOGIN_NAME = input_name
self.close_window()
else:
QMessageBox.about(self, '提示', '该用户不存在')
# 点击取消按钮
def cancel_login(self):
global USER_LOGIN_MSG_FLAG
USER_LOGIN_MSG_FLAG = False
self.close_window()
# 关闭窗口
def close_window(self):
self.name_lineEdit.setPlaceholderText("请输入姓名")
self.password_lineEdit.setPlaceholderText("请输入密码")
self.close()
Estructura de la tabla de base de datos (tabla de usuario)
código de la base de datos
# -*- coding: utf-8 -*-
import pymysql
def init_conn():
conn = pymysql.connect(
host="127.0.0.1", # 数据库的IP地址
user="root", # 数据库用户名称
password="root", # 数据库用户密码
db="contest", # 数据库名称
port=3306, # 数据库端口名称
charset="utf8" # 数据库的编码方式
)
return conn
def execute_with_bool(sql_str, args=()):
conn = init_conn()
cursor = conn.cursor()
try:
cursor.execute(sql_str, args)
conn.commit()
return True
except Exception as e:
conn.rollback()
print(e)
return False
finally:
cursor.close()
def execute_with_list(sql_str):
conn = init_conn()
cursor = conn.cursor()
results = []
try:
cursor.execute(sql_str)
results = cursor.fetchall()
except Exception as e:
conn.rollback()
print(e)
finally:
cursor.close()
return results
def insert_data(name, password, age, sex, more, face_encoding):
return execute_with_bool(
"insert into user(name,password,age,sex,more,face_encoding) values(%s,%s,%s,%s,%s,%s)",
(name, password, age, sex, more, face_encoding))
def update_by_name(name, password, age, sex, more, face_encoding):
return execute_with_bool(
"update user set name=%s,password=%s,age=%s,sex=%s,more=%s,face_encoding=%s where name = %s",
(name, password, age, sex, more, face_encoding, name))
def update_by_name_without_encoding(name, age, sex, more):
return execute_with_bool("update user set name=%s,age=%s,sex=%s,more=%s where name = %s",
(name, age, sex, more, name))
def search_all_msg():
return execute_with_list("select * from user")
def search_by_name(name):
return execute_with_list("select * from user where name = " + name)
def search_count_name(name):
return execute_with_list("select count(*) from user where name = " + name)[0][0]
def delete_by_name(name):
return execute_with_bool("delete from user where name = %s", name)
def search_count_warn(name):
return execute_with_list("select count(*) from warn where name = " + name)[0][0]
def add_name_warn(name):
return execute_with_bool("insert into warn(name) values(%s)", name)
3. Detección de vida
La función de detección de vida detect_face() se detalla en el blog:
4. Reconocimiento facial
La función de reconocimiento de rostrosreconoce_instant_face() se detalla en el blog:
El reconocimiento facial utiliza la función reconocer_instant_face(), que requiere el parámetro face_encoding, que es una matriz de 1*128. Cuando recuperamos el código de rostro del usuario actualmente conectado de la base de datos, es un tipo de cadena y debe convertirse. Escriba la clase de herramienta FaceEncodingUtil y llame al método escrito decoding_FaceStr para convertir. Sus métodos de clase de herramienta son los siguientes:
# -*- coding: utf-8 -*-
import numpy
def decoding_FaceStr(encoding_str):
# 将字符串转为numpy ndarray类型,即矩阵
# 转换成一个list
decoding_list = encoding_str.strip(' ').split(',')
# 将list中str转换为float
decoding_float = list(map(float, decoding_list))
face_encoding = numpy.array(decoding_float)
return face_encoding
2. Registro de usuario
1. juez
La cámara captura la cara actual -> completa la información -> codifica la información facial -> guarda la información (base de datos)
La cámara captura la foto del rostro actual, usa el punto de tiempo actual como el nombre de la foto y lo guarda en el directorio de fotos, y elimina la foto después de que la codificación de la información facial sea exitosa.
signal_register = pyqtSignal() # 用户注册 界面信号
... ...
# 用户注册
def user_register(self):
isCapOpened_flag = self.cap.isOpened()
if not isCapOpened_flag:
QMessageBox.information(self, "提示", self.tr("请先打开摄像头!"))
else:
ret, frame = self.cap.read()
frame_location = face_recognition.face_locations(frame)
if len(frame_location) == 0:
QMessageBox.information(self, "提示", self.tr("没有检测到人脸,请重新拍摄!"))
else:
QMessageBox.information(self, "提示", self.tr("拍照成功!"))
global PHOTO_FOLDER_PATH
global SHOT_TEMP_NAME
SHOT_TEMP_NAME = datetime.now().strftime("%Y%m%d%H%M%S")
self.show_image.save(PHOTO_FOLDER_PATH + SHOT_TEMP_NAME + ".jpg")
self.send_signal_register()
# 发射信号 打开注册用户界面
def send_signal_register(self):
self.signal_register.emit()
2. Escritura lógica
El usuario hace clic en el botón [Registro de usuario] y la interfaz principal muestra la interfaz de llenado de información, lo que requiere que el usuario ingrese el número de cuenta, la contraseña y otra información. Después de hacer clic en Aceptar, el sistema juzga si el formato de la información de entrada es correcto.
# 用户注册界面
class RegisterWindow(QMainWindow, RegisterMsgUi):
def __init__(self, parent=None):
super(RegisterWindow, self).__init__(parent)
self.setupUi(self)
self.minimize_button.clicked.connect(self.showMinimized)
self.close_button.clicked.connect(self.close_window)
self.cancel_button.clicked.connect(self.delete_shot)
self.confirm_button.clicked.connect(self.fill_information)
# 填写信息
def fill_information(self):
flag = 0
name = self.name_lineEdit.text()
password = self.password_lineEdit.text()
age = self.age_lineEdit.text()
sex = self.sex_lineEdit.text()
more_infor = self.more_lineEdit.text()
if self.judge_name_conflict(name):
if name != '':
# 输入密码
if password != '':
# 输入年龄
if age == '':
age = '未知'
elif not str.isdigit(age):
flag = 1
QMessageBox.about(self, '提示', '请输入正确的年龄格式')
# 输入性别
if sex == '':
sex = '未知'
elif sex != '男' and sex != '女':
flag = 1
QMessageBox.about(self, '提示', '请输入正确的性别格式')
sex = '未知'
# 输入更多信息
if more_infor == '':
more_infor = '未知'
global PHOTO_FOLDER_PATH
global SHOT_TEMP_NAME
if flag == 0:
# 计算脸部数据并保存到数据库
QApplication.processEvents()
register_encoding = self.analyse_encoding(SHOT_TEMP_NAME)
if self.save_database(name, password, age, sex, more_infor, register_encoding):
QMessageBox.about(self, '提示', '完成注册')
else:
QMessageBox.about(self, '提示', '注册失败')
self.delete_shot()
elif flag == 1:
QMessageBox.about(self, '提示', '注册失败')
else:
QMessageBox.about(self, '提示', '请输入密码')
else:
QMessageBox.about(self, '提示', '请输入姓名')
else:
QMessageBox.about(self, '提示', '用户' + name + '已经注册过')
# 保存注册信息
@staticmethod
def save_database(name, password, age, sex, more, face_encoding):
return UserSqlUtil.insert_data(name, password, age, sex, more, face_encoding)
# 判断姓名是否冲突
@staticmethod
def judge_name_conflict(name):
count = UserSqlUtil.search_count_name("\"" + name + "\"")
if count != 0:
return False
else:
return True
# 分析截图
@staticmethod
def analyse_encoding(name):
global PHOTO_FOLDER_PATH
photo_path = PHOTO_FOLDER_PATH + name + ".jpg"
register_images = face_recognition.load_image_file(photo_path)
register_encoding = face_recognition.face_encodings(register_images)[0]
return FaceEncodingUtil.encoding_FaceStr(register_encoding)
# 删除截图
def delete_shot(self):
global PHOTO_FOLDER_PATH
global SHOT_TEMP_NAME
delete_shot_path = PHOTO_FOLDER_PATH + SHOT_TEMP_NAME + ".jpg"
os.remove(delete_shot_path)
SHOT_TEMP_NAME = ""
self.close_window()
# 关闭窗口
def close_window(self):
lineText = [self.age_lineEdit, self.sex_lineEdit, self.name_lineEdit, self.more_lineEdit]
line = 0
for lineEdit in lineText:
lineEdit.setPlaceholderText(str(line))
if 3 >= line >= 0:
lineEdit.setPlaceholderText("请输入信息")
line = line + 1
self.close()
Al guardar en la base de datos, los datos de codificación de rostros son una matriz de 1*128, que debe convertirse mediante el método encoding_FaceStr de la clase de herramienta FaceEncodingUtil. Sus métodos de clase de herramienta son los siguientes:
# -*- coding: utf-8 -*-
import numpy
def encoding_FaceStr(image_face_encoding):
# 将numpy array类型转化为列表
encoding__array_list = image_face_encoding.tolist()
# 将列表里的元素转化为字符串
encoding_str_list = [str(i) for i in encoding__array_list]
# 拼接列表里的字符串
encoding_str = ','.join(encoding_str_list)
return encoding_str
3. Cierre de sesión del usuario
La operación de cierre de sesión del usuario es relativamente simple, solo configure el indicador global USER_LOGIN_FLAG en False.
El código del juez es el siguiente:
# 用户登出
def user_logout(self):
global USER_LOGIN_FLAG
global USER_LOGIN_NAME
if not USER_LOGIN_FLAG:
QMessageBox.about(self, '提示', '请先登录')
else:
USER_LOGIN_FLAG = False
QMessageBox.about(self, '提示', '退出成功')
self.save_record(USER_LOGIN_NAME, '退出登录') # 记录到excel表格中
4. Registros de tablas de Excel
Guarde el tiempo de operación de inicio y cierre de sesión del usuario, el equipo, el nombre de usuario y otra información en el formulario de Excel del sistema. Puede iniciar sesión en el sistema como administrador y exportar el formulario de Excel del sistema para verlo. El código para exportar el formulario de Excel está escrito en el lado del administrador.
El código para guardar la información en la tabla de Excel es el siguiente:
# 将记录保存到excel中
@staticmethod
def save_record(name, record):
global DATA_FOLDER_PATH
local_path = DATA_FOLDER_PATH + 'history.xls'
old_book = xlrd.open_workbook(local_path)
new_book = copy(old_book)
sheet2 = new_book.get_sheet(0)
sheet0 = old_book.sheet_by_index(0)
n_rows = sheet0.nrows
str_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
sheet2.write(n_rows + 1, 0, str_time)
sheet2.write(n_rows + 1, 1, '摄像头')
sheet2.write(n_rows + 1, 2, name)
sheet2.write(n_rows + 1, 3, record)
new_book.save('new_book.xls')
os.remove(local_path)
os.rename('new_book.xls', local_path)
sigue leyendo:
Visualización de la pantalla de la cámara: sistema de reconocimiento facial - visualización de la pantalla de la cámara
Lógica del lado del cliente:
- Reconocimiento facial: Python | Sistema de reconocimiento facial: reconocimiento facial
- Detección de vida: Python | Sistema de reconocimiento facial - Detección de vida
- Desenfoque de fondo: Python | Sistema de reconocimiento facial - Desenfoque de fondo
- Detección de poses: Python | Sistema de reconocimiento facial - Detección de poses
- Comparación de rostros: Python | Sistema de reconocimiento facial - comparación de rostros
Lógica del lado del administrador:
- Operaciones del administrador: Python | Sistema de reconocimiento facial——Operaciones del administrador
Nota: El código anterior es solo de referencia. Para ejecutarlo, consulte el código fuente de GitHub: Su-Face-Recognition