基于机器视觉的考场人脸比对&考生信息管理系统

本文介绍了一个基于机器视觉的考场人脸比对和考生信息管理系统,旨在提高考试监控效率和准确性,保证公平性和安全性。系统通过摄像头实时监控,利用人脸识别技术验证考生身份,避免冒名顶替。核心算法包括Haar特征、AdaBoost级联分类器和PCA人脸识别。系统整合了图像处理、面部特征提取和人脸比对,确保了考试的公正性和安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.研究背景与意义

项目参考AAAI Association for the Advancement of Artificial Intelligence

研究背景与意义

随着科技的不断发展,机器视觉技术在各个领域得到了广泛的应用。其中,基于机器视觉的考场人脸比对和考生信息管理系统是一个备受关注的研究领域。传统的考试监控方式主要依靠人工监控,但这种方式存在一些问题,如人工监控的效率低、容易出现疏漏、难以保证监控的公正性等。而基于机器视觉的考场人脸比对和考生信息管理系统可以有效地解决这些问题,提高考试监控的效率和准确性,保证考试的公平性和安全性。

首先,基于机器视觉的考场人脸比对和考生信息管理系统可以提高考试监控的效率。传统的考试监控方式需要大量的人力投入,监控人员需要对考场进行全天候的监控,这不仅浪费人力资源,而且容易出现监控疏漏的情况。而基于机器视觉的系统可以实现自动化的监控,通过摄像头对考场进行实时监控,并通过人脸识别技术对考生进行身份验证,大大减轻了监控人员的工作负担,提高了监控的效率。

其次,基于机器视觉的考场人脸比对和考生信息管理系统可以提高考试监控的准确性。传统的考试监控方式容易出现监控疏漏的情况,监控人员可能会因为疲劳或其他原因而错过一些异常情况。而基于机器视觉的系统可以实现全天候的监控,不会出现监控疏漏的情况。同时,人脸识别技术可以准确地对考生进行身份验证,避免了考生冒名顶替的情况,保证了考试的公平性和安全性。

最后,基于机器视觉的考场人脸比对和考生信息管理系统可以提高考试的公平性和安全性。传统的考试监控方式容易出现人为因素的干扰,监控人员可能会对某些考生有偏见或不公正的对待。而基于机器视觉的系统可以实现自动化的监控,不会受到人为因素的干扰,保证了考试的公平性。同时,人脸识别技术可以准确地对考生进行身份验证,避免了考生冒名顶替的情况,保证了考试的安全性。

综上所述,基于机器视觉的考场人脸比对和考生信息管理系统在提高考试监控效率和准确性、保证考试公平性和安全性方面具有重要的意义。通过研究和开发这样的系统,可以为教育行业提供更加高效、准确、公正和安全的考试监控解决方案,推动教育行业的发展和进步。

2.图片演示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.视频演示

基于机器视觉的考场人脸比对&考生信息管理系统_哔哩哔哩_bilibili

4.系统流程图

OpenCV是一个开源发行的跨平台计算机视觉库,可以运行在Linux , Windows 、Android ,Mac OS操作系统上.它用C++编写,但提供了大量的Python , Ruby 等语言接口[4.5].
在OpenVCV2.4以后,加入了新的类FaceRec-ognizer.通过它可以方便快捷的进行人脸识别.首先输入人脸图像训练样本, FaceRecognizer类调用train方法对其进行训练,训练的结果通过调用save方法保存到FaceRecognizer对象中.接着进行识别工作,先通过load方法加载之前训练好的特征文件,然后FaceRecognizer调用predict方法进行人脸识别,整个识别过程在OpenCV中的实现过程如图所示.
在这里插入图片描述

5.核心代码讲解

5.1 config.py

以下是根据您提供的代码封装的类:

class EmotionDetection:
    def __init__(self):
        self.path_model = 'emotion_detection/Modelos/model_dropout.hdf5'
        self.w, self.h = 48, 48
        self.rgb = False
        self.labels = ['angry', 'disgust', 'fear', 'happy', 'neutral', 'sad', 'surprise']

class FaceRecognition:
    def __init__(self):
        self.path_images = "images_db"

这样,您可以通过实例化这两个类来使用这些核心部分的代码。例如:

emotion_detection = EmotionDetection()
face_recognition = FaceRecognition()

然后,您可以使用emotion_detectionface_recognition对象来访问这些核心部分的代码。

该程序文件名为config.py,主要包含两个部分的配置信息。

第一部分是关于情绪检测(emotion_detection)的配置:

  • path_model:情绪检测模型的路径,模型文件名为’model_dropout.hdf5’,该模型用于检测情绪。
  • w,h:将输入图像转换为48x48大小的灰度图像。
  • rgb:图像是否为RGB格式,这里设置为False,表示图像为灰度图像。
  • labels:情绪检测模型可以识别的情绪类别,包括’angry’,‘disgust’,‘fear’,‘happy’,‘neutral’,‘sad’,‘surprise’。

