1. 代码部分
此代码块为extract_embeddings.py内的代码
# USAGE
# python extract_embeddings.py --dataset dataset --embeddings output/embeddings.pickle
# \ --detector face_detection_model --embedding-model openface_nn4.small2.v1.t7
# 加载必要的包
from imutils import paths
import numpy as np
import imutils
import pickle
import cv2
import os
def extract_embeddings():
## 从磁盘加载序列化人脸检测器(serialized face detector)
## 使用OpenCV的基于Caffe的深度学习人脸检测器来定位图像中人脸。
## 用途:检测或定位人脸在图像中的位置
print("[INFO] loading face detector...")
# 用cv2.dnn.readNetFromCaffe来加载Caffe模型定义prototxt,以及预训练模型。
protoPath = os.path.sep.join(['face_detection_model', "deploy.prototxt"])
modelPath = os.path.sep.join(['face_detection_model',
"res10_300x300_ssd_iter_140000.caffemodel"])
detector = cv2.dnn.readNetFromCaffe(protoPath, modelPath)
## 从磁盘加载序列化面部嵌入模型(serialized face embedding model)
## 使用OpenCV的基于Torch的深度学习面部嵌入模型来提取面部嵌入(face embedding)
## 用途:用于提取人脸的128维(128-D)面部嵌入
print("[INFO] loading face recognizer...")
embedder = cv2.dnn.readNetFromTorch(r'openface_nn4.small2.v1.t7')
## 获得输入人脸数据库的路径
# imagePaths列表包含数据集中每个图像的路径。
# 这个功能是通过imutils包中的函数paths.list_images实现的
print("[INFO] quantifying faces...")
imagePaths = list(paths.list_images(r'dataset'))
## 初始化提取的面部嵌入和相应的人名
# 我们将把提取的面部嵌入和相应的人名保存在下述两个列表中
knownEmbeddings = []
knownNames = []
## 初始化我们成功处理的人脸的数量
total = 0
## 在人脸数据库中循环,这个循环将从每个图像中找到的人脸上提取面部嵌入
for (i, imagePath) in enumerate(imagePaths):
## 从图像路径(人脸数据库)中提取人名
print("[INFO] processing image {}/{}".format(i + 1,
len(imagePaths)))
# 通过使用imagePath.split拆分字符
# 该函数生成一个沿着目录树向下走的文件夹/文件名(字符串)列表
# 我们获取倒数第二个索引,即人名
# 示例:
# >>> imagePaths = list(paths.list_images("dataset"))
# >>> imagePath = imagePaths[0]
# >>> imagePath
# 'dataset/adrian/00004.jpg'
# >>> imagePath.split(os.path.sep)
# ['dataset', 'adrian', '00004.jpg']
# >>> imagePath.split(os.path.sep)[-2]
# 'adrian'
name = imagePath.split(os.path.sep)[-2]
## 加载图像,将其宽度调整为600像素(同时保持纵横比),并读取图像尺寸
image = cv2.imread(imagePath)
image = imutils.resize(image, width=600)
# 读取图像的尺寸
(h, w) = image.shape[:2]
## 应用OpenCV中的基于深度学习的人脸检测器来检测和定位输入图像中的人脸
# 使用cv2.dnn.blobFromImag来对输入图像进行归一化,从而产生一个已知的blob形状。
# 也即从图像来创建一个blob
# 此处的知识点参考收藏:Deep learning: How OpenCV’s blobFromImage works
imageBlob = cv2.dnn.blobFromImage(
cv2.resize(image, (300, 300)), 1.0, (300, 300),
(104.0, 177.0, 123.0), swapRB=False, crop=False)
# 将imageBlob传递到detector神经网络来检测图像中的面部
detector.setInput(imageBlob)
# 以imageBlob为输入,在神经网络中完成一次正向传播,并将分类结果保存至detections
# 注:我们不是在训练DNN,而是在使用预训练模型,
# 因此只需要将blob从网络中传递过去,来获取结果,不需要反向传播。
# detections列表包含图像中的人脸的概率和定位人脸的坐标
# 注:一张照片可能检测出多张人脸,也就是说可能会有多个识别为人脸的边界框
detections = detector.forward()
## 确保即将处理的图像中包括人脸,如果不包括,则读取下一张图片
# 在图像中检测到了至少一个人脸才会进入if语句主体
if len(detections) > 0:
# 本程序假设每个照片中只有一张人脸
# 因此找到概率最大的边界框
# 也就是说要提取最高置信度的人脸的面部嵌入
i = np.argmax(detections[0, 0, :, 2])
confidence = detections[0, 0, i, 2]
## 确保即将处理的图像中人脸的概率大于一个阈值
# 设定过滤弱检测的最小概率阈值,若图像的置信度满足该阈值则进行面部嵌入的提取
if confidence > 0.5:
## 计算人脸边界框(the bounding box for the face)的(x,y)坐标
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype("int")
## 提取人脸的感兴趣区域(ROI)并获取感兴趣区域(ROI)的维度(即ROI的宽度和高度)
face = image[startY:endY, startX:endX]
(fH, fW) = face.shape[:2]
## 确保提取到的人脸的感兴趣区域(ROI)足够的大
## 如果不满足设定值,则不进行后续处理,直接读取下一张图像
if fW < 20 or fH < 20:
continue
## 使用OpenCV的基于Torch的深度学习面部嵌入模型来提取面部嵌入
## 借此来获得描述人脸的128维(128-D)面部嵌入
# 这次为人脸的感兴趣区域(ROI)构造一个blob
# (不同于第73行代码,73行是为整个图像构造blob)
faceBlob = cv2.dnn.blobFromImage(face, 1.0 / 255,
(96, 96), (0, 0, 0), swapRB=True, crop=False)
# 将faceBlob传递给面部嵌入模型卷积神经网络(embedder CNN)
embedder.setInput(faceBlob)
# 在神经网络中完成一次正向传播,并将分类结果保存至vec
# 获得描述人脸的128维(128-D)面部嵌入
# 注:我们将把这些数据作为人脸识别模型的训练数据
vec = embedder.forward()
## 将人名和相应的面部嵌入添加到各自的列表中
knownNames.append(name)
knownEmbeddings.append(vec.flatten())
# 成功处理的人脸数量的总数目加一
total += 1
#之后便是继续循环图像,检测人脸,并为人脸数据集中的每个图像提取面部嵌入
## 循环结束后将面部嵌入和人名存储到磁盘中
print("[INFO] serializing {} encodings...".format(total))
# 将面部嵌入和人名添加到data字典中
data = {"embeddings": knownEmbeddings, "names": knownNames}
# 将字典写入embeddings.pickle文件中
f = open(r'output/embeddings.pickle', "wb")
f.write(pickle.dumps(data))
f.close()
## 测试脚本用
if __name__ == '__main__':
extract_embeddings()
2. 函数结构说明
3. 程序流程图
4. 函数图解
5. 使用说明
本函数需搭配视频流人脸识别系统一起使用。
视频流人脸识别系统的系统函数见此博客:一、视频流人脸识别系统的系统函数的构建(Python)
文中用到的deploy.prototxt、res10_300x300_ssd_iter_140000.caffemodel、openface_nn4.small2.v1.t7文件在此处下载:人脸识别集成包