200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > [深度学习] Python人脸识别库face_recognition使用教程

[深度学习] Python人脸识别库face_recognition使用教程

时间:2023-10-01 23:04:17

相关推荐

[深度学习] Python人脸识别库face_recognition使用教程

Python人脸识别库face_recognition使用教程

face_recognition号称是世界上最简单的开源人脸识别库,可以通过Python或命令行识别和操作人脸。face_recognition提供了十分完整的技术文档和应用实例,人脸识别初学者建议研究该库上手。face_recognition的官方代码仓库为:face_recognition。face_recognition也有自己的官方中文文档,该文档详情见:face_recognition中文使用说明。

本文所有的代码和大部分测试图像来自于face_recognition官方代码仓库的examples文件夹。实际使用建议看看官方文档的函数接口说明face_recognition函数接口。

face_recognition中的人脸识别模型来自开源的机器学习库Dlib,Dlib的官方代码仓库见:dlib。大部分模型用Labeled Faces in the Wild人脸数据集进行测试,有高达99.38%的准确率。但对小孩和亚洲人脸的识别准确率尚待提升。Labeled Faces in the Wild是美国麻省大学安姆斯特分校(University of Massachusetts Amherst)制作的人脸数据集,该数据集包含了从网络收集的13,000多张面部图像。该数据集算是一个非常小型的人脸数据集。

总体而言这个项目的人脸识别模型是基于成年人的,在孩子身上效果可能会一般。face_recognition一般学习代码使用或者研究源代码比较好,离工程应用还是有一定的距离。

某些网站会判定本文人脸图片违规,这是网站识别算法自身问题。本文所有算法展示效果和代码见:

github: Python-Study-Notes

1 face_recognition安装与相关知识

face_recognition支持linux,mac和windows系统,推荐linux系统使用face_recognition。安装face_recognition库之前需要安装dlib的python库。dlib的python库具体安装说明见:[常用工具] dlib编译调用指南中的第四节。注意windows下的dlib库安装不那么容易,多查查文档。

当dlib安装好后,输入以下命令安装face_recognition。

pip install face_recognition

人脸识别通用流程一般有人脸检测,人脸对齐和人脸识别三步:

1 人脸检测/人脸定位 face detection and location:人脸检测就是在图片中找到人脸的具体位置,并输出包含人脸位置的边界矩形框。某些检测算法可以同时输出人脸相应的关键点。2 人脸对齐 face alignment:所谓的人脸对齐就是有时候人脸的角度不正,根据关键点检测结果通过图像变换或其他方法,将人脸上对准到一个预设的固定位置上(通常是正脸)。这样使得不同人脸的眼睛,鼻子都被放在同一个位置,大大提高识别精度。3 人脸识别 face recognition:人脸识别有很多应用方向,但是目的都是识别当前人脸对应哪个人。

简单的人脸识别通用流程示意图如下图所示。在face_recognition中所有代码都有涉及这些步骤;但是人脸对齐是直接调用dlib代码,没有实例说明。

当然在成熟的商业工程应用不只有这三个部分,比如还有人脸质量判断,活体检测之类的,但是一般的项目都包含这三大步骤。关于人脸识别的更多介绍见:/xiaoyh/p/11874270.html

2 人脸检测/定位

本部分主要是对人脸进行检测和定位,并输出人脸相应的矩形框。主要用到的face_recognition内置函数有:

face_recognition.api.face_locations(img, number_of_times_to_upsample=1, model=‘hog’)

用途:人脸检测,返回图像中人脸边界框的数组img:输入图像,numpy数组number_of_times_to_upsample:对图像进行上采样次数以找到更小的人脸,默认为1model:检测模型,默认是hog机器学习模型,另外可设置cnn选择卷积神经网络模型以提高检测精度返回:包含多张人脸边界框的list数组,边界框数据以人脸(top, right, bottom, left) 顺序表示

face_recognition.api.load_image_file(file, mode=‘RGB’)

用途:加载图像file:图像路径名mode:图像颜色类型,设置RGB表示返回RGB图像,设置’L’表示返回灰度图像返回:numpy数组

2.1 基于机器学习实现人脸检测

来自examples/find_faces_in_picture.py

%matplotlib inlineimport matplotlib.pyplot as plt from PIL import Imageimport face_recognition# 通过PIL加载图片image = face_recognition.load_image_file("test_img/obama.jpg")# 基于hog机器学习模型进行人脸识别,不能使用gpu加速face_locations = face_recognition.face_locations(image)# 找到几张人脸print("I found {} face(s) in this photograph.".format(len(face_locations)))for face_location in face_locations:# 打印人脸信息top, right, bottom, left = face_locationprint("A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right))# 提取人脸face_image = image[top:bottom, left:right]pil_image = Image.fromarray(face_image)# jupyter 绘图# pil_image.show()plt.imshow(pil_image)plt.axis('off') plt.show()

I found 1 face(s) in this photograph.A face is located at pixel location Top: 142, Left: 349, Bottom: 409, Right: 617