第二部分是关于人脸识别(face_recognition)的配置:

  • path_images:存放人脸图像的文件夹路径,该文件夹用于人脸识别。
5.2 ExamSubjects.py
class ExamSubjects:
    def __init__(self, subjects_file_path):
        self.subjects_file_path = subjects_file_path

    def get_subjects_from_file(self):
        try:
            with open(self.subjects_file_path, 'r') as file:
                subjects = file.readlines()
                subjects = [subject.strip() for subject in subjects]
                return subjects
        except FileNotFoundError:
            print("文件不存在或路径错误。")
            return []

    def display_subjects(self, subjects):
        if subjects:
            print("考试科目:")
            for index, subject in enumerate(subjects, start=1):
                print(f"{index}. {subject}")
        else:
            print("无可用的考试科目信息。")

这个程序文件名为ExamSubjects.py,它包含一个名为ExamSubjects的类。这个类有一个构造函数__init__,它接受一个参数subjects_file_path,用于指定考试科目文件的路径。类中还有两个方法:get_subjects_from_file和display_subjects。

get_subjects_from_file方法用于从文件中获取考试科目信息。它首先尝试打开指定路径的文件,然后逐行读取文件内容并存储在一个列表中。每行内容被去除换行符后存储在列表中。最后,返回这个列表作为考试科目信息。如果文件不存在或路径错误,会打印出错误信息并返回一个空列表。

display_subjects方法用于显示考试科目信息。它接受一个参数subjects,这个参数是一个包含考试科目信息的列表。如果列表不为空,会依次打印出每个考试科目的序号和名称。如果列表为空,会打印出无可用的考试科目信息。

在示例用法部分,首先定义了一个变量subjects_file_path,用于存储考试科目文件的路径。然后,通过调用ExamSubjects类的构造函数,创建了一个exam_subjects对象,并将subjects_file_path作为参数传递进去。接下来,调用exam_subjects对象的get_subjects_from_file方法,将返回的考试科目信息存储在subjects_list变量中。最后,调用exam_subjects对象的display_subjects方法,将subjects_list作为参数传递进去,显示考试科目信息。

5.3 FaceRecognitionSystem.py

这个程序文件名为FaceRecognitionSystem.py,它是一个人脸识别系统的实现。该系统包含以下几个模块:

  1. FaceDetection:人脸检测模块,用于检测图像中的人脸。
  2. ExamSubjects:考试科目显示模块,用于显示考试科目的信息。
  3. StudentManagement:学生信息管理模块,用于管理学生的信息。

FaceRecognitionSystem类是整个系统的主要类,它的构造函数接受三个参数:人脸检测器的路径、考试科目文件的路径和学生信息文件的路径。在初始化过程中,它会分别初始化人脸检测模块、考试科目显示模块和学生信息管理模块。

该类提供了一些方法来操作系统:

  • start_system方法用于启动系统,会打印出系统已启动的提示信息。
  • stop_system方法用于关闭系统,会打印出系统已关闭的提示信息。
  • recognize_face方法用于识别人脸并进行相应操作。它会调用人脸检测模块的方法来检测图像中的人脸,并调用人脸检测模块的方法来提取人脸特征。根据识别结果,可以调用显示考试科目或管理学生信息的方法。
  • display_exam_subjects方法用于显示考试科目信息。它会调用考试科目显示模块的方法来获取考试科目信息,并调用考试科目显示模块的方法来显示考试科目信息。
  • manage_students方法用于管理学生信息。它接受两个参数:操作类型和学生信息。根据操作类型的不同,它会调用学生信息管理模块的不同方法来添加、删除、修改或查询学生信息。

在示例用法部分,首先根据文件路径和参数初始化了一个人脸识别系统对象。然后启动系统,并模拟人脸识别并根据识别结果进行相应操作。接着显示考试科目信息,并进行学生信息管理的示例操作。最后关闭系统。

整个程序的目的是实现一个人脸识别系统,通过调用不同模块的方法来完成人脸检测、考试科目显示和学生信息管理等功能。

