opencv-python实战(17)——人脸识别详解(代码片段)

盼小辉丶 盼小辉丶     2023-01-30     593

关键词:

0. 前言

人脸处理是人工智能中的一个热门话题,人脸处理可以使用计算机视觉算法从人脸中自动提取大量信息,例如身份、意图和情感。随着计算机视觉、机器学习和深度学习的发展,人脸识别已经成为一个热门话题。在本文中,我们介绍 OpenCV 提供的与人脸识别相关的函数,同时还将探索一些用于人脸识别的深度学习方法,这些方法可以轻松集成到计算机视觉项目中以实现高精度的人脸识别。

1. 人脸识别简介

人脸识别具有广泛的应用前景,包括犯罪预防、智能监视以及社交网络。但自动人脸识别同样面临多种挑战,例如遮挡、装束变化、表情、年龄老化等。继在对象识别方面取得成功之后,CNN 已被广泛用于人脸识别。

2. 使用 OpenCV 进行人脸识别

OpenCV 提供了三种不同的实现来执行人脸识别

  • Eigenfaces
  • Fisherfaces
  • Local Binary Patterns Histograms (LBPH)

这些实现以不同的方式执行人脸识别。但是,我们仅需更改识别器的创建方式就可以独立于其内部算法使用它们了:

# 创建识别器
face_recognizer = cv2.face.LBPHFaceRecognizer_create()
face_recognizer = cv2.face.EigenFaceRecognizer_create()
face_recognizer = cv2.face.FisherFaceRecognizer_create()

一旦创建,其将独立于特定内部算法,均可以分别使用方法 train()predict() 来执行人脸识别系统的训练和测试,使用这些方法的方式与创建的识别器无关。
因此,可以很容易对比这三种识别器,然后针对特定任务选择性能最佳的识别器。但在涉及不同环境和光照条件的户外识别图像时,LBPH 通常比另外两种方法具有更好的性能。此外,LBPH 人脸识别器支持 update() 函数,可以在该方法中根据新数据更新人脸识别器,但 EigenfacesFisherfaces 方法并不支持 update() 函数。
为了训练识别器,应该调用 train() 方法:

face_recognizer.train(faces, labels)

cv2.face_FaceRecognizer.train(src, labels) 方法训练具体的人脸识别器,其中 src 表示图像(人脸)训练集,参数 labels 为训练集中的每张图像对应的标签。
要识别新面孔,应调用 predict() 方法:

label, confidence = face_recognizer.predict(face)

cv2.face_FaceRecognizer.predict(src) 方法通过输出预测的标签和相应置信度来输出(预测)对新 src 图像的识别结果。
OpenCV 还提供了 write()read() 方法用于保存创建的模型和加载之前创建的模型。对于这两种方法,文件名参数设置要保存或加载的模型的名称:

cv2.face_FaceRecognizer.write(filename)
cv2.face_FaceRecognizer.read(filename)

如果使用的是 LBPH 人脸识别器,可以使用 update() 方法进行更新:

cv2.face_FaceRecognizer.update(src, labels)

其中,srclabels 设置了用于更新 LBPH 识别器的新训练数据集。

2.1 使用 OpenCV 进行人脸识别流程示例

接下来,通过一个脚本来熟悉下使用 OpenCV 进行人脸识别的流程:

import cv2
import numpy as np
import matplotlib.pyplot as plt
import glob

face_recognizer = cv2.face.LBPHFaceRecognizer_create()

imgs = glob.glob('img/*.png')
faces = []
rects = []

