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

article/2025/10/25 1:04:15

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代码,没有实例说明。

当然在成熟的商业工程应用不只有这三个部分,比如还有人脸质量判断,活体检测之类的,但是一般的项目都包含这三大步骤。关于人脸识别的更多介绍见:https://www.cnblogs.com/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:对图像进行上采样次数以找到更小的人脸,默认为1
    • model:检测模型,默认是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 inline
import matplotlib.pyplot as plt 
from PIL import Image
import 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

png

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

来自examples/find_faces_in_picture_cnn.py

%matplotlib inline
import matplotlib.pyplot as plt 
from PIL import Image
import 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

png

2.3 人脸马赛克

来自examples/blur_faces_on_webcam.py

%matplotlib inline
import matplotlib.pyplot as plt
import face_recognition
import 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>

png

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 inline
import matplotlib.pyplot as plt 
from PIL import Image, ImageDraw
import 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.

png

3.2 人脸涂色

来自examples/digital_makeup.py

%matplotlib inline
import matplotlib.pyplot as plt
from PIL import Image, ImageDraw
import 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()

png

3.3 人眼睁闭状态识别

来自examples / blink_detection.py

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

import matplotlib.pylab as plt
import face_recognition
import cv2
from 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 

png

frame 1 | MAYBE EYES CLOSED 

png

frame 2 | MAYBE EYES CLOSED 

png

frame 3 | EYES CLOSED

png

frame 4 | EYES OPENED 

png

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
    • 返回:包含人脸特征的列表
  • face_recognition.api.compare_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 inline
import matplotlib.pyplot as plt
from PIL import Image, ImageDraw
import 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 = face_recognition.compare_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))

png

png

png

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

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

来自examples/identify_and_draw_boxes_on_faces.py

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

%matplotlib inline
import matplotlib.pyplot as plt
import face_recognition
from PIL import Image, ImageDraw
import 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 = face_recognition.compare_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")

png

png

png

png

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 plt
import math
from sklearn import neighbors
import os
import os.path
import pickle
from PIL import Image, ImageDraw
import face_recognition
from 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__":# 训练图片下载地址:https://github.com/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)

png

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

png

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

png

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

png

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

png

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_recognition
import cv2
from multiprocessing import Process, Manager, cpu_count, set_start_method
import time
import numpy
import threading
import platform# 多线程运行人脸识别
# 获取下一个线程的id
def next_id(current_id, worker_num):if current_id == worker_num:return 1else:return current_id + 1# 获取上一个线程的id
def 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 = face_recognition.compare_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_recognition
  • dlib
  • face_recognition函数接口

5.2 文档

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

http://chatgpt.dhexx.cn/article/xcJiCueE.shtml

相关文章

Face Recognition 库-人脸识别

1. Face Recognition 库简介&#xff1a; 中文文档&#xff1a; [face_recognition/README_Simplified_Chinese.md] Face Recognition 库主要封装了dlib这一 C 图形库&#xff0c;通过 Python 语言将它封装为一个非常简单就可以实现人脸识别的 API 库&#xff0c;屏蔽了人脸识…

应用层下的人脸识别(二):人脸库

本文为系列文章的第二篇&#xff0c;介绍人脸库的相关内容。人脸库是人脸识别的基础&#xff0c;建立人脸库往往是人脸项目的首要任务&#xff0c;全文围绕着什么是人脸库及如何建立人脸库展开讨论。 1. 什么是人脸库 简单来讲&#xff0c;人脸库就是人脸数据的储存管理中心&a…

全国高校计算机能力挑战赛Java试题(一)

消除字符串 这个题目上来就是运用一个回文的一个思想&#xff0c;我目前算法也是入门阶段&#xff0c;所以也处于学习阶段。 public class xiaozfc {public static void main(String[] args) {Scanner sc new Scanner(System.in);String txt sc.next();ArrayList<String&…

Java课程设计--学生成绩管理系统

一、团队名称&#xff1a; 团队成员&#xff1a; 刘江华 2019122249819 19信管专升本杨利杰 2018122241648 18信管本张富强 2018122241658 18信管本 二、需求分析 1.数据存储在数据库和文件中 分为“教师”模块和“学生”模块。 2.学生模块提供登陆功能&#xff0c;登陆成功后…

Java8--20道关于Stream流的题目练习

正题开始 Student 类 具有属性&#xff1a; 不及格次数failCount&#xff0c; 名字name&#xff0c; 科任老师chineseTeacher&#xff0c; 班主任classTeacher题目1&#xff1a;筛选学生不及格次数3次及3次以上的学生列表 List<String> arrayList array.stream().filte…

第十三届蓝桥杯省赛 JAVA B组(真题解析+个人体会)(已更新完G题)

试题 A: 星期计算【填空题】 题目&#xff1a; 答案&#xff1a;7 解析&#xff1a; 此题直接对7求余即可。 public class Main {public static void main(String[] args) {System.out.println(Math.pow(20, 22) % 7 6);} } 贴一个BigInteger的代码 import java.math.Bi…

java的一些课程设计题目_Java课程设计

Java课程设计 1. 题目及要求 基于学校的搜索引擎 负责部分:Java GUI设计 2.界面调查 1)调查界面:百度 2)思考: 根据我的调查,我认为我需要完成三个界面的设计: 第一个是调查主界面,里面有一个集美大学的logo,一个搜索框用文本字段,因为需要在里面写入搜索内容,一个搜索…