5.3 info.py
# -*- coding: utf-8 -*-

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Dialog_info(object):
    def setupUi(self, Dialog_info):
        Dialog_info.setStyleSheet("background-color: rgb(189,215,238)")
        Dialog_info.setObjectName("Dialog_info")
        Dialog_info.resize(394, 500)
        self.button_confirm = QtWidgets.QPushButton(Dialog_info)
        self.button_confirm.setGeometry(QtCore.QRect(260, 452, 112, 34))
        self.button_confirm.setObjectName("button_confirm")
        self.formLayoutWidget = QtWidgets.QWidget(Dialog_info)
        self.formLayoutWidget.setGeometry(QtCore.QRect(40, 50, 331, 400))
        self.formLayoutWidget.setObjectName("formLayoutWidget")
        self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget)
        self.formLayout.setContentsMargins(0, 0, 0, 0)
        self.formLayout.setObjectName("formLayout")
        self.label = QtWidgets.QLabel(self.formLayoutWidget)
        self.label.setObjectName("label")
        self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label)
        self.label_2 = QtWidgets.QLabel(self.formLayoutWidget)
        self.label_2.setObjectName("label_2")
        self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_2)
        self.label_3 = QtWidgets.QLabel(self.formLayoutWidget)
        self.label_3.setObjectName("label_3")
        self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_3)
        self.label_4 = QtWidgets.QLabel(self.formLayoutWidget)
        self.label_4.setObjectName("label_4")
        self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_4)

        self.label_5 = QtWidgets.QLabel(self.formLayoutWidget)
        self.label_5.setObjectName("label_5")
        self.formLayout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_5)
        self.label_6 = QtWidgets.QLabel(self.formLayoutWidget)
        self.label_6.setObjectName("label_6")
        self.formLayout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.label_6)
        self.label_7 = QtWidgets.QLabel(self.formLayoutWidget)
        self.label_7.setObjectName("label_7")
        self.formLayout.setWidget(9, QtWidgets.QFormLayout.LabelRole, self.label_7)
        self.label_8 = QtWidgets.QLabel(self.formLayoutWidget)
        self.label_8.setObjectName("label_8")
        self.formLayout.setWidget(10, QtWidgets.QFormLayout.LabelRole, self.label_8)
        self.label_9 = QtWidgets.QLabel(self.formLayoutWidget)
        self.label_9.setObjectName("label_9")
        self.formLayout.setWidget(11, QtWidgets.QFormLayout.LabelRole, self.label_9)

        self.line_id = QtWidgets.QLineEdit(self.formLayoutWidget)
        self.line_id.setObjectName("line_id")
        self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.line_id)
        self.line_name = QtWidgets.QLineEdit(self.formLayoutWidget)
        self.line_name.setObjectName("line_name")
        self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.line_name)
        self.line_sex = QtWidgets.QLineEdit(self.formLayoutWidget)
        self.line_sex.setObjectName("line_sex")
        self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.line_sex)
        self.line_address = QtWidgets.QLineEdit(self.formLayoutWidget)
        self.line_address.setObjectName("line_address")
        self.formLayout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.line_address)

        self.line_passwords = QtWidgets.QLineEdit(self.formLayoutWidget)
        self.line_passwords.setObjectName("line_passwords")
        self.formLayout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.line_passwords)
        self.line_age = QtWidgets.QLineEdit(self.formLayoutWidget)
        self.line_age.setObjectName("line_name")
        self.formLayout.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.line_age)
        self.line_race = QtWidgets.QLineEdit(self.formLayoutWidget)
        self.line_race.setObjectName("line_race")
        self.formLayout.setWidget(9, QtWidgets.QFormLayout.FieldRole, self.line_race)
        self.line_emotion = QtWidgets.QLineEdit(self.formLayoutWidget)
        self.line_emotion.setObjectName("line_emotion")
        self.formLayout.setWidget(10, QtWidgets.QFormLayout.FieldRole, self.line_emotion)
        self.line_check = QtWidgets.QLineEdit(self.formLayoutWidget)
        self.line_check.setObjectName("line_check")
        self.formLayout.setWidget(11, QtWidgets.QFormLayout.FieldRole, self.line_check)

        self.retranslateUi(Dialog_info)
        QtCore.QMetaObject.connectSlotsByName(Dialog_info)

        Dialog_info.setTabOrder(self.line_id, self.line_name)
        Dialog_info.setTabOrder(self.line_name, self.line_sex)
        Dialog_info.setTabOrder(self.line_sex, self.line_address)

        Dialog_info.setTabOrder(self.line_address, self.line_passwords)
        Dialog_info.setTabOrder(self.line_passwords, self.line_age)
        Dialog_info.setTabOrder(self.line_age, self.line_race)
        Dialog_info.setTabOrder(self.line_race, self.line_emotion)
        Dialog_info.setTabOrder(self.line_emotion, self.line_check)

    def retranslateUi(self, Dialog_info):
        _translate = QtCore.QCoreApplication.translate
        Dialog_info.setWindowTitle(_translate("Dialog_info", "学生信息详情"))
        self.button_confirm.setText(_translate("Dialog_info", "确定"))
        self.label.setText(_translate("Dialog_input", "姓名:"))
        self.label_2.setText(_translate("Dialog_input", "学号*:"))
        self.label_3.setText(_translate("Dialog_input", "性别:"))
        self.label_4.setText(_translate("Dialog_input", "籍贯:"))
        self.label_5.setText(_translate("Dialog_input", "密码:"))
        self.label_6.setText(_translate("Dialog_input", "年龄:"))
        self.label_7.setText(_translate("Dialog_input", "种族:"))
        self.label_8.setText(_translate("Dialog_input", "情绪*:"))
        self.label_9.setText(_translate("Dialog_input", "考勤:"))

这是一个名为info.py的程序文件,它是一个使用PyQt5生成的用户界面代码文件。该文件定义了一个名为Ui_Dialog_info的类,用于设置和显示一个学生信息详情对话框。