2.2 基于卷积神经网络实现人脸检测

来自examples/find_faces_in_picture_cnn.py

%matplotlib inlineimport matplotlib.pyplot as plt from PIL import Imageimport face_recognition# 通过PIL加载图片image = face_recognition.load_image_file("test_img/obama.jpg")# 基于cnn识别人脸,是否使用gpu看装机环境face_locations = face_recognition.face_locations(image, number_of_times_to_upsample=0, model="cnn")print("I found {} face(s) in this photograph.".format(len(face_locations)))for face_location in face_locations:# 打印人脸信息top, right, bottom, left = face_locationprint("A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right))# 提取人脸face_image = image[top:bottom, left:right]pil_image = Image.fromarray(face_image)# jupyter 绘图# pil_image.show()plt.imshow(pil_image)plt.axis('off') plt.show()

I found 1 face(s) in this photograph.A face is located at pixel location Top: 154, Left: 375, Bottom: 390, Right: 611

2.3 人脸马赛克

来自examples/blur_faces_on_webcam.py

%matplotlib inlineimport matplotlib.pyplot as pltimport face_recognitionimport cv2frame = cv2.imread("test_img/obama.jpg")# 缩小图像以加快速度small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)# 找到人脸face_locations = face_recognition.face_locations(small_frame, model="cnn")for top, right, bottom, left in face_locations:# 提取边界框在原图比例的边界框top *= 4right *= 4bottom *= 4left *= 4# 提取人脸face_image = frame[top:bottom, left:right]# 高斯模糊人脸face_image = cv2.GaussianBlur(face_image, (99, 99), 30)# 原图人脸替换frame[top:bottom, left:right] = face_image# 展示图像img = frame[:,:,::-1] plt.axis('off')plt.imshow(img)

<matplotlib.image.AxesImage at 0x2139a75cdf0>

3 人脸关键点识别

本部分主要是对人脸进行关键点识别,并输出人脸特征位置。主要用到的face_recognition内置函数有:

face_recognition.api.face_landmarks(face_image, face_locations=None, model=‘large’) 用途:人脸关键点识别,返回图像人脸特征位置的字典face_image:输入图像,numpy数组face_locations:要识别的位置列表(可选)model:使用的识别模型。默认值为large表示大模型。small表示小模型,但只返回五个特征点返回:特征位置(眼睛、鼻子等)的字典列表

3.1 提取图像中的人脸关键点

来自examples/find_facial_features_in_picture.py

%matplotlib inlineimport matplotlib.pyplot as plt from PIL import Image, ImageDrawimport face_recognition# 通过PIL加载图片image = face_recognition.load_image_file("test_img/two_people.jpg")# 找到图像中所有人脸的所有面部特征,返回字典face_landmarks_list = face_recognition.face_landmarks(image)# 发现人脸数print("I found {} face(s) in this photograph.".format(len(face_landmarks_list)))# 创建展示结果的图像pil_image = Image.fromarray(image)d = ImageDraw.Draw(pil_image)# 绘制关键点for face_landmarks in face_landmarks_list:# 打印此图像中每个面部特征的位置# for facial_feature in face_landmarks.keys():# print("The {} in this face has the following points: {}".format(facial_feature, face_landmarks[facial_feature]))# 用一条线勾勒出图像中的每个面部特征for facial_feature in face_landmarks.keys():d.line(face_landmarks[facial_feature], width=5)# jupyter 绘图# pil_image.show()plt.imshow(pil_image)plt.axis('off') plt.show()

I found 2 face(s) in this photograph.

3.2 人脸涂色

来自examples/digital_makeup.py

%matplotlib inlineimport matplotlib.pyplot as pltfrom PIL import Image, ImageDrawimport face_recognition# 通过PIL加载图片image = face_recognition.load_image_file("test_img/two_people.jpg")# 找到图像中所有人脸的所有面部特征,返回字典face_landmarks_list = face_recognition.face_landmarks(image)pil_image = Image.fromarray(image)# 绘图for face_landmarks in face_landmarks_list:d = ImageDraw.Draw(pil_image, 'RGBA')# 眉毛涂色d.polygon(face_landmarks['left_eyebrow'], fill=(68, 54, 39, 128))d.polygon(face_landmarks['right_eyebrow'], fill=(68, 54, 39, 128))d.line(face_landmarks['left_eyebrow'], fill=(68, 54, 39, 150), width=5)d.line(face_landmarks['right_eyebrow'], fill=(68, 54, 39, 150), width=5)# 嘴唇涂色d.polygon(face_landmarks['top_lip'], fill=(150, 0, 0, 128))d.polygon(face_landmarks['bottom_lip'], fill=(150, 0, 0, 128))d.line(face_landmarks['top_lip'], fill=(150, 0, 0, 64), width=8)d.line(face_landmarks['bottom_lip'], fill=(150, 0, 0, 64), width=8)# 眼睛涂色d.polygon(face_landmarks['left_eye'], fill=(255, 255, 255, 30))d.polygon(face_landmarks['right_eye'], fill=(255, 255, 255, 30))# 眼线涂色d.line(face_landmarks['left_eye'] + [face_landmarks['left_eye'][0]], fill=(0, 0, 0, 110), width=6)d.line(face_landmarks['right_eye'] + [face_landmarks['right_eye'][0]], fill=(0, 0, 0, 110), width=6)# jupyter 绘图# pil_image.show()plt.imshow(pil_image)plt.axis('off')plt.show()

