基于PyQT+FaceNet卷积神经网络实现的学生人脸识别考勤系统
项目源码获取方式见文章末尾! 回复暗号:13,免费获取600多个深度学习项目资料,快来加入社群一起学习吧。
**《------往期经典推荐------》**
项目名称
1.【MobileViT模型实现图像分类】
2.【卫星图像道路检测DeepLabV3Plus模型】
3.【GAN模型实现二次元头像生成】
4.【CNN模型实现mnist手写数字识别】
5.【fasterRCNN模型实现飞机类目标检测】
6.【CNN-LSTM住宅用电量预测】
7.【VGG16模型实现新冠肺炎图片多分类】
8.【AlexNet模型实现鸟类识别】
9.【DIN模型实现推荐算法】
10.【FiBiNET模型实现推荐算法】
11.【钢板表面缺陷检测基于HRNET模型】
…
1. 项目简介
该项目基于PyQT和FaceNet卷积神经网络,实现了学生人脸识别考勤系统,旨在通过人脸识别自动化学生考勤,减少人工干预,提高效率。系统采用MTCNN算法对视频流中的人脸进行实时检测,并使用FaceNet模型提取人脸的高维特征嵌入,以实现精确的身份匹配。FaceNet通过将人脸图像转化为128维的特征向量,使得系统能够将捕获到的人脸与数据库中的学生人脸数据进行比对,识别出相应的学生并自动更新数据库中的考勤记录。该系统与SQLite数据库集成,用于存储学生信息及其对应的人脸特征数据,并通过PyQT构建了用户友好的界面,使用户能够方便地管理考勤记录。本系统通过深度学习模型的实际应用,提供了智能化的考勤解决方案,简化了课堂管理和记录维护的流程。
2.技术创新点摘要
该项目基于FaceNet和MTCNN,主要创新点集中在多项技术的集成与实际应用的优化。具体创新点如下:
- MTCNN与FaceNet集成:该项目集成了MTCNN(多任务卷积神经网络)用于人脸检测和FaceNet用于人脸特征提取。MTCNN能快速且准确地在实时视频流中检测出人脸区域,而FaceNet则通过预训练模型,将人脸图像转化为128维的嵌入向量,能够在大规模人脸数据中实现高效的身份识别。这种双网络架构的组合,既保证了检测精度,又实现了高效、精准的人脸识别。
- 实时人脸识别与考勤系统结合:通过摄像头实时获取人脸图像并进行检测和识别,系统能够即时对比学生人脸与数据库中存储的特征向量,完成考勤数据的自动化更新。通过将视频流中的最大人脸识别并锁定识别框,该系统能有效避免多重人脸干扰问题,确保准确性。
- 数据库与嵌入特征的联动:项目采用SQLite数据库存储学生的身份信息及其人脸特征向量,实时识别后自动将学生的考勤状态写入数据库。特别地,系统不仅支持对人脸的识别,还通过预先计算的人脸嵌入特征,提升了匹配速度,解决了大规模数据的识别性能瓶颈。
- 人脸预处理与增强:在人脸检测和识别前,项目中对人脸图像进行了预白化(prewhitening)处理,去除冗余信息以提升模型的识别准确性。此外,还通过裁剪和缩放操作,将检测到的人脸规范化为统一尺寸,保证模型输入数据的质量一致性。
- 用户友好性与扩展性:使用PyQT搭建了图形化用户界面,使得用户可以轻松操作摄像头、拍照、添加或删除数据库记录等功能,提升了系统的易用性和扩展性。这种设计不仅提高了项目的实用性,也为系统未来的功能扩展打下了基础。
3. 数据集与预处理
本项目的人脸识别考勤系统使用的数据集主要来源于学生的实际人脸图像,这些图像通过摄像头实时采集,并存储于本地数据库中。该数据集的特点是每个学生对应多个不同角度和表情的图像,增强了识别的鲁棒性。同时,项目在使用FaceNet模型前,需要对这些人脸图像进行一系列的预处理,以确保模型输入的一致性和识别精度。
数据预处理流程:
- 人脸检测:首先,使用MTCNN(多任务卷积神经网络)在图像中检测人脸区域。该步骤自动检测并裁剪出包含人脸的部分,过滤掉背景和无关信息。MTCNN能有效处理不同角度和光照条件下的人脸,并在视频流中实时跟踪。
- 图像裁剪与缩放:为保证每张人脸图像输入模型时具有相同的尺寸,系统对检测到的人脸进行裁剪和缩放操作,将其规范化为统一大小(如160x160像素)。这种操作保证了输入数据的一致性,从而提升模型在不同图像尺寸下的泛化能力。
- 预白化(Prewhitening) :在将图像输入FaceNet模型之前,项目对图像进行了预白化处理。通过计算图像的均值和标准差,去除冗余信息,使图像数据分布更加均匀。该步骤能够有效提升模型的训练和推理效果,避免因光照变化、对比度差异等外部因素导致的识别精度下降。
- 特征提取:使用预训练的FaceNet模型,将每张人脸图像转化为128维的嵌入向量。每个嵌入向量代表该人脸的特征信息,确保了高维特征空间中人脸之间的距离能够反映出其相似性。这为后续的人脸匹配和身份识别奠定了基础。
4. 模型架构
本项目采用的模型结构基于FaceNet,一个深度卷积神经网络(CNN),用于人脸识别任务。FaceNet通过将输入的人脸图像映射到一个128维的欧几里得空间,并利用这种特征向量来度量不同人脸之间的相似性。模型的结构逻辑如下:
- 输入层:输入图像首先经过一系列预处理步骤(如裁剪、缩放、预白化),统一为固定尺寸(160x160像素)的三通道RGB图像,输入到模型中。
- 卷积层(Conv Layers) :多层卷积操作用于提取局部图像特征。假设输入图像为
X
,卷积层的输出为: - Z ( l ) = f ( W ( l ) ∗ X ( l − 1 ) + b ( l ) ) Z^{(l)} = f(W^{(l)} * X^{(l-1)} + b^{(l)}) Z(l)=f(W(l)∗X(l−1)+b(l))
- 其中,W(l)为第 lll 层的卷积核,∗*∗ 表示卷积操作,f(⋅)为激活函数,通常采用ReLU激活函数,b(l)为偏置项。
- 池化层(Pooling Layers) :池化操作(通常为最大池化)用于减少特征图的尺寸,并增强模型的平移不变性。对于每个特征图块,最大池化计算如下:
- P ( l ) = max ( Z ( l ) ) P^{(l)} = \max(Z^{(l)}) P(l)=max(Z(l))
- 这一步骤可以减少特征图的大小,同时保留主要特征。
- 全连接层(Fully Connected Layers) :卷积和池化层提取的特征最终通过全连接层进行融合。全连接层的计算如下:
- h ( l ) = W ( l ) ⋅ Z ( l − 1 ) + b ( l ) h ( l ) = W ( l ) ⋅ Z ( l − 1 ) + b ( l ) h ( l ) = W ( l ) ⋅ Z ( l − 1 ) + b ( l ) h(l)=W(l)⋅Z(l−1)+b(l)h^{(l)} = W^{(l)} \cdot Z^{(l-1)} + b^{(l)}h(l)=W(l)⋅Z(l−1)+b(l) h(l)=W(l)⋅Z(l−1)+b(l)h(l)=W(l)⋅Z(l−1)+b(l)h(l)=W(l)⋅Z(l−1)+b(l)
- 其中,W(l)W^{(l)}W(l) 和 b(l)b^{(l)}b(l) 分别为权重矩阵和偏置向量,输出为下一层输入。
- 嵌入层(Embedding Layer) :FaceNet的核心是将输入人脸图像转换为128维的嵌入向量。通过一个最后的全连接层,输出特征向量 e∈R128e \in \mathbb{R}^{128}e∈R128,代表人脸的高维特征。
- e = f ( W e ⋅ Z + b e ) e = f ( W e ⋅ Z + b e ) e = f ( W e ⋅ Z + b e ) e=f(We⋅Z+be)e = f(W_e \cdot Z + b_e)e=f(We⋅Z+be) e=f(We⋅Z+be)e=f(We⋅Z+be)e=f(We⋅Z+be)
- 这些嵌入向量用于后续的人脸比对,通过计算两个嵌入向量的欧氏距离 ddd 来度量人脸之间的相似度:
- d ( x 1 , x 2 ) = ∣ ∣ e 1 − e 2 ∣ ∣ d ( x 1 , x 2 ) = ∣ ∣ e 1 − e 2 ∣ ∣ d ( x 1 , x 2 ) = ∣ ∣ e 1 − e 2 ∣ ∣ d(x1,x2)=∣∣e1−e2∣∣d(x_1, x_2) = ||e_1 - e_2||d(x1,x2)=∣∣e1−e2∣∣ d(x1,x2)=∣∣e1−e2∣∣d(x1,x2)=∣∣e1−e2∣∣d(x1,x2)=∣∣e1−e2∣∣
- 当距离小于某个阈值时,判定两个人脸为相同。
- Triplet Loss:为了优化模型,使用三元组损失(Triplet Loss)。损失函数由锚点样本 xax_axa、正样本 xpx_pxp(与锚点同一人)和负样本 xnx_nxn(不同人)组成。损失函数为:
- L = m a x ( 0 , ∣ ∣ f ( x a ) − f ( x p ) ∣ ∣ 2 − ∣ ∣ f ( x a ) − f ( x n ) ∣ ∣ 2 + α ) L = max ( 0 , ∣ ∣ f ( x a ) − f ( x p ) ∣ ∣ 2 − ∣ ∣ f ( x a ) − f ( x n ) ∣ ∣ 2 + α ) L = m a x ( 0 , ∣ ∣ f ( x a ) − f ( x p ) ∣ ∣ 2 − ∣ ∣ f ( x a ) − f ( x n ) ∣ ∣ 2 + α ) L=max(0,∣∣f(xa)−f(xp)∣∣2−∣∣f(xa)−f(xn)∣∣2+α)L = \max\left( 0, ||f(x_a) - f(x_p)||^2 - ||f(x_a) - f(x_n)||^2 + \alpha \right)L=max(0,∣∣f(xa)−f(xp)∣∣2−∣∣f(xa)−f(xn)∣∣2+α) L=max(0,∣∣f(xa)−f(xp)∣∣2−∣∣f(xa)−f(xn)∣∣2+α)L=max(0,∣∣f(xa)−f(xp)∣∣2−∣∣f(xa)−f(xn)∣∣2+α)L=max(0,∣∣f(xa)−f(xp)∣∣2−∣∣f(xa)−f(xn)∣∣2+α)
- 其中,α 是一个超参数,用于控制正负样本之间的间隔。
2) 模型的整体训练流程
训练流程主要包括以下步骤:
- 数据预处理:首先通过MTCNN检测人脸,进行图像裁剪和缩放操作,统一所有输入图像的尺寸。然后通过预白化处理,去除冗余信息,减少外界光照、对比度等因素的干扰。
- 构建三元组(Triplet)样本:每次训练选取一个三元组样本,包括锚点样本(Anchor)、正样本(Positive)和负样本(Negative)。锚点样本和正样本是同一个人不同的照片,而负样本是其他人的照片。
- 前向传播:输入预处理后的图像,通过FaceNet模型,提取128维的嵌入向量。
- 计算Triplet Loss:使用三元组损失函数计算模型的损失,确保正样本和锚点样本的距离尽量小,而锚点样本和负样本的距离尽量大。训练时,优化的目标是最小化三元组损失。
- 反向传播与优化:通过反向传播算法更新模型的权重,采用Adam或其他优化器优化损失函数。训练过程中,模型不断学习如何在高维特征空间中更好地区分不同人的人脸。
评估指标
评估模型性能的主要指标包括:
- 欧氏距离(Euclidean Distance) :衡量不同人脸特征向量之间的相似度。相同人脸的特征向量距离应小于预设的阈值,不同人脸的距离应大于阈值。
- 准确率(Accuracy) :通过交叉验证,评估模型在测试集上的准确率,计算识别正确的比例。
- ROC曲线与AUC值:通过计算Receiver Operating Characteristic(ROC)曲线和曲线下的面积(AUC),衡量模型的分类能力。
5. 核心代码详细讲解
1. 人脸检测与预处理
文件:get_face.py
bounding_boxes, _ = align.detect_face.detect_face(img, minsize, pnet, onet, rnet, threshhold, factor)
解释:
bounding_boxes
是通过MTCNN
检测到的所有人脸的边界框。该函数使用pnet
、rnet
和onet
三个网络进行级联检测。align.detect_face.detect_face
是 MTCNN 中的主要函数,负责从输入图像中检测人脸。minsize
定义了检测的最小人脸大小。threshhold
和factor
控制人脸检测的置信度阈值和图像金字塔缩放因子。- 返回的
bounding_boxes
包含每个检测到的边界框的坐标(左上角和右下角)。
cropped = img[bb[1]:bb[3], bb[0]:bb[2], :] # 对角坐标
cropped = cv2.resize(cropped, (imgae_size, imgae_size), interpolation=cv2.INTER_AREA)
prewhitened = facenet.prewhiten(cropped)
解释:
cropped
从原始图像中提取人脸区域,使用边界框bb
的坐标进行切割。bb
是整数型数组,存储了边界框的上下左右坐标。cv2.resize
将裁剪后的图像缩放到模型需要的固定大小image_size
(例如160x160像素)。prewhitened
通过facenet.prewhiten
对裁剪后的图像进行预白化处理。预白化通过去除图像的均值和标准差,使图像具有标准的分布,增强了模型的泛化能力。
2. 人脸特征提取
文件:get_face.py
和 face_recognition.py
facenet.load_model(model)
images_placeholder = tf.get_default_graph().get_tensor_by_name("input:0")
embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0")
phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0")
解释:
facenet.load_model(model)
加载预训练的 FaceNet 模型。model
是模型的文件路径,包含了预训练权重。images_placeholder
是模型输入的占位符,用于接收预处理后的图像输入。embeddings
是模型输出的128维人脸嵌入向量,用于表示输入图像的高维特征。phase_train_placeholder
表示训练阶段标志位,当模型在推理(预测)时,这个占位符设置为False
。
compare_emb = sess.run(embeddings, feed_dict={images_placeholder: images, phase_train_placeholder: False})
解释:
sess.run(embeddings, feed_dict={...})
是在 TensorFlow 会话中运行图,输入数据images
,输出128维的特征嵌入compare_emb
。compare_emb
保存了每张人脸图像的嵌入向量。这些向量用于后续的比较,判断两张人脸是否相似。feed_dict
用于向占位符传入数据,这里传入的images
是一批预处理过的图像。
3. 人脸识别主循环
文件:face_recognition.py
while True:ret, frame = capture.read()frame = cv2.flip(frame, 1)rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)mark, bounding_box, crop_image = self.load_and_align_data(rgb_frame, 160)
解释:
capture.read()
从摄像头实时获取视频帧,ret
表示读取是否成功,frame
是捕获的帧。cv2.flip(frame, 1)
水平翻转帧图像,确保人脸与镜像一致。cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
将帧图像的颜色空间从 BGR 转换为 RGB,这是因为 OpenCV 读取图像时默认是 BGR 格式,而大多数深度学习模型使用 RGB。self.load_and_align_data(rgb_frame, 160)
调用自定义函数对视频流中的帧进行人脸检测、对齐和裁剪,返回检测标志mark
、边界框bounding_box
和裁剪后的图像crop_image
。
if mark:emb = sess.run(embeddings, feed_dict={images_placeholder: crop_image, phase_train_placeholder: False})dist = np.sqrt(np.sum(np.square(np.subtract(emb[i, :], compare_emb[j, :]))))
解释:
if mark:
表示如果检测到有效人脸,开始计算嵌入向量。sess.run(embeddings, feed_dict={...})
再次运行嵌入向量计算,将裁剪后的人脸图像crop_image
输入模型,输出128维特征向量emb
。np.sqrt(np.sum(np.square(np.subtract(emb[i, :], compare_emb[j, :]))))
计算欧氏距离,用于比较当前视频帧中的人脸与数据库中存储的人脸特征向量的相似度。emb[i, :]
表示当前人脸的特征,compare_emb[j, :]
表示数据库中的人脸特征。
4. 考勤系统更新
文件:face_recognition.py
if find_obj[0] != "Unknow":self.sqlite.update_checkwork(self.sqlite.DB_STUDENTCHECKWORK_PATH, checkwork, find_obj[0])
解释:
find_obj[0]
是识别到的学生的学号,如果识别出的结果不是“Unknow”,说明匹配成功。self.sqlite.update_checkwork
调用 SQLite 数据库的更新函数,将识别出的学生学号写入考勤记录表DB_STUDENTCHECKWORK_PATH
。
5. Triplet Loss的实现
文件:facenet.py
pos_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, positive)), 1)
neg_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, negative)), 1)
basic_loss = tf.add(tf.subtract(pos_dist, neg_dist), alpha)
loss = tf.reduce_mean(tf.maximum(basic_loss, 0.0))
解释:
pos_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, positive)), 1)
计算锚点(anchor)与正样本(positive)之间的欧氏距离。neg_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, negative)), 1)
计算锚点与负样本(negative)之间的欧氏距离。basic_loss = tf.add(tf.subtract(pos_dist, neg_dist), alpha)
计算三元组损失的基本形式,即通过加上一个边距参数alpha
,确保负样本与锚点之间的距离大于正样本与锚点之间的距离。loss = tf.reduce_mean(tf.maximum(basic_loss, 0.0))
取所有样本的平均损失,如果basic_loss
小于0,则置为0。
6. SQLite 数据库集成
文件:Sqlite_UI.py
ret = self.sf.insert(self.db_path, self.table, lineEdit_data)
解释:
self.sf.insert
调用数据库插入函数,将lineEdit_data
插入到指定表中。self.db_path
是 SQLite 数据库的路径,self.table
是要更新的表名,lineEdit_data
是要插入的数据。
ret = self.sf.executeCMD(self.db_path, str_sql)
解释:
self.sf.executeCMD
执行 SQL 命令,str_sql
是自动生成的 SQL 查询语句,用于获取表中的数据。
6. 模型优缺点评价
模型优点:
- 高精度人脸识别:该项目采用FaceNet模型,通过128维的特征向量将人脸进行高效匹配,具有极高的精度,能够在大规模数据中准确识别不同个体的人脸。
- 实时检测与识别:集成MTCNN算法进行实时人脸检测,能够快速捕获和对齐人脸,适用于摄像头实时视频流的处理,保证了系统的及时响应能力。
- 自动化考勤:将人脸识别与考勤系统结合,自动更新数据库,极大地减少了人工操作,提升了考勤管理的效率。
- 预处理增强:通过预白化处理去除图像冗余信息,增强模型的鲁棒性,使其在不同光照条件和复杂背景下仍能保持较高的识别率。
模型缺点:
- 对遮挡的敏感性:FaceNet在处理部分遮挡或光照极端变化时可能表现不佳。因为模型依赖于清晰的特征提取,当人脸部分遮挡或光线条件差时,识别准确度会下降。
- 硬件依赖:由于模型的复杂性和实时视频处理的需求,系统对硬件资源的要求较高。在低性能设备上可能导致较高的延迟。
- 有限的数据增强:项目中的数据增强方法(如旋转、裁剪等)较为有限,未包含如亮度调整、噪声添加等更多样化的数据增强策略,这在处理复杂的真实场景时可能存在不足。
模型改进方向:
- 结构优化:可以尝试集成更轻量化的模型(如MobileNet或EfficientNet),在保证识别精度的前提下,提升实时性能并降低对硬件的依赖。
- 超参数调整:在训练过程中,可以进一步优化超参数,如学习率、正则化项、Triplet Loss中的边距参数等,以提升模型的收敛速度和最终性能。
- 数据增强:引入更丰富的图像增强方法,如亮度、对比度、噪声等,以提升模型在复杂环境下的泛化能力,增强模型对不同光照、遮挡等情况的鲁棒性。
- 多任务学习:可以在现有的人脸识别任务中增加年龄、性别预测等多任务学习,提升模型的多维度能力。
👍感谢小伙伴们点赞、关注! 如有其他项目需求的,可以在评论区留言,抽空制作更新!
✌粉丝福利:点击下方名片↓↓↓ ,回复暗号:13,免费获取600多个深度学习项目资料,快来加入社群一起学习吧。