该对话框的界面布局由多个标签和文本框组成,用于显示和输入学生的姓名、学号、性别、籍贯、密码、年龄、种族、情绪和考勤等信息。还有一个确定按钮用于提交信息。

该文件中的代码通过调用PyQt5库中的相关函数来设置对话框的样式、大小和布局,并连接了一些信号和槽函数,以实现一些交互功能。

注意:该文件是由PyQt5的UI代码生成器生成的,如果对该文件进行修改,将会丢失所有更改。

5.4 input_dialog.py
# -*- coding: utf-8 -*-

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Dialog_input(object):
    def setupUi(self, Dialog_input):
        Dialog_input.setStyleSheet("background-color: rgb(189,215,238)")
        Dialog_input.setObjectName("Dialog_input")
        Dialog_input.resize(394, 800)
        self.buttonBox = QtWidgets.QDialogButtonBox(Dialog_input)
        self.buttonBox.setGeometry(QtCore.QRect(-20, 700, 341, 32))
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
        self.buttonBox.setObjectName("buttonBox")
        self.label = QtWidgets.QLabel(Dialog_input)
        self.label.setGeometry(QtCore.QRect(60, 110, 81, 18))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(Dialog_input)
        self.label_2.setGeometry(QtCore.QRect(60, 40, 81, 18))
        self.label_2.setObjectName("label_2")
        self.label_3 = QtWidgets.QLabel(Dialog_input)
        self.label_3.setGeometry(QtCore.QRect(60, 180, 81, 18))
        self.label_3.setObjectName("label_3")
        self.label_4 = QtWidgets.QLabel(Dialog_input)
        self.label_4.setGeometry(QtCore.QRect(60, 250, 81, 18))
        self.label_4.setObjectName("label_4")

        self.label_5 = QtWidgets.QLabel(Dialog_input)
        self.label_5.setGeometry(QtCore.QRect(60, 320, 81, 18))
        self.label_5.setObjectName("label_5")
        self.label_6 = QtWidgets.QLabel(Dialog_input)
        self.label_6.setGeometry(QtCore.QRect(60, 390, 81, 18))
        self.label_6.setObjectName("label_6")
        self.label_7 = QtWidgets.QLabel(Dialog_input)
        self.label_7.setGeometry(QtCore.QRect(60, 460, 81, 18))
        self.label_7.setObjectName("label_7")
        self.label_8 = QtWidgets.QLabel(Dialog_input)
        self.label_8.setGeometry(QtCore.QRect(60, 530, 81, 18))
        self.label_8.setObjectName("label_8")
        self.label_9 = QtWidgets.QLabel(Dialog_input)
        self.label_9.setGeometry(QtCore.QRect(60, 600, 81, 18))
        self.label_9.setObjectName("label_9")

        self.line_name = QtWidgets.QLineEdit(Dialog_input)
        self.line_name.setGeometry(QtCore.QRect(130, 100, 181, 31))
        self.line_name.setObjectName("line_name")
        self.line_id = QtWidgets.QLineEdit(Dialog_input)
        self.line_id.setGeometry(QtCore.QRect(130, 30, 181, 31))
        self.line_id.setObjectName("line_id")
        self.line_sex = QtWidgets.QLineEdit(Dialog_input)
        self.line_sex.setGeometry(QtCore.QRect(130, 170, 181, 31))
        self.line_sex.setObjectName("line_sex")
        self.line_address = QtWidgets.QLineEdit(Dialog_input)
        self.line_address.setGeometry(QtCore.QRect(130, 250, 181, 31))
        self.line_address.setObjectName("line_address")

        self.line_passwords = QtWidgets.QLineEdit(Dialog_input)
        self.line_passwords.setGeometry(QtCore.QRect(130, 320, 181, 31))
        self.line_passwords.setObjectName("line_passwords")
        self.line_age = QtWidgets.QLineEdit(Dialog_input)
        self.line_age.setGeometry(QtCore.QRect(130, 390, 181, 31))
        self.line_age.setObjectName("line_age")
        self.line_race = QtWidgets.QLineEdit(Dialog_input)
        self.line_race.setGeometry(QtCore.QRect(130, 460, 181, 31))
        self.line_race.setObjectName("line_race")
        self.line_emotion = QtWidgets.QLineEdit(Dialog_input)
        self.line_emotion.setGeometry(QtCore.QRect(130, 530, 181, 31))
        self.line_emotion.setObjectName("line_emotion")
        self.line_check = QtWidgets.QLineEdit(Dialog_input)
        self.line_check.setGeometry(QtCore.QRect(130, 600, 181, 31))
        self.line_check.setObjectName("line_check")

        self.retranslateUi(Dialog_input)
        self.buttonBox.rejected.connect(Dialog_input.reject)
        QtCore.QMetaObject.connectSlotsByName(Dialog_input)
        Dialog_input.setTabOrder(self.line_id, self.line_name)
        Dialog_input.setTabOrder(self.line_name, self.line_sex)
        Dialog_input.setTabOrder(self.line_sex, self.line_address)

        Dialog_input.setTabOrder(self.line_address, self.line_passwords)
        Dialog_input.setTabOrder(self.line_passwords, self.line_age)
        Dialog_input.setTabOrder(self.line_age, self.line_race)
        Dialog_input.setTabOrder(self.line_race, self.line_emotion)
        Dialog_input.setTabOrder(self.line_emotion, self.line_check)

    def retranslateUi(self, Dialog_input):
        _translate = QtCore.QCoreApplication.translate
        Dialog_input.setWindowTitle(_translate("Dialog_input", "输入用户信息"))
        self.label.setText(_translate("Dialog_input", "姓名:"))
        self.label_2.setText(_translate("Dialog_input", "学号*:"))
        self.label_3.setText(_translate("Dialog_input", "性别:"))
        self.label_4.setText(_translate("Dialog_input", "籍贯:"))

        self.label_5.setText(_translate("Dialog_input", "密码:"))
        self.label_6.setText(_translate("Dialog_input", "年龄:"))
        self.label_7.setText(_translate("Dialog_input", "种族:"))
        self.label_8.setText(_translate("Dialog_input", "情绪*:"))
        self.label_9.setText(_translate("Dialog_input", "考勤:"))