3.3 人眼睁闭状态识别

来自examples / blink_detection.py

该部分代码作用为根据人眼关键点数据计算人眼的纵横比。人眼睁开的时候纵横比较高,人眼闭上的时候纵横比较小。如果眼睛闭上次数超过设定阈值,则输出人眼处于闭眼状态。

import matplotlib.pylab as pltimport face_recognitionimport cv2from scipy.spatial import distance as dist# 这是一个检测眼睛状态的演示# 人眼闭上次数超过设定阈值EYES_CLOSED_SECONDS,判定人眼处于闭眼状态EYES_CLOSED_SECONDS = 2def main():# 闭眼次数closed_count = 0# 读取两张图像模仿人睁闭眼img_eye_opened = cv2.imread('test_img/eye_opened.jpg')img_eye_closed = cv2.imread('test_img/eye_closed.jpg')# 设置图像输入序列,前1张睁眼,中间3张闭眼,最后1张睁眼frame_inputs = [img_eye_opened] + [img_eye_closed] * 3 + [img_eye_opened] * 1for frame_num, frame in enumerate(frame_inputs):# 缩小图片small_frame = cv2.resize(frame, (0, 0), fx=0.5, fy=0.5)# bgr通道变为rgb通道rgb_small_frame = small_frame[:, :, ::-1]# 人脸关键点检测face_landmarks_list = face_recognition.face_landmarks(rgb_small_frame)# 没有检测到关键点if len(face_landmarks_list) < 1:continue# 获得人眼特征点位置for face_landmark in face_landmarks_list:# 每只眼睛有六个关键点,以眼睛最左边顺时针顺序排列left_eye = face_landmark['left_eye']right_eye = face_landmark['right_eye']# 计算眼睛的纵横比ear,ear这里不是耳朵的意思ear_left = get_ear(left_eye)ear_right = get_ear(right_eye)# 判断眼睛是否闭上# 如果两只眼睛纵横比小于0.2,视为眼睛闭上closed = ear_left < 0.2 and ear_right < 0.2# 设置眼睛检测闭上次数if closed:closed_count += 1else:closed_count = 0# 如果眼睛检测闭上次数大于EYES_CLOSED_SECONDS,输出眼睛闭上if closed_count > EYES_CLOSED_SECONDS:eye_status = "frame {} | EYES CLOSED".format(frame_num)elif closed_count > 0:eye_status = "frame {} | MAYBE EYES CLOSED ".format(frame_num)else:eye_status = "frame {} | EYES OPENED ".format(frame_num)print(eye_status)plt.imshow(rgb_small_frame)# 左右眼轮廓第一个关键点颜色为red,最后一个关键点颜色为blue,其他关键点为yellowcolor = ['red'] + ['yellow'] * int(len(left_eye) - 2) + ['blue']# 按照顺序依次绘制眼睛关键点for index in range(len(left_eye)):leye = left_eye[index]reye = right_eye[index]plt.plot(leye[0], leye[1], 'bo', color=color[index])plt.plot(reye[0], reye[1], 'bo', color=color[index])plt.title(eye_status)plt.show()# 计算人眼纵横比def get_ear(eye):# 计算眼睛轮廓垂直方向上下关键点的距离A = dist.euclidean(eye[1], eye[5])B = dist.euclidean(eye[2], eye[4])# 计算水平方向上的关键点的距离C = dist.euclidean(eye[0], eye[3])# 计算眼睛的纵横比ear = (A + B) / (2.0 * C)# 返回眼睛的纵横比return earif __name__ == "__main__":main()

frame 0 | EYES OPENED

frame 1 | MAYBE EYES CLOSED

frame 2 | MAYBE EYES CLOSED

frame 3 | EYES CLOSED

frame 4 | EYES OPENED

4 人脸识别

本部分主要是对人脸进行识别,提供多种实际任务案例。主要用到的face_recognition内置函数有:

face_recognition.api.face_encodings(face_image, known_face_locations=None, num_jitters=1, model=‘small’)

用途:返回图像中每个人脸的128维人脸特征face_image:输入图像,numpy数组known_face_locations:每个人脸的边界框(可选),能够大大提高识别速度num_jitters:计算人脸特征时重新采样人脸的次数。更高更准确,但更慢,即设置为100慢100倍model:使用的识别模型,默认值为small表示小模型,只返回五个特征点;可设置为large返回:包含人脸特征的列表