def detect_img(img, faces, rects):
    img = cv2.imread(img)
    (h, w) = img.shape[:2]
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    net = cv2.dnn.readNetFromCaffe("deploy.prototxt", "res10_300x300_ssd_iter_140000_fp16.caffemodel")
    blob = cv2.dnn.blobFromImage(img, 1.0, (300, 300), [104., 117., 123.], False, False)
    net.setInput(blob)
    detections = net.forward()
    for i in range(0, detections.shape[2]):
        # 获取当前检测结果的置信度
        confidence = detections[0, 0, i, 2]
        # 如果置信大于最小置信度,则将其可视化
        if confidence > 0.7:
            # 获取当前检测结果的坐标
            box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
            (startX, startY, endX, endY) = box.astype('int')
            face_w = endX - startX
            face_h = endY - startY
            rects.append([startX, startY, face_w, face_h])
            faces.append(gray[startY:startY+face_h, startX:startX+face_w])
    return faces, rects
# 构造训练数据集
for img in imgs:
    faces, rects = detect_img(img, faces, rects)
# 根据实际情况构造标签数组
labels = [0] * len(faces)
# 训练识别器模型
face_recognizer.train(faces, np.array(labels))
# 加载测试图像并进行测试
img_test = cv2.imread('test.png')
face_test, rect_test = [], []
face_test, rect_test =  detect_img(img, face_test, rect_test)

label, confidence = face_recognizer.predict(face_test[0])
print(label, confidence)

3. 使用 dlib 进行人脸识别

Dlib 提供了基于深度学习的高性能人脸识别算法,该模型对户外数据集中标记人脸的识别准确率可以达到 99.38%。该算法基于 ResNet-34 网络实现,使用 300 万张人脸进行训练,预训练的模型文件 dlib_face_recognition_resnet_model_v1.dat 下载后就可以直接用于前向计算。
网络以生成 128 维 (128D) 描述符的方式进行训练,用于量化人脸。训练使用三元组执行,单个三元组训练数据由三个图像组成,其中两个对应于同一个人。网络为每张图像生成 128D 描述符,三元组损失函数对此进行了量化,尝试将同一个人的两个图像的 128D 描述符相距更近,同时将不同人的两个图像的 128D 描述符相距更远。
这个过程对数千个不同人的数百万张图像重复数百万次,最后,它能够为每个人生成一个 128D 描述符,最终的 128D 描述符是能够很好的对人脸进行编码:

  • 同一个人的两幅图像生成的 128D 描述符彼此非常相似
  • 不同人的两张图像生成的 128D 描述符差别很大

因此,利用 dlib 函数,我们可以使用预训练模型将人脸映射到 128D 描述符。然后使用这些特征向量来进行人脸识别。
计算 128D 描述符用于量化人脸的过程很简单:

# 使用 dlib 库加载特征点预测器、人脸编码和人脸检测器
pose_predictor_5_point = dlib.shape_predictor("shape_predictor_5_face_landmarks.dat")
face_encoder = dlib.face_recognition_model_v1("dlib_face_recognition_resnet_model_v1.dat")
detector = dlib.get_frontal_face_detector()

def face_encodings(face_image, number_of_times_to_upsample=1, num_jitters=1):
    """返回图像中每个人脸的 128D 描述符"""

    # 检测人脸
    face_locations = detector(face_image, number_of_times_to_upsample)
    # 检测面部特征点
    raw_landmarks = [pose_predictor_5_point(face_image, face_location) for face_location in face_locations]
    # 使用每个检测到的特征点计算每个检测到的人脸的编码
    return [np.array(face_encoder.compute_face_descriptor(face_image, raw_landmark_set, num_jitters)) for
            raw_landmark_set in raw_landmarks]

# 加载图像并转换为 RGB 模式
image = cv2.imread("jared_1.jpg")
rgb = image[:, :, ::-1]

# 计算图像中每个人脸的编码
encodings = face_encodings(rgb)
# 打印第一个编码的特征
print(encodings[0])

如上所示,关键是调用 dlibface_encoder.compute_face_descriptor() 函数,使用检测到的每个人脸的特征点计算每个检测到的人脸的 128D 编码,其中 num_jitters 参数用于设置每个人脸随机抖动的次数,返回值为每次计算的平均 128D 描述符,输出的 128D 描述符如下:

[-0.09235165  0.11607055  0.03648872 -0.08326858 -0.12627071 -0.01334486 -0.11334236 -0.10083835  0.20534235 -0.1636433   0.16874117 -0.05276754 -0.17746128 -0.05377002 -0.02731067  0.24751744 -0.22732623 -0.20258367 -0.03421091 -0.00150665  0.05875423 0.03020219  0.03901095  0.03496565 -0.15658092 -0.34250638 -0.08725534 -0.06245319 -0.04688681 -0.04861078 -0.07620423  0.05013577 -0.18563135 -0.04075277  0.05248301  0.09195475 -0.00887688 -0.1192601   0.18633801  0.00056917 -0.29226956  0.01442468  0.09583923  0.19053322  0.15580602 -0.04580544  0.01866002 -0.15243134  0.13535264 -0.17270051  0.03029358  0.16308595  0.04719323  0.08862312  0.01600051 -0.112983    0.06787978  0.17171389 -0.09536573 -0.02140218  0.11402114 -0.04710582 -0.01966342 -0.0705786   0.21773803  0.12153016 -0.08498291 -0.24783675  0.06667361 -0.08091511 -0.11054871  0.08837797 -0.17216064 -0.18642734 -0.27270097 -0.03300989  0.31748736  0.06824204 -0.16750985  0.0599058  -0.00497202 -0.02882685  0.07890167  0.19422579 -0.02771271  0.05871597 -0.06130363  0.04929798  0.27234387 -0.04948008 -0.00844343  0.22556995  0.00912007  0.07115038  0.01273906  0.03535268 -0.05074561  0.05441948 -0.13103089 -0.00421767  0.07432865  0.0025964 -0.06208063  0.12578207 -0.16597968  0.09258381 -0.02716768  0.02978029 -0.00216489 -0.01805471 -0.04702468 -0.05231683  0.11994087 -0.16787212  0.17464222  0.16930985  0.05848085  0.09450675  0.11558257  0.0659898 -0.00265438 -0.01509937 -0.22738113  0.01624682  0.13056616 -0.04214386  0.06433617  0.00774699]

获取到检测到的人脸编码后,下一步就是进行人脸识别。
使用 128D 描述符计算的某种距离度量可以用于执行人脸识别,如果两个人脸描述符向量之间的欧几里得距离小于 0.6 (欧几里得距离可以使用 numpy.linalg.norm() 计算),则可以认为它们属于同一个人;否则,他们是不同的人。
接下来,我们使用 5 张已知图像与另 1 张测试图像进行比较。为了比较人脸,我们需要编写两个函数:compare_faces()compare_faces_ordered()
compare_faces() 函数返回已知人脸编码与待识别人脸间的距离:

def compare_faces(encodings, encoding_to_check):
    return list(np.linalg.norm(encodings - encoding_to_check, axis=1))

compare_faces_ordered() 函数返回排序后的已知人脸编码与待识别人脸间的距离和相应的名称:

def compare_faces_ordered(encodings, face_names, encoding_to_check):
    distances = list(np.linalg.norm(encodings - encoding_to_check, axis=1))
    return zip(*sorted(zip(distances, face_names)))

接下来,将 5 个已标记图像与 1 个未标记图像进行比较,第一步是加载所有图像并转换为 RGB 格式:

# 加载所有图像并转换为 RGB 格式
known_image_1 = cv2.imread("小新_1.png")
known_image_2 = cv2.imread("小甜_1.png")
known_image_3 = cv2.imread("小甜_2.png")
known_image_4 = cv2.imread("小甜_3.png")
known_image_5 = cv2.imread("小新_2.png")
unknown_image = cv2.imread("test.png")
known_image_1 = known_image_1[:, :, ::-1]
known_image_2 = known_image_2[:, :, ::-1]
known_image_3 = known_image_3[:, :, ::-1]
known_image_4 = known_image_4[:, :, ::-1]
known_image_5 = known_image_5[:, :, ::-1]
unknown_image = unknown_image[:, :, ::-1]
# 标记人脸
names = ["小新_1.png", "小甜_1.png", "小甜_2.png", "小甜_3.png", "小新_2.png"]