这是一个名为input_dialog.py的程序文件,它是使用PyQt5生成的一个用户界面文件。该文件定义了一个名为Ui_Dialog_input的类,用于设置输入对话框的界面。

界面中包含了一些标签和文本框,用于输入用户的信息。标签包括姓名、学号、性别、籍贯、密码、年龄、种族、情绪和考勤。文本框用于输入对应的信息。

界面还包含了一个按钮框,其中包含了取消和确定按钮,用于取消或确认输入。

整个界面的背景颜色被设置为RGB(189,215,238)。

该文件还定义了setupUi和retranslateUi两个方法,用于设置界面的布局和翻译界面的文本。

最后,通过连接信号和槽的方式,将按钮框的rejected信号与对话框的reject槽函数连接起来,以实现点击取消按钮时关闭对话框的功能。

该文件使用了QtCore、QtGui和QtWidgets模块中的类和方法。

5.5 main.py
# 定义日志文件名称
LOG_FILENAME = 'exam.log'



# 定义日志记录函数
def log_info(exam, student, result):
    with open('./exam.log', 'a') as f:
        f.write(f'{datetime.datetime.now()}\t{exam}\t{student}\t{result}\n')


# 定义数据库连接函数
def connect_database():
    return mysql.connector.connect(
        host='localhost',
        user='root',
        password='ltc19981118',
        database='exam'
    )


# 定义获取考试列表函数
def get_exam_list():
    # 执行SQL查询语句,获取考试列表
    cnx = connect_database()
    cursor = cnx.cursor()
    cursor.execute('SELECT name, start_time, end_time FROM exams')
    exam_list = cursor.fetchall()
    cursor.close()
    cnx.close()

    # 将考试列表转换为二维数组
    exam_list = [[str(cell) for cell in row] for row in exam_list]
    return exam_list


# 定义获取参考学生名单函数
def get_student_list(exam):
    # 执行SQL查询语句,获取参考学生名单
    cnx = connect_database()
    cursor = cnx.cursor()
    cursor.execute('SELECT name FROM students WHERE exam=%s', (exam,))
    student_list = cursor.fetchall()
    cursor.close()
    cnx.close()

    # 将参考学生名单转换为一维数组
    student_list = [str(row[0]) for row in student_list]
    return student_list


# 定义主窗口类
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        # 设置主窗口的标题和大小
        self.setWindowTitle('考生考试管理系统')
        self.setGeometry(100, 100, 800, 700)

        # 创建主窗口的组件
        self.exam_table = QTableWidget()
        self.exam_table.setEditTriggers(QTableWidget.NoEditTriggers)  # 表格不可编辑
        self.exam_table.setColumnCount(3)  # 设置表格列数
        self.exam_table.setHorizontalHeaderLabels(['考试科目', '考试开始时间', '考试结束时间'])
        self.exam_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)  # 表格列宽自适应
        self.exam_table.itemClicked.connect(self.load_student_list)

       ......

这个程序文件是一个考生考试管理系统的主程序。程序首先导入了一些必要的模块和库,然后定义了一些函数和类。

函数部分:

  • log_info(exam, student, result):用于记录日志信息,将考试、学生和结果写入日志文件。
  • connect_database():用于连接数据库。
  • get_exam_list():用于获取考试列表。
  • get_student_list(exam):用于获取参考学生名单。
  • face_detect():用于执行人脸识别。

类部分:

  • MainWindow:主窗口类,继承自QMainWindow。在初始化函数中设置了主窗口的标题和大小,并创建了主窗口的组件。主窗口包括一个考试列表表格、一个参考学生名单表格、一个考生考场人脸比对按钮、一个查看日志按钮、一个学生管理按钮和一个退出系统按钮。还创建了一个右侧的组件,用于显示人脸图片。在加载考试列表函数中,调用了get_exam_list()函数获取考试列表,并将其加载到表格中。在加载参考学生名单函数中,调用了get_student_list(exam)函数获取参考学生名单,并将其加载到表格中。在执行人脸识别函数中,首先打开摄像头,然后使用人脸检测器检测每一帧图像中的人脸,并在图像上绘制人脸框和特征点。最后调用人脸识别函数获取人脸的姓名,并根据姓名判断是否允许通过,并记录日志。