pare_faces(known_face_encodings, face_encoding_to_check, tolerance=0.6)

用途:将人脸特征与候选人脸特征进行比较,以查看它们是否匹配。known_face_encodings:已知人脸特征列表face_encoding_to_check:与已知人脸特征列表进行比较的单个人脸特征tolerance:人脸距离越小表示人脸越相近,当人脸距离小于tolerance,表示是同一个人;0.6是默认值,也是作者认为的最佳值(实际有所出入)返回:包含True或者False的列表,以表示是否为同一个人脸

face_recognition.api.face_distance(face_encodings, face_to_compare)

用途:给定一个人脸特征列表,将它们与已知的人脸特征进行比较,并获得人脸特征向量之间的欧几里德距离,距离越小面孔越相似。face_encodings:已知的人脸特征列表face_to_compare:未知的人脸特征列表返回:代表距离的numpy数组,和face_encodings的排序方式一样

4.1 人脸比对

来自examples/recognize_faces_in_pictures.py

该部分代码就是输入两张已知人脸图像和一张未知人脸图像,看未知人脸图像和已知人脸的哪一张图像表示的是同一个人。

%matplotlib inlineimport matplotlib.pyplot as pltfrom PIL import Image, ImageDrawimport face_recognition# 通过PIL加载图片biden_image = face_recognition.load_image_file("test_img/biden.jpg")obama_image = face_recognition.load_image_file("test_img/obama.jpg")unknown_image = face_recognition.load_image_file("test_img/obama2.jpg")plt.imshow(biden_image)plt.title('biden')plt.axis('off')plt.show()plt.imshow(obama_image)plt.title('obama')plt.axis('off')plt.show()plt.imshow(unknown_image)plt.title('unknown')plt.axis('off')plt.show()# 获取输入图像文件中每个人脸的人脸特征,人脸特征维度为128# 由于输入图像中可能有多张脸,因此它会返回一个特征列表。# 默认输入图像只有一张人脸,只关心每个图像中的第一个特征,所以设置特征获取索引为0# 建议单步看看该函数运行机制try:biden_face_encoding = face_recognition.face_encodings(biden_image)[0]obama_face_encoding = face_recognition.face_encodings(obama_image)[0]unknown_face_encoding = face_recognition.face_encodings(unknown_image)[0]except IndexError:# 没有找到人脸的情况print("I wasn't able to locate any faces in at least one of the images. Check the image files. Aborting...")quit()# 已知人脸列表,按照顺序为拜登的人脸特征,奥巴马的人脸特征known_faces = [biden_face_encoding,obama_face_encoding]# 如果未知人脸与已知人脸数组中的某个人匹配,则匹配结果为真# 这个函数调用了face_distance人脸特征距离计算函数,可以单步调试看看源代码results = pare_faces(known_faces, unknown_face_encoding)# 是否和第一个人匹配print("Is the unknown face a picture of Biden? {}".format(results[0]))# 是否和第二个人匹配print("Is the unknown face a picture of Obama? {}".format(results[1]))# 这张人脸是否曾经见过print("Is the unknown face a new person that we've never seen before? {}".format(not True in results))

Is the unknown face a picture of Biden? FalseIs the unknown face a picture of Obama? TrueIs the unknown face a new person that we've never seen before? False

4.2 人脸识别之后在原图上画框并标注姓名

来自examples/identify_and_draw_boxes_on_faces.py

该部分代码就是输入两张已知人脸图像和一张未知人脸图像,然后进行人脸识别并在未知人脸图像标注各个人脸身份信息

%matplotlib inlineimport matplotlib.pyplot as pltimport face_recognitionfrom PIL import Image, ImageDrawimport numpy as np# 加载第一张示例图片并提取特征obama_image = face_recognition.load_image_file("test_img/obama.jpg")obama_face_encoding = face_recognition.face_encodings(obama_image)[0]# 加载第二张示例图片并提取特征biden_image = face_recognition.load_image_file("test_img/biden.jpg")biden_face_encoding = face_recognition.face_encodings(biden_image)[0]# 创建已知人脸特征和其名字的数据known_face_encodings = [obama_face_encoding,biden_face_encoding]known_face_names = ["Barack Obama","Joe Biden"]# 加载未知人脸图片unknown_image = face_recognition.load_image_file("test_img/two_people.jpg")# 人脸检测face_locations = face_recognition.face_locations(unknown_image)# 人脸特征提取face_encodings = face_recognition.face_encodings(unknown_image, face_locations)# 查看输入图像plt.imshow(biden_image)plt.title('biden')plt.axis('off')plt.show()plt.imshow(obama_image)plt.title('obama')plt.axis('off')plt.show()plt.imshow(unknown_image)plt.title('unknown')plt.axis('off')plt.show()# 绘图pil_image = Image.fromarray(unknown_image)draw = ImageDraw.Draw(pil_image)# 未知人脸图片中每张人脸处理for (top, right, bottom, left), face_encoding in zip(face_locations, face_encodings):# 判断和哪张人脸匹配matches = pare_faces(known_face_encodings, face_encoding)name = "Unknown"# 结果匹配方式1# 有多张人脸匹配成功,只以匹配的第一张人脸为结果# if True in matches:#first_match_index = matches.index(True)#name = known_face_names[first_match_index]# 结果匹配方式2# 一种更好的结果匹配方式,使用距离新面孔最小的已知面孔为结果# 计算已知人脸和未知人脸特征向量的距离,距离越小表示两张人脸为同一个人的可能性越大face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)# 提取和未知人脸距离最小的已知人脸编号best_match_index = np.argmin(face_distances)# 提取匹配的已知人脸名if matches[best_match_index]:name = known_face_names[best_match_index]# 为人脸画边界框draw.rectangle(((left, top), (right, bottom)), outline=(0, 0, 255))# 在人脸边界框下方绘制该人脸所属人的名字text_width, text_height = draw.textsize(name)draw.rectangle(((left, bottom - text_height - 10), (right, bottom)), fill=(0, 0, 255), outline=(0, 0, 255))draw.text((left + 6, bottom - text_height - 5), name, fill=(255, 255, 255, 255))del draw# jupyter 绘图# pil_image.show()plt.imshow(pil_image)plt.axis('off')plt.show()# 保存识别结果# pil_image.save("image_with_boxes.jpg")