下一步是计算每个图像的 128D 编码:

# 计算每个图像的 128D 编码
known_image_1_encoding = face_encodings(known_image_1)[0]
known_image_2_encoding = face_encodings(known_image_2)[0]
known_image_3_encoding = face_encodings(known_image_3)[0]
known_image_4_encoding = face_encodings(known_image_4)[0]
known_image_5_encoding = face_encodings(known_image_5)[0]
known_encodings = [known_image_1_encoding, known_image_2_encoding, known_image_3_encoding, known_image_4_encoding, known_image_5_encoding]
unknown_encoding = face_encodings(unknown_image)[0]

最后,可以使用 compare_faces_ordered() 函数比较与识别人脸:

computed_distances_ordered, ordered_names = compare_faces_ordered(known_encodings, names, unknown_encoding)
# 打印返回信息
print(computed_distances)
print(computed_distances_ordered)
print(ordered_names)

打印的返回信息如下:

(0.26459402873041915, 0.2728113455078627, 0.2945116087102425, 0.42567525558949304, 0.42899966791571725)
('小甜', '小甜', '小甜', '小新', '小新')

通过上示的打印信息,可以得出结论待识别的人脸属于小甜,而小新的人脸编码信息与待识别人脸的编码信息距离较远,表示不是同一个人:

4. 使用 face_recognition 进行人脸识别

使用 face_recognition 进行人脸识别内部使用了 dlib 函数对人脸进行编码并计算已编码人脸的距离。因此,无需自己编写 face_encodings()compare_faces() 函数,只需直接调用 face_recognition 库中已经封装好的相应函数。
接下来,首先使用 face_recognition.face_encodings() 函数创建 128D 描述符,然后使用 face_recognition.compare_faces() 比较人脸:

# 加载图像
known_image_1 = face_recognition.load_image_file("小美_1.png")
known_image_2 = face_recognition.load_image_file("小美_2.png")
known_image_3 = face_recognition.load_image_file("小美_3.png")
known_image_4 = face_recognition.load_image_file("小可_1.png")
# 为每个图像创建标签
names = ["小美_1.png", "小美_2.png", "小美_3.png", "小可_1.png"]
# 加载待识别图像(用于与已加载的标记图像进行比较)
unknown_image = face_recognition.load_image_file("unrecognition.jpg")
# 将每张图片中的人脸编码为 128D 向量
known_image_1_encoding = face_recognition.face_encodings(known_image_1)[0]
known_image_2_encoding = face_recognition.face_encodings(known_image_2)[0]
known_image_3_encoding = face_recognition.face_encodings(known_image_3)[0]
known_image_4_encoding = face_recognition.face_encodings(known_image_4)[0]
known_encodings = [known_image_1_encoding, known_image_2_encoding,
known_image_3_encoding, known_image_4_encoding]
unknown_encoding = face_recognition.face_encodings(unknown_image)[0]
# 人脸对比
results = face_recognition.compare_faces(known_encodings, unknown_encoding)
# 打印结果
print(results)

得到的结果是 [True, True, True, False]。因此,前三个加载的图像 ("小美_1.png", “小美_2.png” 和 “小美_3.png”) 与待识别图像 ("unrecognition.jpg") 是同一个人,而第四个加载的图像 ("小可_1.png") 被判定为待识别图像属于不同的人。

小结

在本文中,我们介绍 OpenCV 提供的与人脸识别相关的函数,同时还将探索一些用于人脸识别的深度学习方法,主要包括 dlibface_recognition 库,这些方法可以轻松集成到计算机视觉项目中以实现高精度的人脸识别。

系列链接