总体来说,这个程序文件实现了一个考生考试管理系统的主要功能,包括显示考试列表、显示参考学生名单、执行人脸识别等。

5.6 make_database.py
import pymysql

class ExamDatabase:
    def __init__(self, host, user, password):
        self.conn = pymysql.connect(
            host=host,
            user=user,
            password=password
        )
        self.cursor = self.conn.cursor()
        self.cursor.execute('CREATE DATABASE IF NOT EXISTS exam')
        self.cursor.execute('USE exam')
        self.create_tables()
        self.insert_data()
        self.conn.commit()
        self.cursor.close()
        self.conn.close()

    def create_tables(self):
        self.cursor.execute('CREATE TABLE IF NOT EXISTS exams ('
                            'id INT PRIMARY KEY AUTO_INCREMENT, '
                            'exam VARCHAR(50) NOT NULL, '
                            'start_time DATETIME NOT NULL, '
                            'end_time DATETIME NOT NULL'
                            ')')
        self.cursor.execute('CREATE INDEX idx_exam ON exams (exam)')

        self.cursor.execute('CREATE TABLE IF NOT EXISTS students ('
                            'id INT PRIMARY KEY AUTO_INCREMENT, '
                            'name VARCHAR(50) NOT NULL, '
                            'gender VARCHAR(10) NOT NULL, '
                            'student_id VARCHAR(50) NOT NULL, '
                            'major VARCHAR(50) NOT NULL, '
                            'class VARCHAR(50) NOT NULL, '
                            'exam VARCHAR(50) NOT NULL, '
                            'FOREIGN KEY (exam) REFERENCES exams(exam) ON DELETE CASCADE'
                            ')')

    def insert_data(self):
        exams = [
            ('Math', '2023-03-27 09:00:00', '2023-03-27 11:00:00'),
            ('Chinese', '2023-03-27 13:00:00', '2023-03-27 15:00:00'),
            ('English', '2023-03-28 09:00:00', '2023-03-28 11:00:00'),
            ('Physics', '2023-03-28 13:00:00', '2023-03-28 15:00:00')
        ]

        students = [
            ('bingbing', 'female', '20230001', 'Mathematics', 'Grade 1', 'Chinese'),
            ('liudehua', 'male', '20230002', 'Mathematics', 'Grade 1', 'Math'),
            ('tom', 'male', '20230003', 'Computer Science', 'Grade 2', 'Math'),
            ('charles', 'male', '20230004', 'Computer Science', 'Grade 2', 'Chinese'),
            ('caocao', 'male', '20230005', 'Physics', 'Grade 3', 'English'),
            ('karo', 'female', '20230006', 'Physics', 'Grade 3', 'English'),
        ]

        for exam in exams:
            self.cursor.execute('INSERT INTO exams (exam, start_time, end_time) VALUES (%s, %s, %s)', exam)

        for student in students:
            self.cursor.execute('INSERT INTO students (name, gender, student_id, major, class, exam) VALUES (%s, %s, %s, %s, %s, %s)', student)

这个程序文件名为make_database.py,它用于创建一个MySQL数据库,并在其中创建两个表格:exams和students。exams表格包含id、exam、start_time和end_time四个列,其中id为自增主键,exam为考试名称,start_time为考试开始时间,end_time为考试结束时间。students表格包含id、name、gender、student_id、major、class和exam七个列,其中id为自增主键,name为学生姓名,gender为学生性别,student_id为学生学号,major为学生专业,class为学生班级,exam为学生所参加的考试。

程序首先连接到MySQL数据库,然后创建名为exam的数据库(如果不存在),并将其设置为当前使用的数据库。接着,程序创建exams表格(如果不存在),并在exam列上创建索引。然后,程序创建students表格(如果不存在),并在exam列上创建外键,参考exams表格的exam列,并设置级联删除。

接下来,程序插入一些数据到exams和students表格中。exams表格插入了四个考试的信息,包括考试名称、开始时间和结束时间。students表格插入了六个学生的信息,包括姓名、性别、学号、专业、班级和所参加的考试。

最后,程序提交更改并关闭数据库连接。

6.系统整体结构

整体功能和构架概述:
该程序是一个基于机器视觉的考场人脸比对和考生信息管理系统。它使用人脸识别技术来进行考生身份验证,并提供了考试科目管理和学生信息管理的功能。

下表整理了每个文件的功能:

文件名功能
config.py配置文件,包含程序的一些配置参数
ExamSubjects.py考试科目管理模块,用于显示和管理考试科目信息
FaceRecognitionSystem.py人脸识别系统模块,用于进行人脸识别和管理考生信息
f_Face_info2.py考生信息输入对话框模块,用于输入考生信息
info.py对话框界面设置模块,用于设置对话框的样式和布局
input_dialog.py输入对话框模块,用于显示和获取用户输入的信息
main.py主程序模块,用于启动系统和处理用户交互
make_database.py数据库管理模块,用于创建和管理数据库
manange.py学生信息管理模块,用于添加、删除、修改和查询学生信息
StudentManagement.py学生信息管理界面模块,用于显示和管理学生信息
ui.py用户界面模块,用于设置和管理用户界面
my_face_recognition\f_face_recognition.py人脸识别模块,用于进行人脸检测和特征提取
my_face_recognition\f_main.py人脸识别主程序模块,用于启动人脸识别系统
my_face_recognition\f_storage.py人脸数据存储模块,用于存储和管理人脸数据

以上是对每个文件功能的简要描述,具体实现细节可能需要查看每个文件的代码。

7.考生脸部图像获取及处理

在考生人脸识别之前,需要先进行考生面部图像的获取.为防止学生替考,要求用二代身份证核验身份,通过拍摄二代身份证上的照片提取面部图像.拍照的角度,拍照时的光线强弱等因素都会带来干扰,对照片有影响.加上JPEG格式压缩的图像,其本身也有一定程度的失真.给人脸识别增加难度.这些因素没法改变,因此只能通过选择合适的算法,并对其进行优化,在一定程度上消除不利因素.
人脸识别算法对照片中人脸的标准化要求很高,在进行人脸识别之前,要对原始的照片进行预处理.预处理之后的照片应该大小一样,人脸的位置也应该保持一致.
预处理流程步骤:首先对照片进行旋转,旋转到两个眼睛处在同一条水平线上即可.接着对照片进行裁剪,根据人脸图像的宽度是标准照片中两个眼睛之间的距离的2倍进行裁剪,两个眼睛的位置确定下来,其他器官的位置也就跟着确定了,一张标准化的人脸图像就生成了.接着对图像进行灰度归一化处理,为了方便统一处理不同灰度值的图像,图像的灰度值和方差需要被设定到一个合理的范围之内.
在这里插入图片描述

8.面部特征提取

目前面部特征提取方法有:基于几何特征面部识别方法、基于BP神经网络面部识别方法、基于LBP的面部识别方法等叫.每种方法都各有适用场景及优缺点,考虑到平台的兼容性,硬件资源配置低的因素,本文采用PCA (Principal ComponentAnalysis)算法.
PCA即主成分分析,是一种常用的数据降维方法.它可以通过线性变换将面部原始数据变换为一组各维度线性无关表示,以此来提取数据的主要特征分量.PCA算法步骤P;
(1)将面部图像采集到数据库中.这一步先进行图像预处理,然后再将数据按列组成n*n矩阵X.
(⑵)求特征协方差矩阵.将X的每一行进行零均值化处理,求出协方差矩阵C,进而求出协方差矩阵C的特征值及对应的特征向量.
(3)对面部特征进行降维.将面部特征向量按照对应特征值大小从上到下按行进行排列成矩阵,取前k行组成矩阵P,Y=PX即为降维到k 维后的特征向量.
在这里插入图片描述

9.人脸比对算法

Haar特征与积分图像

在对人脸进行检测训练前,要先正确表示出人脸,选择正确的人脸特征和正确的人脸表示方法是后面进一步检测人脸和进行人脸识别的基础。很多研究者提出了一些表征人脸的特征,其中由Viola提出的利用人脸图像的灰度值来表示人脸是很方便和准确的,人脸图像上面有明显的灰度差,比如眼睛就与附近肤色的灰度相差较大,Haar特征39]可以用来代表人脸图像中像素相似局部就是黑白像素块的特征,主要描述两个相邻矩形区域的灰度差,是一种简单的矩形特征。如图所示,Haar特征主要分为四类: a、边缘特征、b、线性特征、c、中心环绕特征以及d、对角线特征,其他特征都是有这些图像旋转变化的来的,所以下图3-2所示的四种基本特征:

在这里插入图片描述

其中 feature,图像中矩形个数用N表示,RectSum(,)是矩形’所围成图像的灰度积分°为此矩形的权重,灰度积分RectSum(r,)则表示图像中矩形”所围成的第i个矩形内所有像素灰度值的总和。
用Haar特征表示人脸是很方便的,也很容易实现,但是单一的 Haar特征也是有缺点的,它只能从一个方向表示出相应的特征,是线性的,没有相对的位置,在判断的过程中不容易判断准确,因此,我们在定义人脸某一个局部特征的时候一般都用两个以上的Haar 特征表示,如图所示,所以,当我们表示人眼的时候就同时用同一区域同时出这两个特征,如下图所示:
在这里插入图片描述

如图所示其中,图a为原始图像,图b是根据横向的眼睛以及和眼睛下方肤色的不同来区分黑白像素块的,图c是根据两个眼睛与中间鼻子部分的灰度值差距较大来表示明睛的.所以眼瞎可以由这两个特征来表示。其他部位表示的方法以此类推。