计算机二级--java篇

计算机二级 全国计算机等级&#xff08;NCRE&#xff09;&#xff0c;计算机二级分为语言程序设计&#xff08;包括C、C、Java、Visual Basic&#xff09;、数据库程序设计&#xff08;包括Visual FoxPro、Access&#xff09;、MS Office高级应用&#xff0c;各项目均为机考。考…

java 课程设计题目_Java课程设计题目有哪些?Java课程设计题目汇总

在学习Java的路上,多多练习项目实践是很有必要的。因此,本文整理了20道Java课程设计题目,希望大家总结、回顾和实践学过的所有面向对象的编程思想以及编程方法。 1、编写一个记事本程序 要求:用图形用户界面实现。 能实现编辑、保存、另存为、查找替换等功能。 提示:使用文…

Java绘制圆形

package 坦克大战.draw;import javax.swing.*; import java.awt.*;/*** Auther:* Date: 2022/4/16 - 04 - 16 - 21:16* Description: 坦克大战.draw* version: 1.0*/ public class draw extends JFrame{//继承JFrame、JFrame对应窗口&#xff0c;可以当作一个画框//定义一个画板…

Java练习题(经典8题)

题目一 共有50枚硬币&#xff0c;可能包括4种类型&#xff1a;1元&#xff0c;5角&#xff0c;1角&#xff0c;5分。已知总价值为20元。求各种硬币的数量。 解题思路&#xff1a;简单分析可知硬币有多种组合&#xff0c;我们可以假设先抛开50枚硬币去寻找1元需要多少个硬币&…

Java中常见的30道例题(附代码)

目录 第一题&#xff1a;判断数组中奇数偶数的个数并求和 第二题&#xff1a;判断三个数中的最大值 第三题&#xff1a;剔除某些数据并打印输出 第四题&#xff1a;输入0到7判断星期几 第五题&#xff1a;将一个数组倒序输出 第六题&#xff1a;输入一个数判断是否是素数 …

Linux内核编译详细总结

一、实验目的 学习重新编译Linux内核&#xff0c;理解、掌握Linux内核和发行版本的区别。 二、实验内容 在Linux操作系统环境下重新编译内核。实验主要内容&#xff1a; A. 查找并且下载一份内核源代码&#xff0c;本实验使用最新的Linux内核2.6.36。 B. 配置内核。 C. 编…

LINUX内核目录文件说明以及配置并编译内核的方法

在下载内核前&#xff0c;我们应该讨论一些重要的术语和事实。Linux内核是一个宏内核&#xff0c;这意味着整个操作系统都运行在内核预留的内存里。说的更清楚一些&#xff0c;内核是放在内存里的。内核所使用的空间是内核预留的。只有内核可以使用预留的内核空间。内核拥有这些…

Linux内核的编译、安装、调试

这里写目录标题 编译安装内核下载内核安装依赖更改.config编译内核安装首先安装模块安装内核更改引导更改grub重启 其他操作清理内核源目录卸载安装的内核修改内核配置菜单实现对新加入内核源码的控制 常见问题1. Module.symvers is missing2. No rule to make target ‘debian…

linux内核编译及添加系统调用(详细版)

linux内核编译及添加系统调用 注&#xff1a;文章共四部分&#xff0c;分别是 1、编译更换内核 2、添加一个简单系统系统调用 3、添加读取/修改nice值的系统调用 4、自己设计简单&#xff08;真的简单&#xff09;系统调用 注&#xff1a;四个部分结构相似&#xff0c;请…

打造自己的专属linux(四):Linux内核编译过程简介

linux在前不久刚发布了最新的3.0内核&#xff0c;在linux的学习中&#xff0c;了解内核的编译是一个必不可少的功课。前几天&#xff0c;学习了linux内核的编译流程&#xff0c;在此总结下&#xff0c;大家来一起学习。 以最新的3.0内核为例&#xff0c;我下载的是linux3.0.1 …

Linux内核开发_1_编译LInux内核

目录 1. 准备工作 1.1 学习环境 1.2 下载Linux内核源码 1.3 解压Linux内核 1.4 目录结构介绍 2. Linux内核配置 2.1 配置选项 1. make config 2. make menuconfig 3. make gconfig 3 开始配置 1. 配置解释 General setup 通用选项 Enable loadable module support…

ubuntu上编译Linux内核步骤

一、虚拟机的准备 1.下载Ubuntu镜像 Enterprise Open Source and Linux | Ubuntu 在最左边Ubuntu Desktop处点22.04LTS下载iso文件 2.在VMware上创建新的虚拟机 Ubuntu 20.04 虚拟机安装教程_柯基的博客-CSDN博客_虚拟机安装ubuntu20.04 特别注意: 在"指定磁盘容量&…

Microsoft Outlook 2019 for mac(电子邮件和日历工具) v16.45Beta中文激活版

Microsoft Outlook 2019 for Mac版是一款非常好用的电子邮件和日历工具&#xff0c;Outlook是office办公软件套装的组件之一&#xff0c;可以帮助您收发电子邮件、管理联系人信息、记日记、安排日程与分配任务&#xff0c;文件视图&#xff0c;保持连接并提升生产效率等.