OpenCV-Python实战(1)——OpenCV简介与图像处理基础
OpenCV-Python实战(2)——图像与视频文件的处理
OpenCV-Python实战(3)——OpenCV中绘制图形与文本
OpenCV-Python实战(4)——OpenCV常见图像处理技术
OpenCV-Python实战(5)——OpenCV图像运算
OpenCV-Python实战(6)——OpenCV中的色彩空间和色彩映射
OpenCV-Python实战(7)——直方图详解
OpenCV-Python实战(8)——直方图均衡化
OpenCV-Python实战(9)——OpenCV用于图像分割的阈值技术
OpenCV-Python实战(10)——OpenCV轮廓检测
OpenCV-Python实战(11)——OpenCV轮廓检测相关应用
OpenCV-Python实战(12)——一文详解AR增强现实
OpenCV-Python实战(13)——OpenCV与机器学习的碰撞
OpenCV-Python实战(14)——人脸检测详解
OpenCV-Python实战(15)——面部特征点检测详解
OpenCV-Python实战(16)——人脸追踪详解

opencv-python实战(14)——人脸检测详解(仅需6行代码学会4种人脸检测方法)(代码片段)

OpenCV-Python实战(14)——人脸检测详解(仅需6行代码学会4种人脸检测方法)0.前言1.人脸处理简介2.安装人脸处理相关库2.1安装dlib2.2安装face_recognition2.3安装cvlib3.人脸检测3.1使用OpenCV进行人脸检测3.1.1基于Haar级联... 查看详情

基于python的百度ai人脸识别api接口(可用于opencv-python人脸识别)(代码片段)

基于Python的百度AI人脸识别API接口(可用于OpenCV-Python人脸识别)资源:https://download.csdn.net/download/weixin_53403301/43644312之前的项目:【最新】基于OpenCV的Python人脸识别、检测、框选(遍历目录下所有照片依次识别... 查看详情

opencv-python也能实现人脸检测了(代码片段)

opencv中也可以实现深度学习中的人脸识别算法了。是怎么一回事呢?就是opencv中的DNN库,更新了好多深度学习的模块或者说是库函数,这样就让我们摆脱了安装庞大繁琐的深度学习框架。我们只需下载相应的权重文件... 查看详情

树莓派人脸识别------opencv-python环境搭建最全教程(从零开始)(代码片段)

文章目录需要用到的工具系统烧录系统无线联网以及基础连接配置SSH连接系统配置更新软件源需要用到的工具Rufusnotepad++vncviewerMobaXterm系统烧录首先需要烧录系统打开工具rufus-3.9p.exe然后选择烧录的系统进行烧录系统无线联... 查看详情

opencv⚠️实战⚠️人脸识别☢️建议手收藏☢️(代码片段)

【OpenCV】⚠️实战⚠️人脸识别☢️建议手收藏☢️概述模型获取detectMultiScale图片人脸识别视频人脸识别概述OpenCV是一个跨平台的计算机视觉库,支持多语言,功能强大.今天小白就带大家来实战一下,用OpenCV实现人脸识别.模型获取... 查看详情

opencv⚠️实战⚠️人脸识别☢️建议手收藏☢️(代码片段)

【OpenCV】⚠️实战⚠️人脸识别☢️建议手收藏☢️概述模型获取detectMultiScale图片人脸识别视频人脸识别概述OpenCV是一个跨平台的计算机视觉库,支持多语言,功能强大.今天小白就带大家来实战一下,用OpenCV实现人脸识别.模型获取... 查看详情

人脸识别完整项目实战:完整项目案例运行演示

一、前言本文是《人脸识别完整项目实战》系列博文第1部分,第一节《完整项目运行演示》,本章内容系统介绍:人脸系统核心功能的运行演示。本内容已经录制成视频课程,详见网易云课堂。整个《人脸识别完整项目实战》... 查看详情

王文峰《人脸识别原理与实战以matlab为工具》pdf及代码+《人脸识别原理及算法(沈理)》pdf+学习参考

...作和研究成果,全书共分为3个部分。《人脸识别原理与实战以MATLAB为工具》作为该技术的进阶指南,在内容上尽可能涵盖人脸识别的各技术模块,立足于作者 在中国科学院、985工程大学国家重点实验室从事视频识别与智能... 查看详情