AdaBoost级联算法

Viola和 Jones将AdaBoost级联算法成功的应用到人脸检测中,很大的提高了基于AdaBoost算法的人脸检测的检测效率,经过积分图计算后,在一个24×24的小窗口内,一共有 45000个Haar 特征,每个特征都在一定程度上能够对人脸和非人脸有所判断,即每个特征都相当于一个弱分类器。
级联分类器是一种强分类器构造,通过多次筛选剔除不好的特征,在人脸检测中应用以后,提高了检测率,它的结构如下图所示
在这里插入图片描述

AdaBoost级联分类器是先用强分类器除去大部分错误的样本来,由于强分类器与弱分类器对样本正确与否的敏感度不同,我们把特征比较少的分类器放在前段,把特征比较多的分类器放在后端,又粗到细逐层递进,利用更加严格的强匪类器把与人脸非常接近的样本筛选出去,最终达到判定人脸的效果。

PCA人脸识别

在结合人脸识别考生身份认证系统中,考生在注册时只提供了一张人脸图片,在人脸识别的过程中就面临单样本的问题,想要依靠一张人脸来识别考生的身份是本系统需要解决的一大难题。本文依靠奇异值分解用-一张人脸图片变换出多个人脸图片,提取特征,然后与后验图片进行对比,通过改进的 PCA人脸识别算法判断人脸是否是本人的。整个人脸识别过程包含三个部分:图像处理、人脸检测、人脸识别。前面已经详细介绍了人脸检测的方法,下面就利用奇异值分解法处理图像,然后识别人脸的过程进行描述。
对人脸图像进行处理和人脸检测后,就要对人脸进行识别。
(1)由于只能得到一个目标人脸样本,无法像多样本那样进行多次训练就能得到较高的检测匹配率,这就需要我们只能从单一样本出发进行匹配,以完成人脸的检测流程。这就需要在缺少大量样本训练的条件下,还要保证匹配成功率。而且单样本问题在现实生活中也是常有遇到,更值得针对此类问题提出一个中行之有效的检测方法。
(2)原始PCA方法的抗干扰性较差,容易受光照条件,局部表情变化影响全局信息的反应等因素的影响,导致脸部信息提取失真,最终导致无法成功检测出目标人脸。
鉴于以上这些原始PCA方法所具有的不足,本章针对其提出了新的一种解决方案,通过演示验证了本文提出的ISPCA人脸检索理念的可行性,以弥补原始PCA的应用局限性。

奇异值分解

在校园一卡通中存有人脸图像,可以用来进行人脸识别,但是由于其样本数量的缺少就使得识别遇到了一些瓶颈:能够提取的特征信息不多,不能够使得识别特别地准确;在识别的过程中很多简单方便的算法不能使用等。很多研究者就开始研究单样本下人脸识别的方法:用单样本生成多个样本和对单样本图像进行处理,突出样本人脸的特征或者利用单样本构建人脸的3D模型然后生成各种姿势的人脸。这样处理后,就可以用很多算法进行单样本条件下人脸识别了。
小样本问题l等对于人脸识别是经常遇到的问题,这主要是因为人脸素材数量上的局限性,或者无法达到可检测出结果的程度,这都局限了人脸识辨的应用性。如果把小样本的容量限定为1,就产生了一个新的问题,就是只具有一个训练样本,即单样本问题。
目前单样本人脸识别方法有两类:一类是根据单样本得到新副本,扩充样本空间,将单样本问题转换为常见的多样本问题,依靠样本扩张,从而可以解决问题,目前已有具体的操作方法例如独立元素分析法和光照模拟方法等。另一-类方法不通过样本扩容,而是直接操作该样本,将突出的人脸特征从较为普遍的人脸特征干扰中提取出来以强化差异性。

10.系统整合

下图完整源码&环境部署视频教程&自定义UI界面

在这里插入图片描述

参考博客《基于机器视觉的考场人脸比对&考生信息管理系统》

11.参考文献


[1]江琨,郑禄,帖军.基于 LBP 和 PCA 算法的智能人脸识别[J].计算机与数字工程.2016,(10).DOI:10.3969/j.issn.1672-9722.2016.10.039 .

[2]赵鑫,汪维家,曾雅云,等.改进的模块PCA人脸识别新算法[J].计算机工程与应用.2015,(2).DOI:10.3778/j.issn.1002-8331.1303-0095 .

[3]张晓璐.基于PCA的人脸识别技术的研究[J].辽宁科技学院学报.2014,(4).DOI:10.3969/j.issn.1008-3723.2014.04.015 .

[4]曾健平,邵艳洁.Android系统架构及应用程序开发研究[J].微计算机信息.2011,(9).1-3.

[5]刘海建.基于OpenCV的人脸辨识算法研究与实现[J].集美大学.2014.

[6]林启亮.基于OpenCV2.x的车牌识别系统设计与实现[J].厦门大学.2013.

[7]王艳红.基于OpenCV的运动目标检测与跟踪算法的研究[J].杭州电子科技大学.2013.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值