4.3 在不同精度上进行人脸比对

来自examples/face_distance.py

该部分代码功能类似4.1,区别在于根据人脸特征向量的距离和不同距离阈值来判断两张人脸是否表示的是同一个人

import face_recognition# 加载图像known_obama_image = face_recognition.load_image_file("test_img/obama.jpg")known_biden_image = face_recognition.load_image_file("test_img/biden.jpg")# 获得人脸图像特征obama_face_encoding = face_recognition.face_encodings(known_obama_image)[0]biden_face_encoding = face_recognition.face_encodings(known_biden_image)[0]known_encodings = [obama_face_encoding,biden_face_encoding]# 加载未知人脸图像image_to_test = face_recognition.load_image_file("test_img/obama2.jpg")image_to_test_encoding = face_recognition.face_encodings(image_to_test)[0]# 计算未知人脸和已知人脸的距离face_distances = face_recognition.face_distance(known_encodings, image_to_test_encoding)# 查看不同距离阈值下的人脸匹配结果for i, face_distance in enumerate(face_distances):# 打印距离print("The test image has a distance of {:.2} from known image #{}".format(face_distance, i))# 当阈值为0.6,是否匹配print("- With a normal cutoff of 0.6, would the test image match the known image? {}".format(face_distance < 0.6))# 当阈值为更严格的0.5,是否匹配print("- With a very strict cutoff of 0.5, would the test image match the known image? {}".format(face_distance < 0.5))print()

The test image has a distance of 0.35 from known image #0- With a normal cutoff of 0.6, would the test image match the known image? True- With a very strict cutoff of 0.5, would the test image match the known image? TrueThe test image has a distance of 0.82 from known image #1- With a normal cutoff of 0.6, would the test image match the known image? False- With a very strict cutoff of 0.5, would the test image match the known image? False

4.4 基于K最近邻KNN分类算法进行人脸识别

来自examples/face_recognition_knn.py

该部分代码和前面部分代码是一样的,只是最后提取人脸特征后用KNN近邻算法进行分类,而不是用距离来判断。

