Python | Sistema de reconocimiento facial—Operación del usuario

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:

Lógica del lado del administrador:

Nota: El código anterior es solo de referencia. Para ejecutarlo, consulte el código fuente de GitHub:  Su-Face-Recognition

Supongo que te gusta

Origin blog.csdn.net/sun80760/article/details/130493221
Recomendado
Clasificación