开发工具与环境
选择使用Visual Studio Code作为主要的开发工具。
安装其他相关的工具和库,face_recognition和cv2: OpenCV ,它们分别用于面部识别和视频捕捉和图像处理。
整体架构流程
该程序采用模块化设计,其各模块函数功能如下:
load_target_images: 加载目标人物的图像并生成面部编码。
initialize_camera: 初始化摄像头并设置参数。
recognize_faces: 主要的面部识别和标注逻辑,包含一个无限循环,处理每一帧视频。
cleanup: 释放资源,关闭摄像头和窗口。
主程序main:调用上述函数,执行面部识别流程。
这种结构清晰易懂,便于后续维护和扩展。
其核心模块recognize_faces流程图如下:
核心数据结构
-
面部特征编码 (face_encoding)
数据类型: numpy.ndarray
用途: 存储一个面部的128维特征向量,该特征向量用于表示面部的独特特征。
face_recognition.face_encodings(image) 函数会返回一个包含所有检测到的面部特征编码的列表。每个编码是一个长度为128的浮点数数组,代表面部的独特特征。 -
视频帧 (frame)
数据类型: numpy.ndarray
用途: 存储从摄像头捕捉到的单帧图像。
video_capture.read()函数会返回两个值:ret 是一个布尔值,表示是否成功读取帧;frame是捕获到的图像,通常是一个三维数组,表示图像的高、宽和颜色通道(BGR格式)。 -
面部位置 (face_locations)
数据类型: list of tuple
用途: 存储在图像中检测到的所有面部的位置,每个位置由一个包含四个整数的元组表示。
face_recognition.face_locations(image)函数会返回一个包含所有检测到的面部位置的列表。每个位置由四个值组成的元组 (top, right, bottom, left),表示面部在图像中的位置。 -
面部距离 (face_distance)
数据类型: list of float
用途: 存储一个面部特征编码与目标面部特征编码之间的距离。
face_recognition.face_distance(known_face_encodings, face_encoding_to_check) 函数会返回一个列表,包含每个已知面部特征编码与待检查的面部特征编码之间的距离。距离越小,表示两个面部特征越相似。
核心算法解释
- 一
target_face_encoding1 = face_recognition.face_encodings(target_image1)[0]
对加载的目标图像target_image1进行面部编码,并提取该图像中的第一个面部特征编码。
-
face_recognition.face_encodings(target_image1):
函数作用: face_recognition.face_encodings是face_recognition库中的一个函数,用于从给定的图像中检测并提取面部特征编码。
参数:
target_image1: 这是之前加载的目标图像,以 NumPy 数组的形式表示。该图像包含了需要识别的目标人物的面部。
返回值: 该函数返回一个列表,列表中的每个元素都是一个面部特征编码(长度为128的浮点数数组)。每个编码表示图像中一个检测到的面部。
如果图像中有多个面部,这个列表会包含多个编码。
如果图像中没有检测到面部,列表会是空的。 -
[0]:
作用: 索引操作,用于提取列表中的第一个元素。
原因: 通常情况下,每张图像只包含一个目标面部。因此,我们只需要提取第一个(也是唯一一个)面部特征编码。如果图像中可能包含多个面部,这种操作需要小心,确保选择的是正确的面部特征编码。 -
target_face_encoding1
作用: 将提取到的第一个面部特征编码赋值给变量target_face_encoding1。
用途:target_face_encoding1用于在后续的面部识别过程中,与实时捕获的视频帧中的面部特征编码进行比较,以确定视频帧中的面部是否与目标人物匹配。
这行代码的核心在于将图像中检测到的面部特征编码提取出来,为后续的识别操作做准备。
- 二
ret, frame = video_capture.read()
从摄像头捕捉一帧视频图像。
- video_capture.read():
函数作用: read()方法是 OpenCV 中 VideoCapture类的一部分,用于从视频流(通常是摄像头)中读取一帧图像。
返回值:
ret: 一个布尔值,表示读取是否成功。如果成功读取到一帧图像,则 ret为True,否则为False。
frame: 读取到的视频帧,是一个 NumPy 数组,表示捕获的图像。它的作用是存储读取到的图像帧,是一个多维数组。通常情况下,这个数组的形状是 (height, width, 3),表示图像的高度、宽度和颜色通道(BGR格式)。 - 在使用 read()方法之前,需要初始化摄像头。例如:
video_capture = cv2.VideoCapture(0) 这里,0通常表示默认的摄像头设备。如果有多个摄像头,可以传递不同的索引值来选择不同的设备。 - ret, frame = video_capture.read() 是一个用于从摄像头捕获视频帧的重要函数调用。ret表示捕获是否成功,frame存储捕获到的视频帧图像。该方法是实时视频处理和计算机视觉应用中非常常见的操作,用于获取摄像头的实时图像进行进一步处理。
- 三
face_locations = face_recognition.face_locations(frame)
检测图像帧中的所有面部位置。
face_recognition.face_locations(frame):
函数作用: 该函数用于在给定的图像(frame)中检测所有人脸的位置。
参数:
frame: 这是一个包含图像数据的NumPy数组,通常是从视频捕获设备读取的一帧图像。
返回值: 该函数返回一个列表,每个列表项是一个元组,表示检测到的一个面部的位置。每个返回的元组包含四个整数,分别表示面部在图像中的位置。具体格式如下:
(top, right, bottom, left)
top: 面部边界的上边缘的y坐标。
right: 面部边界的右边缘的x坐标。
bottom: 面部边界的下边缘的y坐标。
left: 面部边界的左边缘的x坐标。
frame 是从摄像头捕获的一帧图像,通常是一个三维的NumPy数组,形状为 (height, width, 3),表示图像的高度、宽度和颜色通道(BGR格式)。
face_recognition.face_locations(frame) 函数用于检测图像中的所有面部位置,并返回这些位置的坐标。每个面部位置由一个元组 (top, right, bottom, left) 表示,指示面部在图像中的具体位置。这些信息可以用于在图像上绘制面部边界框,或进行进一步的面部识别处理。
- 四
face_encodings = face_recognition.face_encodings(frame, face_locations)
在给定图像帧(frame)中的特定面部位置(face_locations)提取面部特征编码。
分解与解释:
face_recognition.face_encodings(frame, face_locations):
函数作用: 该函数用于在指定的面部位置提取面部特征编码(128维的向量),这些特征编码可以用于面部比较和识别。
参数:
frame: 包含图像数据的NumPy数组,通常是从视频捕获设备读取的一帧图像。
face_locations: 一个列表,包含图像中所有检测到的面部位置。每个位置用一个元组表示,格式为 (top, right, bottom, left)。
返回值: 返回一个列表,每个列表项是一个面部特征编码(长度为128的浮点数数组),对应于 face_locations 中的每个面部位置。每个面部特征编码是一个128维的浮点数数组,表示该面部的特征。这个编码是通过预训练的深度学习模型生成的,可以用于面部识别。
详细过程:
先输入图像和面部位置:frame 是从摄像头捕获的一帧图像。face_locations 是之前检测到的图像中所有面部的位置,每个位置用 (top, right, bottom, left) 表示。
然后调用 face_recognition.face_encodings 函数:该函数会处理输入的图像,并在指定的面部位置提取特征编码。返回的面部特征编码是一个128维的浮点数数组,可以用于面部比较和识别。这些编码可以在后续的步骤中与已知面部的编码进行比较,以实现面部识别功能。
- 五
face_distance1 = face_recognition.face_distance([target_face_encoding1], face_encoding)
计算当前检测到的面部特征编码与目标面部特征编码之间的距离(即相似度)。
分解与解释:
face_recognition.face_distance([target_face_encoding1], face_encoding):
函数作用: 该函数用于计算两个面部特征编码之间的距离。距离越小,表示两个面部越相似。
参数:
[target_face_encoding1]: 一个列表,包含一个已知目标面部的特征编码。即目标面部的128维浮点数数组。
face_encoding: 当前检测到的面部特征编码,也是一个128维浮点数数组。
返回值: 返回一个包含距离值的NumPy数组。因为第一个参数是一个列表,所以返回的数组中每个元素表示face_encoding与列表中对应元素的距离。在这个例子中,返回的数组只有一个元素,即目标面部编码与当前面部编码的距离。
距离的意义:距离表示两个面部特征编码的相似度。通常来说,距离越小,表示两个面部越相似。距离越大,表示两个面部越不相似。
源代码
程序代码:
# 导入必要的库
import face_recognition
import cv2
import time # 此处未使用,可以移除
from scipy.spatial import distance # 此处未使用,可以移除
# 加载目标人群的图像并学习如何识别它们
def load_target_images():
target_image1 = face_recognition.load_image_file("target_person1.jpg")
target_face_encoding1 = face_recognition.face_encodings(target_image1)[0]
target_image2 = face_recognition.load_image_file("target_person2.jpg")
target_face_encoding2 = face_recognition.face_encodings(target_image2)[0]
return target_face_encoding1, target_face_encoding2
# 初始化摄像头
def initialize_camera():
video_capture = cv2.VideoCapture(0)
video_capture.set(3, 620) # 设置视频宽度
video_capture.set(4, 240) # 设置视频高度
fps = 10 # 设置帧率为10帧每秒
video_capture.set(cv2.CAP_PROP_FPS, fps)
return video_capture
# 面部识别和标注
def recognize_faces(video_capture, target_face_encoding1, target_face_encoding2):
while True:
# 抓取一帧视频
ret, frame = video_capture.read()
# 将视频帧中的所有脸部位置找出来
face_locations = face_recognition.face_locations(frame)
face_encodings = face_recognition.face_encodings(frame, face_locations)
# 在这个视频帧中的每个脸部上循环
for (top, right, bottom, left), face_encoding in zip(face_locations, face_encodings):
# 计算面部与目标面部的距离
face_distance1 = face_recognition.face_distance([target_face_encoding1], face_encoding)
face_distance2 = face_recognition.face_distance([target_face_encoding2], face_encoding)
# 默认框颜色设置为蓝色
box_color = (255, 0, 0) # 蓝色框
# 设置一个阈值
if face_distance1[0] < 0.49:
name = "Target 1"
elif face_distance2[0] < 0.49:
name = "Target 2"
else:
name = "Unknown"
# 画框并标注结果
cv2.rectangle(frame, (left, top), (right, bottom), box_color, 2)
cv2.rectangle(frame, (left, bottom - 35), (right, bottom), box_color, cv2.FILLED)
font = cv2.FONT_HERSHEY_DUPLEX
cv2.putText(frame, name, (left + 6, bottom - 6), font, 0.5, (255, 255, 255), 1)
# 显示结果图像
cv2.imshow('Video', frame)
# 按'q'退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头和关闭窗口
def cleanup(video_capture):
video_capture.release()
cv2.destroyAllWindows()
# 主程序
def main():
target_face_encoding1, target_face_encoding2 = load_target_images()
video_capture = initialize_camera()
recognize_faces(video_capture, target_face_encoding1, target_face_encoding2)
cleanup(video_capture)
if __name__ == "__main__":
main()
注意,我们需要将待识别人脸照片放在和主程序同一文件夹下,路径不要有中文出现。
target_image1 = face_recognition.load_image_file("target_person1.jpg")
这里的target_person1.jpg是我要识别的照片文件名,可以根据需要添加多张待识别的人脸照片。
最后运行主程序,弹出识别窗口,将主机摄像头打开进行识别,若主机无自带摄像头可以购买外设摄像头。
感谢您的阅读,如有问题欢迎与作者联系。