一、人脸识别技术
人脸识别目前有两种主要的使用场景:
- 身份验证:也就是客户端已经知道你是谁了,现在需要通过人脸来验证你是你。
- 人脸登录:一般在局部范围内,比如小区门禁,办公楼门禁,公司门禁等,特点就是先录入,然后刷脸开门,实际上每一个刷脸设备一定绑定了一个GroupID,这样可以缩小比对范围。
- 刷脸支付:这个技术门槛就很高了,即要求高准确性,又要求高算力支持。
现在的主流技术已经普遍转向了深度学习,尤其是基于卷积神经网络(CNN)等架构的深度学习模型。
1. 人脸检测:从 Haar 到 CNN
在人脸识别系统中,首先要进行的步骤是找到输入图像中存在的人脸。这一部分传统上使用 Haar 特征和 Adaboost 分类器来完成,但在现代系统中,通常会采用深度学习的对象检测方法,例如基于 CNN 的 MTCNN(Multi-task Cascaded Convolutional Neural Networks),或者是更为先进的 RetinaFace 模型。
MTCNN 作为一种经典的人脸检测方法,其工作原理是使用多阶段的卷积网络来实现人脸的逐步检测与精细定位。首先,MTCNN 使用一个粗略的候选网络来快速找到可能的人脸区域,然后通过两个后续的更精细的网络逐步精确定位和过滤结果。这种方法的优势在于它的多任务学习方式,同时进行人脸检测和人脸关键点的定位,使其在姿态和光照变化中保持较高的精度。
以下是使用 MTCNN 进行人脸检测的代码示例:
from mtcnn.mtcnn import MTCNN
import cv2
import matplotlib.pyplot as plt
# 读取输入图像
image_path = 'example.jpg'
image = cv2.imread(image_path)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 初始化 MTCNN 检测器
detector = MTCNN()
# 进行人脸检测
faces = detector.detect_faces(image_rgb)
# 在图像中绘制检测到的人脸
for face in faces:
x, y, width, height = face['box']
cv2.rectangle(image_rgb, (x, y), (x + width, y + height), (0, 255, 0), 2)
# 显示结果
plt.imshow(image_rgb)
plt.axis('off')
plt.show()
在上述代码中,我们使用了 MTCNN 库来实现对人脸的检测。它能够在输入的图像中找到所有人脸,并且绘制出相应的边框。
2. 特征提取:使用深度学习网络提取人脸特征
人脸检测完成之后,接下来需要提取人脸的特征。在深度学习时代,常用的方法是使用卷积神经网络来进行特征提取。ResNet、Inception 等架构非常适合用于这一目的,因为它们在处理图像特征的提取方面表现优异。对于工业级别的应用,FaceNet 和 ArcFace 是目前常用的两种人脸特征提取方法。
FaceNet 使用了一种叫做 triplet loss
的损失函数来训练网络。该损失函数的核心思想是将同一人的不同人脸映射到特征空间中彼此靠得更近的位置,而将不同人的特征映射得尽可能远。这种方法确保提取的特征具有良好的区分能力。
ArcFace 是另一种更为先进的模型,它通过增加角度损失(Angular Margin Loss)来强化类别之间的可分性,从而使得模型在边界上具有更好的判别能力。
下面是一个使用 FaceNet 进行特征提取的代码示例:
from keras.models import load_model
import numpy as np
from PIL import Image
import cv2
# 加载预训练的 FaceNet 模型
model = load_model('facenet_keras.h5')
# 图像预处理函数
def preprocess_image(image_path):
image = Image.open(image_path)
image = image.resize((160, 160))
image_array = np.asarray(image)
image_array = (image_array - 127.5) / 128.0
image_array = np.expand_dims(image_array, axis=0)
return image_array
# 提取人脸特征
image_path = 'face.jpg'
image = preprocess_image(image_path)
feature_vector = model.predict(image)
print('提取的人脸特征向量为:', feature_vector)
在这个例子中,我们使用了预训练的 FaceNet 模型,该模型能够从输入图像中提取长度为 128 或 512 的特征向量。这个特征向量是用来进行后续匹配的基础。
3. 特征匹配与分类
最后一步是将提取的特征与数据库中的人脸特征进行匹配。这个过程可以使用简单的距离度量方法,例如欧氏距离,来计算输入人脸与数据库中人脸之间的相似度。阈值判断是最常用的匹配方式,找到距离最小且小于设定阈值的人脸即认为是识别成功。
如果我们使用 FaceNet 提取的 128 维度特征向量,那么匹配的过程可以通过计算输入人脸与数据库中所有人脸的欧氏距离来实现。如下代码:
import numpy as np
# 计算两个特征向量之间的欧氏距离
def calculate_distance(vector1, vector2):
return np.linalg.norm(vector1 - vector2)
# 假设数据库中已有的人脸特征向量
database_feature = np.random.rand(1, 128)
# 输入图像特征向量
input_feature = feature_vector
# 计算距离并判断是否匹配
distance = calculate_distance(input_feature, database_feature)
threshold = 0.8 # 设定阈值
if distance < threshold:
print('匹配成功')
else:
print('匹配失败')
在这个例子中,我们随机生成了一个数据库特征向量,并将输入图像特征与其进行比较。设定一个合理的阈值可以帮助系统在匹配的过程中过滤掉错误匹配的情况。
4、支付宝刷脸支付
支付宝的刷脸支付系统在背后依赖于深度学习模型。整个系统分为以下几个阶段:
- 人脸检测和关键点识别:使用类似于 MTCNN 或者 RetinaFace 的检测网络来定位人脸和人脸的关键点(例如眼睛、鼻子、嘴巴的坐标)。
- 特征提取:通过一个经过优化的 CNN 网络来提取人脸的特征向量。在支付宝系统中,提取的特征一般会进一步进行压缩和量化,以提高特征存储和比较的效率。
- 匹配与验证:提取的特征会与用户数据库中的特征进行匹配,采用相似度度量的方法确保识别的准确性。如果相似度达标,就完成支付验证。
支付宝对系统的鲁棒性要求非常高,因为支付安全性至关重要。因此,他们会使用多个不同的模型进行联合判断,以确保即便在光照、姿态或者表情变化较大的情况下,依然能够准确地进行识别。更为复杂的策略还包括对视频流中人脸进行多帧分析,从而避免假体攻击(例如使用照片或者视频来欺骗系统)。
地铁闸机的人脸识别
地铁闸机的人脸识别系统虽然在目标上与支付系统类似,但其实现细节有所不同。对于这种场景,速度比精度更加重要,因为需要快速响应大量乘客的请求。通常,这些系统会使用优化的 YOLO(You Only Look Once)等实时目标检测模型来进行人脸检测,并结合一个轻量化的 CNN 来提取特征。
在这些场景中,模型通常会被量化(quantization)或者使用剪枝(pruning)技术进行加速,使得它们可以在低计算能力的硬件上高效运行。采用这种方式使得人脸识别系统在嵌入式设备(如闸机上的边缘设备)上依然可以保持相对较高的速度和精度。
工业界对深度学习人脸识别模型的优化
工业界的人脸识别系统在实现中面临诸多挑战,包括计算资源的限制、光照和环境的变化、安全和隐私问题等。因此,工程师们会采取多种手段来优化深度学习模型。
- 模型剪枝与量化:为了使得深度学习模型可以在嵌入式设备上运行,模型剪枝和量化是常用的手段。通过删除不重要的网络连接(剪枝)和使用低精度的数据类型(量化),可以极大地减少模型的计算复杂度和存储需求。
- 人脸数据增强:工业界的人脸识别系统需要处理各种不同光照、姿态和表情下的人脸,因此数据增强在训练阶段尤为重要。使用 GAN(生成对抗网络)等方法生成不同条件下的合成数据,也是一种有效的提高模型泛化能力的方式。
- 多模型融合:有些应用场景中,单一模型的识别精度不足以满足要求。因此,可以使用多个不同类型的模型同时进行识别,然后通过加权投票等方式得到最终的识别结果。这种方式可以有效降低识别错误的概率。
二、模型对比
主要是对常用模型从准确性,实时性,多人识别场景,工程应用性这几个方面进行总述,方便大家根据自己的实际需求,进行人脸识别模型的选择。文章选取的是常见的7种模型,FaceNet,VGG-Face,ArcFace, Dlib,OpenFace,DeepFace,DeepID。
FaceNet
准确性:FaceNet 使用 Triplet Loss 优化面部特征向量分布,在各种数据集上表现出色。其特征嵌入的方式非常强大,能够很好地区分相似面孔,根据LFW数据集上的实验结果,准确率表现为FaceNet:99.65%。
实时性:虽然 FaceNet 提供高准确率,但由于计算面部特征嵌入需要较多资源,在没有硬件加速的情况下,实时性表现一般。配合 GPU 加速时可以达到接近实时的性能。
多人识别:FaceNet 在多人场景下表现不错,依赖外部检测器(如 MTCNN 或 YOLO)来处理多张面孔的检测。处理多人时性能仍然良好,但在密集人群中依赖检测器的精度。
工程应用性:FaceNet 在各类身份验证、监控系统中得到广泛应用,尤其适用于需要高精度的场景。开源的实现方便集成,但对于需要低延迟和高并发的应用,FaceNet 可能需要较强的硬件支持。
优点
精度高,能够处理复杂场景。
特征嵌入通用性好,适合大规模识别任务。
缺点
对实时性的要求较高时需要硬件加速。
前置检测器的选择对多人识别的效果至关重要。
VGG-Face
准确性:VGG-Face 使用了深度 VGG 网络,虽然其精度在当时领先,但现在比起 FaceNet 和 ArcFace 已经稍逊一筹,尤其是在处理细微差别时,根据LFW数据集上的实验结果,准确率表现为VGG-Face:98.78%。
实时性:VGG-Face 模型较大,运算量庞大,导致实时性较差,特别是在没有硬件加速的情况下。
多人识别:在多人场景中,VGG-Face 依赖于外部人脸检测器,并且由于模型的庞大,处理多张面孔的速度较慢,效率不如 ArcFace 或 FaceNet。
工程应用性:虽然在早期应用中被广泛采用,但由于其体积较大、实时性较差,VGG-Face 现今在工程应用中较少使用,更多地作为学术研究或历史项目参考。
优点
具有良好的鲁棒性,尤其在静态图像识别中表现良好。
缺点
实时性较差。
对资源要求高,难以应用于嵌入式或移动设备。
ArcFace
准确性:ArcFace 使用 Additive Angular Margin Loss,提高了面部特征的区分性,是目前最精确的面部识别模型之一,尤其在处理相似人脸时表现卓越,根据LFW数据集上的实验结果,准确率表现为ArcFace:99.40%。
实时性:尽管 ArcFace 精度极高,但其计算复杂度也较高。在 GPU 加速的帮助下,实时性良好,但对于低资源设备来说可能表现不佳。
多人识别:ArcFace 在多人场景中的表现非常好。配合高效的检测器,可以处理多个面部的识别任务,特别是在人群密集场景下,ArcFace 能够精准区分不同面孔。
工程应用性:ArcFace 被广泛应用于对精度要求较高的场景,如金融、安防等领域,适合大规模部署。在处理高并发、多人识别任务时表现突出,适合高端硬件环境。
优点
极高的准确性,尤其在人群密集的场景下表现优异。
在硬件加速下能够提供实时性能。
缺点
计算量大,硬件需求高。
对低端设备不友好,实时性可能受影响。
Dlib
准确性:Dlib 提供了基于 HOG 和 CNN 的两种检测和识别方法。128D 的面部嵌入特征在一般应用中有足够的准确性,但不如 FaceNet 和 ArcFace 精确,根据LFW数据集上的实验结果,准确率表现为Dlib:99.38%。
实时性:Dlib 的 HOG 检测方式非常轻量,能够在 CPU 上快速运行,实时性较好。而基于 CNN 的方式则更加耗时,但也能够通过 GPU 加速提升性能。
多人识别:Dlib 在处理多人的时候也表现不错,尤其是在使用 HOG 方法进行检测时,速度较快。然而,精度较 FaceNet 或 ArcFace 低,尤其在复杂或高密度人群中可能遇到挑战。
工程应用性:Dlib 是一个轻量级、多功能的库,易于集成,广泛应用于中小规模的工程项目中,特别适合资源有限的设备。但由于其准确性和精度不足,不适合大规模或高精度要求的任务。
优点
易于集成,跨平台支持。
在小规模场景中实时性和准确性表现良好。
缺点
精度不及更现代的算法。
在复杂场景下表现不够稳定。
OpenFace
准确性:OpenFace 基于 FaceNet,但它对模型进行了轻量化,精度因此稍逊于 FaceNet 等更复杂的模型,尤其在处理相似面孔时表现不如 ArcFace,根据LFW数据集上的实验结果,准确率表现为OpenFace:93.80%。
实时性:OpenFace 由于其轻量化设计,在实时性上有很大优势,适合需要较高处理速度的应用场景,特别是在计算资源有限的设备上仍能有效运行。
多人识别:在多人场景下,OpenFace 表现良好,尤其是在处理小规模或低密度人群时。然而,由于其模型简化,在处理高密度人群时,特征区分的精度有所下降。
工程应用性:适合嵌入式系统和实时要求较高的应用场景,如智能家居和移动设备。由于模型轻量,易于集成并且在资源有限的环境中表现良好。
优点:
实时性优秀,轻量化适合嵌入式应用。
容易部署和集成。
缺点:
精度不及 FaceNet 和 ArcFace,尤其在复杂人群场景中。
DeepFace
准确性:DeepFace 使用深度学习技术,在其时代表现出色,但目前相比于 FaceNet 和 ArcFace,其准确性不再领先,尤其在处理高密度或复杂场景时。
实时性:模型较大,运算量大,导致实时性较差,特别是在多人识别场景中,DeepFace 难以保证高效处理。
多人识别:在多人场景中,DeepFace 的表现不如 ArcFace 或 FaceNet,在处理多面孔的任务中,检测和识别效率低于当前的最新技术。
工程应用性:DeepFace 曾被用于 Facebook,但目前已经被其他更先进的模型所取代,现今更多用于学术研究和早期项目。
优点
在当时具有创新性,曾用于大规模社交网络。
缺点
实时性差,模型较为臃肿。
在多人识别中的表现已被更新技术超越。
DeepID
准确性:DeepID 系列在早期面部识别任务中具有重要地位。尽管 DeepID2 和 DeepID3 提升了准确性,但与 FaceNet、ArcFace 等模型相比,精度不再占优势。
实时性:DeepID 系列的计算复杂度较高,模型较大,因此在实时应用中性能有限。
多人识别:DeepID 在小规模多人场景中表现不错,但在人群密集场景或大规模检测任务中,其精度和速度不如 ArcFace 等现代模型。
工程应用性:DeepID 虽然在学术界有很大影响,但由于其性能已落后于当前主流算法,在实际工程中使用有限。
优点
在其发展时期具有较高的准确性。
缺点
实时性差,精度不足以应对复杂场景。
难以处理大规模、多面孔检测。
总结
准确性:ArcFace 和 FaceNet 在所有场景中表现出色,适合高精度需求;VGG-Face、DeepID 等旧模型精度稍逊。
实时性:OpenFace 和 Dlib(HOG 模式)在实时性方面有优势,适合嵌入式和低资源设备;ArcFace 和 FaceNet 则依赖硬件加速才能达到实时性。
多人识别:ArcFace 和 FaceNet 在处理多人场景时表现较好,尤其在人群密集场景下精度更高;OpenFace 和 Dlib 在小规模场景中表现不错,但在人群密集时性能下降。
工程应用性:ArcFace 和 FaceNet 广泛应用于高精度要求的工程项目;Dlib 和 OpenFace 则因其轻量化设计适用于资源受限或低延迟的应用场景。
三、deepface 框架
https://github.com/serengil/deepface
DeepFace是一个面向Python的轻量级人脸识别和面部属性分析(年龄、性别、情绪和种族)框架。它是一个混合人脸识别框架,封装了最先进的模型:VGG-Face
, FaceNet
, OpenFace
, DeepFace
, DeepID
, ArcFace
, Dlib
, SFace
, GhostFaceNet
, Buffalo_L
。
经验显示,人类在人脸识别任务上的准确率为97.53%,而这些模型的准确率已经达到或者超过了人类。
现代人脸识别流程通常包含五个常见阶段:检测(detect)、对齐(align)、归一化(normalize)、表征(represent)和验证(verify)。尽管DeepFace在后台处理了所有这些常见阶段,但您无需深入了解背后的所有流程。您只需通过一行代码调用其验证、查找或分析功能即可。
conda activate opencv4.10
pip install deepface
在运行的时候,它会从 https://github.com/serengil/deepface_models/releases 下载对应的模型。
关于各个模型的Benchmark表现:https://github.com/serengil/deepface/tree/master/benchmarks
from deepface import DeepFace
import matplotlib.pyplot as plt
import cv2
import numpy as np
def face_verify():
result = DeepFace.verify("imgs/huge/20250324095937.png",
"imgs/huge/20250324095959.png")
'''
{
'verified': True,
'distance': 0.3951474552892865,
'threshold': 0.68,
'model': 'VGG-Face',
'detector_backend': 'opencv',
'similarity_metric': 'cosine',
'facial_areas': {
'img1': {'x': 80, 'y': 154, 'w': 308, 'h': 308, 'left_eye': (285, 270), 'right_eye': (172, 277)},
'img2': {'x': 288, 'y': 184, 'w': 152, 'h': 152, 'left_eye': (385, 243), 'right_eye': (332, 242)}
},
'time': 4.36
}
'''
print(result)
def face_recognition():
'''
人脸识别需要多次执行人脸验证。该函数会在db_path文件夹中搜索输入图像的身份,并返回一个包含 Pandas 数据帧的列表作为输出。同时,面部数据库中的面部嵌入会被存储在一个 pickle 文件中,以便下次更快地进行搜索。结果的大小将与源图像中出现的人脸数量一致。此外,数据库中的目标图像也可以包含多张人脸。
'''
results = DeepFace.find("imgs/20250324154252.png", db_path="imgs/huge")
for dataFrame in results:
print(dataFrame)
def embedding():
embeddings = DeepFace.represent("imgs/huge/20250324095937.png")
'''
[
{
'embedding': [......],
'facial_area': {'x': 80, 'y': 154, 'w': 308, 'h': 308, 'left_eye': (285, 270), 'right_eye': (172, 277)},
'face_confidence': 0.93
}
]
'''
output = []
for obj in embeddings:
if obj["face_confidence"] >= 0.5:
output.append(obj["embedding"])
return np.array(output)
def analyze():
result = DeepFace.analyze("imgs/huge/20250324095937.png")
'''
[
{
'emotion': {
'angry': 0.7332970388233662,
'disgust': 1.0652382309572772e-07,
'fear': 0.03976623702328652,
'happy': 0.32364167273044586,
'sad': 0.4743750672787428,
'surprise': 0.003194848250132054,
'neutral': 98.42572212219238
},
'dominant_emotion': 'neutral',
'region': {'x': 80, 'y': 154, 'w': 308, 'h': 308, 'left_eye': (285, 270), 'right_eye': (172, 277)},
'face_confidence': 0.93,
'age': 20,
'gender': {'Woman': 0.0006645485882472713, 'Man': 99.99933242797852},
'dominant_gender': 'Man',
'race': {'asian': 60.22493839263916, 'indian': 7.956235855817795, 'black': 1.1165719479322433, 'white': 7.318518310785294, 'middle eastern': 1.7460104078054428, 'latino hispanic': 21.637719869613647},
'dominant_race': 'asian'
}
]
'''
print(result)
def detectFace():
# result = DeepFace.detectFace("imgs/20250324102804.png")
# cv2.imshow("result", result)
# cv2.waitKey(0)
result = DeepFace.extract_faces(
"imgs/20250324102804.png", detector_backend="mtcnn")
src = cv2.imread("imgs/20250324102804.png", cv2.IMREAD_COLOR)
for val in result:
facial_area = val['facial_area']
src = cv2.rectangle(src, (facial_area['x'], facial_area['y']), (
facial_area['x']+facial_area['w'], facial_area['y']+facial_area['h']), (0, 255, 0), 2)
cv2.imshow("result", src)
cv2.waitKey(0)
def real_time():
'''
您也可以将 DeepFace 用于实时视频。Stream 函数会访问您的摄像头,并同时应用人脸识别和面部属性分析。如果该函数能够连续在 5 帧中聚焦到一张人脸,它就会开始分析该帧。然后,它会显示分析结果 5 秒钟。
'''
DeepFace.stream(db_path="C:/database")
def real_time2():
cap = cv2.VideoCapture(0)
while True:
_, frame = cap.read()
result = DeepFace.analyze(frame, actions=['emotion'])
print(result[0]['dominant_emotion'])
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
face_recognition()