%matplotlib inline"""使用k-最近邻(KNN)算法进行人脸识别的示例"""from matplotlib import pyplot as pltimport mathfrom sklearn import neighborsimport osimport os.pathimport picklefrom PIL import Image, ImageDrawimport face_recognitionfrom face_recognition.face_recognition_cli import image_files_in_folderALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg'}def train(train_dir, model_save_path=None, n_neighbors=None, knn_algo='ball_tree', verbose=False):"""训练k近邻分类器进行人脸识别。:param train_dir: 包含每个已知人员及其人脸的目录。Structure:<train_dir>/├── <person1>/│ ├── <somename1>.jpeg│ ├── <somename2>.jpeg│ ├── ...├── <person2>/│ ├── <somename1>.jpeg│ └── <somename2>.jpeg└── ...:param model_save_path: (可选) 模型保存目录:param n_neighbors: (可选) 分类中要加权的邻居数。如果未指定,则自动选择,就是k-NN的k的值,选取最近的k个点:param knn_algo: (可选) knn底层的搜索算法:param verbose: 打印训练信息:return: 返回训练好的模型"""X = []y = []# 读取人员路径for class_dir in os.listdir(train_dir):if not os.path.isdir(os.path.join(train_dir, class_dir)):continue# 读取当前人员的人脸图片for img_path in image_files_in_folder(os.path.join(train_dir, class_dir)):# 加载图片image = face_recognition.load_image_file(img_path)# 人脸检测face_bounding_boxes = face_recognition.face_locations(image)if len(face_bounding_boxes) != 1:# 没有人就跳过当前图片if verbose:print("Image {} not suitable for training: {}".format(img_path, "Didn't find a face" if len(face_bounding_boxes) < 1 else "Found more than one face"))else:# 保存人脸特征和类别X.append(face_recognition.face_encodings(image, known_face_locations=face_bounding_boxes)[0])y.append(class_dir)# 自定设置n_neighborsif n_neighbors is None:n_neighbors = int(round(math.sqrt(len(X))))if verbose:print("Chose n_neighbors automatically:", n_neighbors)# 训练KNN分类器knn_clf = neighbors.KNeighborsClassifier(n_neighbors=n_neighbors, algorithm=knn_algo, weights='distance')knn_clf.fit(X, y)# 保存分类器if model_save_path is not None:with open(model_save_path, 'wb') as f:pickle.dump(knn_clf, f)return knn_clfdef predict(X_img_path, knn_clf=None, model_path=None, distance_threshold=0.6):"""使用经过训练的KNN分类器识别给定图像中的人脸:param X_img_path: 输入图像:param knn_clf: (可选) knn模型,和model_path必须有一个可用:param model_path: (可选) knn模型路径,和knn_clf必须有一个可用:param distance_threshold: (可选) 人脸分类的距离阈值。阈值越大,就越容易误报。:return: 人脸对应的人名和其边界框"""if not os.path.isfile(X_img_path) or os.path.splitext(X_img_path)[1][1:] not in ALLOWED_EXTENSIONS:raise Exception("Invalid image path: {}".format(X_img_path))if knn_clf is None and model_path is None:raise Exception("Must supply knn classifier either thourgh knn_clf or model_path")# 加载模型if knn_clf is None:with open(model_path, 'rb') as f:knn_clf = pickle.load(f)# 读取图片和进行人脸检测X_img = face_recognition.load_image_file(X_img_path)X_face_locations = face_recognition.face_locations(X_img)# 如果没有检测到人脸就返回空listif len(X_face_locations) == 0:return []# 提取人脸特征faces_encodings = face_recognition.face_encodings(X_img, known_face_locations=X_face_locations)# 使用K近邻进行分类closest_distances = knn_clf.kneighbors(faces_encodings, n_neighbors=1)are_matches = [closest_distances[0][i][0] <= distance_threshold for i in range(len(X_face_locations))]# 返回预测结果return [(pred, loc) if rec else ("unknown", loc) for pred, loc, rec inzip(knn_clf.predict(faces_encodings), X_face_locations, are_matches)]def show_prediction_labels_on_image(img_path, predictions):"""预测结果可视化:param img_path: 预测图像:param predictions: 预测结果:return:"""pil_image = Image.open(img_path).convert("RGB")draw = ImageDraw.Draw(pil_image)for name, (top, right, bottom, left) in predictions:# 画框draw.rectangle(((left, top), (right, bottom)), outline=(0, 0, 255))# 设置名字,需要用uft-8编码name = name.encode("UTF-8")# 标注人名text_width, text_height = draw.textsize(name)draw.rectangle(((left, bottom - text_height - 10), (right, bottom)), fill=(0, 0, 255), outline=(0, 0, 255))draw.text((left + 6, bottom - text_height - 5), name, fill=(255, 255, 255, 255))del draw# jupyter 绘图# pil_image.show()plt.imshow(pil_image)plt.axis('off')plt.show()if __name__ == "__main__":# 训练图片下载地址:/ageitgey/face_recognition/tree/master/examples/knn_examples# STEP 1 训练KNN分类器print("Training KNN classifier...")classifier = train("./test_img/knn_examples/train", model_save_path="trained_knn_model.clf", n_neighbors=2)print("Training complete!")# STEP 2 使用训练好的KNN分类器对测试的人脸图像进行识别for image_file in os.listdir("./test_img/knn_examples/test"):# 待测试人脸图像路径full_file_path = os.path.join("./test_img/knn_examples/test", image_file)print("Looking for faces in {}".format(image_file))# 用经过训练的分类器模型查找图像中的所有人predictions = predict(full_file_path, model_path="trained_knn_model.clf")# 打印结果for name, (top, right, bottom, left) in predictions:print("- Found {} at ({}, {})".format(name, left, top))# 展示结果show_prediction_labels_on_image(os.path.join("./test_img/knn_examples/test", image_file), predictions)

Training KNN classifier...Training complete!Looking for faces in alex_lacamoire1.jpg- Found alex_lacamoire at (633, 206)

Looking for faces in johnsnow_test1.jpg- Found kit_harington at (262, 180)

Looking for faces in kit_with_rose.jpg- Found rose_leslie at (79, 130)- Found kit_harington at (247, 92)

Looking for faces in obama1.jpg- Found obama at (546, 204)

Looking for faces in obama_and_biden.jpg- Found biden at (737, 449)- Found obama at (1133, 390)- Found unknown at (1594, 1062)

4.5 基准性能测试

来自examples/benchmark.py

该部分代码实现一个非常简单的基准测试,可以让您了解人脸识别的每一步在您的系统上运行的速度

import timeit# 这是一个非常简单的基准测试,可以让您了解人脸识别的每一步在您的系统上运行的速度。请注意,在较大的图像大小下,人脸检测变得非常缓慢TEST_IMAGES = ["test_img/obama-240p.jpg","test_img/obama-480p.jpg","test_img/obama-720p.jpg","test_img/obama-1080p.jpg"]# 测试函数def run_test(setup, test, iterations_per_test=2, tests_to_run=3):""":param setup: 数据加载函数:param test: 数据测试函数:param iterations_per_test: 测试次数:param tests_to_run: 每轮测试调用函数多少次:return: execution_time单次函数推理时间,fps每秒处理次数"""fastest_execution = min(timeit.Timer(test, setup=setup).repeat(tests_to_run, iterations_per_test))execution_time = fastest_execution / iterations_per_testfps = 1.0 / execution_timereturn execution_time, fps# 以下设置不同的测试函数代码# setup开头的是数据加载代码,test开头的是函数测试代码setup_locate_faces = """import face_recognitionimage = face_recognition.load_image_file("{}")"""test_locate_faces = """face_locations = face_recognition.face_locations(image)"""setup_face_landmarks = """import face_recognitionimage = face_recognition.load_image_file("{}")face_locations = face_recognition.face_locations(image)"""test_face_landmarks = """landmarks = face_recognition.face_landmarks(image, face_locations=face_locations)[0]"""setup_encode_face = """import face_recognitionimage = face_recognition.load_image_file("{}")face_locations = face_recognition.face_locations(image)"""test_encode_face = """encoding = face_recognition.face_encodings(image, known_face_locations=face_locations)[0]"""setup_end_to_end = """import face_recognitionimage = face_recognition.load_image_file("{}")"""test_end_to_end = """encoding = face_recognition.face_encodings(image)[0]"""# 所有的基准测试都只使用一个CPU核心print("Benchmarks (Note: All benchmarks are only using a single CPU core)")print()for image in TEST_IMAGES:size = image.split("-")[1].split(".")[0]print("Timings at {}:".format(size))# 测试人脸检测print(" - Face locations: {:.4f}s ({:.2f} fps)".format(*run_test(setup_locate_faces.format(image), test_locate_faces)))print(" - Face landmarks: {:.4f}s ({:.2f} fps)".format(*run_test(setup_face_landmarks.format(image), test_face_landmarks)))print(" - Encode face (inc. landmarks): {:.4f}s ({:.2f} fps)".format(*run_test(setup_encode_face.format(image), test_encode_face)))print(" - End-to-end: {:.4f}s ({:.2f} fps)".format(*run_test(setup_end_to_end.format(image), test_end_to_end)))print()

Benchmarks (Note: All benchmarks are only using a single CPU core)Timings at 240p:- Face locations: 0.0819s (12.21 fps)- Face landmarks: 0.0029s (344.69 fps)- Encode face (inc. landmarks): 0.4879s (2.05 fps)- End-to-end: 0.5978s (1.67 fps)Timings at 480p:- Face locations: 0.3257s (3.07 fps)- Face landmarks: 0.0028s (362.23 fps)- Encode face (inc. landmarks): 0.4959s (2.02 fps)- End-to-end: 0.8203s (1.22 fps)Timings at 720p:- Face locations: 0.7046s (1.42 fps)- Face landmarks: 0.0028s (355.30 fps)- Encode face (inc. landmarks): 0.4993s (2.00 fps)- End-to-end: 1.1888s (0.84 fps)Timings at 1080p:- Face locations: 1.5179s (0.66 fps)- Face landmarks: 0.0030s (334.93 fps)- Encode face (inc. landmarks): 0.4838s (2.07 fps)- End-to-end: 1.9404s (0.52 fps)

4.6 多线程人脸识别

来自facerec_from_webcam_multiprocessing.py

该部分代码实现多线程读取视频进行人脸识别,很简单但是实际不这样写,看看代码就好。

import face_recognitionimport cv2from multiprocessing import Process, Manager, cpu_count, set_start_methodimport timeimport numpyimport threadingimport platform# 多线程运行人脸识别# 获取下一个线程的iddef next_id(current_id, worker_num):if current_id == worker_num:return 1else:return current_id + 1# 获取上一个线程的iddef prev_id(current_id, worker_num):if current_id == 1:return worker_numelse:return current_id - 1# 读图线程def capture(read_frame_list, Global, worker_num):# 读取视频video_capture = cv2.VideoCapture('./test_img/short_hamilton_clip.mp4')print("Width: %d, Height: %d, FPS: %d" % (video_capture.get(3), video_capture.get(4), video_capture.get(5)))while not Global.is_exit:# 判断是否该读图 确保当前缓存图像的线程和下一个处理图像的线程不是一个线程,以确保在处理线程开始前缓存图像if Global.buff_num != next_id(Global.read_num, worker_num):# 读取一张图像ret, frame = video_capture.read()read_frame_list[Global.buff_num] = frame # 保存对应图像处理线程要处理的图像Global.buff_num = next_id(Global.buff_num, worker_num) # 下一个要缓存图像的图像处理线程else:time.sleep(0.01)# 释放视频video_capture.release()# 图片处理线程def process(worker_id, read_frame_list, write_frame_list, Global, worker_num):known_face_encodings = Global.known_face_encodingsknown_face_names = Global.known_face_nameswhile not Global.is_exit:# 等待读取图片 当线程是需要处理图像的线程时开始处理图像,同时要确保图像已经缓存while Global.read_num != worker_id or Global.read_num != prev_id(Global.buff_num, worker_num):# 判断是否退出if Global.is_exit:breaktime.sleep(0.01)# 延迟读取保证计算量time.sleep(Global.frame_delay)# 读取一张图像frame_process = read_frame_list[worker_id]# 设置下一个读取视频的线程Global.read_num = next_id(Global.read_num, worker_num)# 交换通道rgb_frame = frame_process[:, :, ::-1]# 人脸识别face_locations = face_recognition.face_locations(rgb_frame)face_encodings = face_recognition.face_encodings(rgb_frame, face_locations)# 人脸绘图for (top, right, bottom, left), face_encoding in zip(face_locations, face_encodings):# 是否和已知人脸匹配matches = pare_faces(known_face_encodings, face_encoding)name = "Unknown"# 如果有匹配人脸,就替换为匹配到人脸的名字if True in matches:first_match_index = matches.index(True)name = known_face_names[first_match_index]# 绘制边界框cv2.rectangle(frame_process, (left, top), (right, bottom), (0, 0, 255), 2)# 绘制人脸标签cv2.rectangle(frame_process, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)font = cv2.FONT_HERSHEY_DUPLEXcv2.putText(frame_process, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1)# 当前线程是否允许保存图像while Global.write_num != worker_id:time.sleep(0.01)# 保存结果write_frame_list[worker_id] = frame_process# 下一个保存图像的图像处理线程Global.write_num = next_id(Global.write_num, worker_num)if __name__ == '__main__':# Macos设置if platform.system() == 'Darwin':set_start_method('forkserver')# 全局变量Global = Manager().Namespace()Global.buff_num = 1 # 正在缓存图像的图像处理线程Global.read_num = 1 # 正在处理图像的图像线程Global.write_num = 1 # 正在保存结果的图像处理线程Global.frame_delay = 0 # 延迟时间Global.is_exit = False # 是否退出read_frame_list = Manager().dict()write_frame_list = Manager().dict()# 处理线程数if cpu_count() > 2:# 减1是为了留出一个线程读取视频worker_num = cpu_count() - 1else:worker_num = 2# 子线程列表p = []# 创建一个线程来捕获帧(如果使用子线程,它将在Mac上崩溃)# 线程0为读图线程p.append(threading.Thread(target=capture, args=(read_frame_list, Global, worker_num,)))p[0].start()# 读取已有图像obama_image = face_recognition.load_image_file("./test_img/obama.jpg")obama_face_encoding = face_recognition.face_encodings(obama_image)[0]biden_image = face_recognition.load_image_file("./test_img/lin-manuel-miranda.png")biden_face_encoding = face_recognition.face_encodings(biden_image)[0]# 创建已有数据信息Global.known_face_encodings = [obama_face_encoding,biden_face_encoding]Global.known_face_names = ["Barack Obama","lin-manuel-miranda."]# 创建图像处理子线程for worker_id in range(1, worker_num + 1):p.append(Process(target=process, args=(worker_id, read_frame_list, write_frame_list, Global, worker_num,)))p[worker_id].start()# 开始读取视频last_num = 1 # 已经处理好的图像序列号fps_list = []tmp_time = time.time()while not Global.is_exit:while Global.write_num != last_num:last_num = int(Global.write_num)# 计算FPSdelay = time.time() - tmp_timetmp_time = time.time()fps_list.append(delay)if len(fps_list) > 5 * worker_num:fps_list.pop(0)fps = len(fps_list) / numpy.sum(fps_list)print("fps: %.2f" % fps)# 根据延时动态调整检测性能if fps < 6:Global.frame_delay = (1 / fps) * 0.75elif fps < 20:Global.frame_delay = (1 / fps) * 0.5elif fps < 30:Global.frame_delay = (1 / fps) * 0.25else:Global.frame_delay = 0# 展示结果cv2.imshow('Video', write_frame_list[prev_id(Global.write_num, worker_num)])# 退出if cv2.waitKey(1) & 0xFF == ord('q'):Global.is_exit = Truebreaktime.sleep(0.01)

5 参考

5.1 代码

face_recognitiondlibface_recognition函数接口

5.2 文档

face_recognition中文使用说明[常用工具] dlib编译调用指南人脸检测和人脸识别原理

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。