人脸识别完整项目实战(14):实时人脸特征点标定程序设计

一、前言本文是《人脸识别完整项目实战》系列博文第14章《实时人脸特征点标定程序设计》,本章内容详细介绍Win10环境下,基于VisualStudio2015+Opencv+Dlib开发环境,如何实现实时视频流人脸特征点标定程序的设计。本文内容已经... 查看详情

『python开发实战菜鸟教程』实战篇:一文带你了解人脸识别应用原理及手把手教学实现自己的人脸识别项目(代码片段)

文章目录0x01:引子0x02:环境搭建0x03:开发实战 1.实现人脸检测标记2.人脸特征点提取3.人脸识别验证0x04:后记开源GitHub地址--> https://github.com/xiaosongshine/dlib_face_recognition推荐补充阅读:『Python开发实战菜鸟... 查看详情

opencv-python实战(番外篇)——利用svm算法识别手写数字(代码片段)

OpenCV-Python实战(番外篇)——利用SVM算法识别手写数字前言使用SVM进行手写数字识别参数C和γ对识别手写数字精确度的影响完整代码相关链接前言支持向量机(SupportVectorMachine,SVM)是一种监督学习技术,它通过根据指定... 查看详情

opencv-python实战(番外篇)——利用knn算法识别手写数字(代码片段)

OpenCV-Python实战(番外篇)——利用KNN算法识别手写数字前言手写数字数据集MNIST介绍基准模型——利用KNN算法识别手写数字改进模型1——参数K对识别手写数字精确度的影响改进模型2——训练数据量对识别手写数字精确... 查看详情

[深度应用]·实战掌握dlib人脸识别开发教程

[深度应用]·实战掌握Dlib人脸识别开发教程个人网站--> http://www.yansongsong.cn/项目GitHub地址--> https://github.com/xiaosongshine/dlib_face_recognition1.背景介绍Dlib是一个深度学习开源工具,基于C++开发,也支持Python开发接口,... 查看详情

『python开发实战菜鸟教程』实战篇:一文带你了解人脸识别应用原理及手把手教学实现自己的人脸识别项目(代码片段)

文章目录0x01:引子0x02:环境搭建0x03:开发实战 1.实现人脸检测标记2.人脸特征点提取3.人脸识别验证0x04:后记开源GitHub地址--> https://github.com/xiaosongshine/dlib_face_recognition推荐补充阅读:『Python开发实战菜鸟... 查看详情

opencv-python实战(11)——opencv轮廓检测相关应用(代码片段)

OpenCV-Python实战(11)——OpenCV轮廓检测相关应用0.前言1.轮廓绘制2.轮廓筛选3.轮廓识别4.轮廓匹配小结系列链接0.前言在计算机视觉领域,轮廓通常指图像中对象边界的一系列点。因此,轮廓通常描述了对象边界的... 查看详情

c#项目实战|人脸识别考勤(代码片段)

此文主要通过WinForm来制作的一个人脸识别考勤打卡程序,有兴趣的小伙伴可以接入到打卡机上。一、实现流程1.1、创建项目1.2、设计页面1.3、创建应用1.4、获取Token及参数解析1.5、与人脸数据比对并展示一、实现流程1.1、创... 查看详情

人脸识别实战:使用opencv+svm实现人脸识别(代码片段)

在本文中,您将学习如何使用OpenCV进行人脸识别。文章分三部分介绍:第一,将首先执行人脸检测,使用深度学习从每个人脸中提取人脸量化为128位的向量。第二,在嵌入基础上使用支持向量机(SVM)... 查看详情

opencv-python实战(15)——面部特征点检测详解(仅需5行代码学会3种面部特征点检测方法)(代码片段)

OpenCV-Python实战(15)——面部特征点检测详解(仅需5行代码学会3种面部特征点检测方法)0.前言1.面部特征点简介2.使用OpenCV检测面部特征点3.用dlib检测面部特征点4.使用face_recognition检测面部特征点小结系列链接0.... 查看详情