人脸识别实战:使用Python OpenCV 和深度学习进行人脸识别

在本教程中,您将学习如何使用 OpenCV、Python 和深度学习执行面部识别。

我们将首先简要讨论基于深度学习的面部识别的工作原理,包括“深度度量学习”的概念。 从那里,我将帮助您安装实际执行人脸识别所需的库。 最后,我们将为静止图像和视频流实现人脸识别。

理解深度学习人脸识别嵌入

那么,深度学习+人脸识别是如何运作的呢?

秘诀是一种称为深度度量学习的技术。 如果您之前有任何深度学习经验,您就会知道我们通常训练网络以: 接受单个输入图像 并输出该图像的分类/标签 然而,深度度量学习是不同的。

相反,我们不是尝试输出单个标签(甚至是图像中对象的坐标/边界框),而是输出实值特征向量。

对于 dlib 人脸识别网络,输出特征向量是 128-d(即 128 个实数值的列表),用于量化人脸。 训练网络是使用三元组完成的:

image-20211119131551638

这里我们向网络提供三张图片: 其中两张图片是同一个人的示例面孔。 第三张图片是我们数据集中的一张随机人脸,与其他两张图片不是同一个人。

作为示例,让我们再次考虑图 1,其中我们提供了三张图像:一张 Chad Smith 和两张 Will Ferrell。 我们的网络对人脸进行量化,为每个人构建 128 维嵌入(量化)。

从那里开始,一般的想法是我们将调整我们的神经网络的权重,以便两个 Will Ferrel 的 128 维测量值将彼此更接近,并且与 Chad Smith 的测量值相距更远。

我们用于人脸识别的网络架构基于 He 等人的 Deep Residual Learning for Image Recognition 论文中的 ResNet-34,但层数更少,过滤器的数量减少了一半。

网络本身由 Davis King 在 ≈300 万张图像的数据集上进行训练。在野外标记人脸 (LFW) 数据集上,该网络与其他最先进的方法进行比较,准确率达到 99.38%。 Davis King(dlib 的创建者)和 Adam Geitgey(我们将很快使用的 face_recognition 模块的作者)都写了关于基于深度学习的面部识别如何工作的详细文章:

我强烈建议您阅读上述文章,以了解有关深度学习面部嵌入如何工作的更多详细信息。

安装人脸识别库

为了使用 Python 和 OpenCV 执行人脸识别,我们需要安装两个额外的库:

由 Davis King 维护的 dlib 库包含我们的“深度度量学习”实现,用于构建用于实际识别过程的人脸嵌入。

由 Adam Geitgey 创建的 face_recognition 库包含了 dlib 的面部识别功能,使其更易于使用。

安装 dlib

pip install dlib

或者你可以从源代码编译:

git clone https://github.com/davisking/dlib.git
cd dlib
mkdir build
cd build
cmake .. -DUSE_AVX_INSTRUCTIONS=1
cmake --build .
cd ..
python setup.py install --yes USE_AVX_INSTRUCTIONS

安装支持 GPU 的 dlib(可选)

如果你有一个兼容 CUDA 的 GPU,你可以安装支持 GPU 的 dlib,使面部识别更快、更高效。 为此,我建议从源代码安装 dlib,因为您可以更好地控制构建:

$ git clone https://github.com/davisking/dlib.git
$ cd dlib
$ mkdir build
$ cd build
$ cmake .. -DDLIB_USE_CUDA=1 -DUSE_AVX_INSTRUCTIONS=1
$ cmake --build .
$ cd ..
$ python setup.py install --yes USE_AVX_INSTRUCTIONS --yes DLIB_USE_CUDA

安装 face_recognition 包

face_recognition 模块可以通过一个简单的 pip 命令安装:

pip install face_recognition

安装 imutils

您还需要我的便利功能包 imutils。 你可以通过 pip 将它安装在你的 Python 虚拟环境中:

pip install imutils

人脸识别数据集

image-20211119182347794

由于侏罗纪公园 (1993) 是我有史以来最喜欢的电影,为了纪念本周五在美国上映的侏罗纪世界:堕落王国 (2018),我们将对电影中的角色样本进行面部识别 : Alan Grant,古生物学家(22 张图片) Claire Dearing,公园运营经理(53 张图片) Ellie Sattler,古植物学家(31 张图片) 伊恩马尔科姆,数学家(41 张图片) 约翰哈蒙德,商人/侏罗纪公园所有者(36 张图片) Owen Grady,恐龙研究员(35 张图片)

获得此图像数据集,我们将:

  • 为数据集中的每个人脸创建 128 维嵌入
  • 使用这些嵌入来识别图像和视频流中人物的面部

人脸识别项目结构

myface
├── dataset
│   ├── alan_grant [22 entries]
│   ├── claire_dearing [53 entries]
│   ├── ellie_sattler [31 entries]
│   ├── ian_malcolm [41 entries]
│   ├── john_hammond [36 entries]
│   └── owen_grady [35 entries]
├── examples
│   ├── example_01.png
│   ├── example_02.png
│   └── example_03.png
├── output
│   └── lunch_scene_output.avi
├── videos
│   └── lunch_scene.mp4
├── encode_faces.py
├── recognize_faces_image.py
├── recognize_faces_video.py
├── recognize_faces_video_file.py
└── encodings.pickle

我们的项目有 4 个顶级目录:

  • dataset/ :包含六个字符的面部图像,根据它们各自的名称组织到子目录中。
  • examples/ :具有三个不在数据集中的用于测试的面部图像。
  • output/ :这是您可以存储处理过的人脸识别视频的地方。 我要把我的一个留在文件夹里——原侏罗纪公园电影中的经典“午餐场景”。
  • videos/ :输入视频应存储在此文件夹中。 该文件夹还包含“午餐场景”视频,但尚未经过我们的人脸识别系统。

我们在根目录下还有 6 个文件:

  • encode_faces.py :人脸的编码(128 维向量)是用这个脚本构建的。
  • identify_faces_image.py :识别单个图像中的人脸(基于数据集中的编码)。
  • identify_faces_video.py :识别来自网络摄像头的实时视频流中的人脸并输出视频。
  • identify_faces_video_file.py :识别驻留在磁盘上的视频文件中的人脸并将处理后的视频输出到磁盘。 我今天不会讨论这个文件,因为骨骼来自与视频流文件相同的骨架。
  • encodings.pickle :面部识别编码通过 encode_faces.py 从您的数据集生成,然后序列化到磁盘。

创建图像数据集后(使用 search_bing_api.py ),我们将运行 encode_faces.py 来构建嵌入。 然后,我们将运行识别脚本来实际识别人脸。

使用 OpenCV 和深度学习对人脸进行编码

img

在识别图像和视频中的人脸之前,我们首先需要量化训练集中的人脸。 请记住,我们实际上并不是在这里训练网络——网络已经被训练为在大约 300 万张图像的数据集上创建 128 维嵌入。

我们当然可以从头开始训练网络,甚至可以微调现有模型的权重,但这对许多项目来说很可能是矫枉过正。

此外,您将需要大量图像来从头开始训练网络。 相反,使用预训练网络然后使用它为我们数据集中的 218 张人脸中的每一张构建 128 维嵌入更容易。

然后,在分类过程中,我们可以使用一个简单的 k-NN 模型 + 投票来进行最终的人脸分类。 其他传统的机器学习模型也可以在这里使用。 要构建我们的人脸嵌入,

请新建 encode_faces.py:

# import the necessary packages
from imutils import paths
import face_recognition
import argparse
import pickle
import cv2
import os

首先,我们需要导入所需的包。 再次注意,此脚本需要安装 imutils 、 face_recognition 和 OpenCV 。 向上滚动到“安装您的人脸识别库”以确保您已准备好在您的系统上使用这些库。 让我们处理在运行时使用 argparse 处理的命令行参数:

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--dataset", required=True,
	help="path to input directory of faces + images")
ap.add_argument("-e", "--encodings", required=True,
	help="path to serialized db of facial encodings")
ap.add_argument("-d", "--detection-method", type=str, default="cnn",
	help="face detection model to use: either `hog` or `cnn`")
args = vars(ap.parse_args())

让我们列出参数标志并讨论它们:

  • –dataset :数据集的路径(我们使用上周博客文章的方法 #2 中描述的 search_bing_api.py 创建了一个数据集)。
  • –encodings :我们的人脸编码被写入这个参数指向的文件中。
  • –detection-method :在我们对图像中的人脸进行编码之前,我们首先需要检测它们。 或者两种人脸检测方法包括 hog 或 cnn 。 这两个标志是唯一适用于 --detection-method 的标志。

现在我们已经定义了我们的参数,让我们获取数据集中文件的路径(以及执行两个初始化):

# grab the paths to the input images in our dataset
print("[INFO] quantifying faces...")
imagePaths = list(paths.list_images(args["dataset"]))
# initialize the list of known encodings and known names
knownEncodings = []
knownNames = []

输入数据集目录的路径来构建其中包含的所有图像路径的列表。

我们还需要在循环之前分别初始化两个列表 knownEncodings 和 knownNames 。 这两个列表将包含数据集中每个人的面部编码和相应的姓名。 是时候开始循环我们侏罗纪公园的角色面孔了!

# loop over the image paths
for (i, imagePath) in enumerate(imagePaths):
	# extract the person name from the image path
	print("[INFO] processing image {}/{}".format(i + 1,
		len(imagePaths)))
	name = imagePath.split(os.path.sep)[-2]
	# load the input image and convert it from BGR (OpenCV ordering)
	# to dlib ordering (RGB)
	image = cv2.imread(imagePath)
	rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

这个循环将循环 218 次,对应于我们在数据集中的 218 张人脸图像。

遍历每个图像的路径。 从那里,我们将从 imagePath(因为我们的子目录被适当命名)中提取人名。 然后让我们加载图像,同时将 imagePath 传递给 cv2.imread。 OpenCV 在 BGR 中订购颜色通道,但 dlib 实际上期望 RGB。 face_recognition 模块使用 dlib ,所以在我们继续之前,让我们在第 37 行交换颜色空间,将新图像命名为 rgb 。 接下来,让我们定位人脸并计算编码:

# detect the (x, y)-coordinates of the bounding boxes
	# corresponding to each face in the input image
	boxes = face_recognition.face_locations(rgb,
		model=args["detection_method"])
	# compute the facial embedding for the face
	encodings = face_recognition.face_encodings(rgb, boxes)
	# loop over the encodings
	for encoding in encodings:
		# add each encoding + name to our set of known names and
		# encodings
		knownEncodings.append(encoding)
		knownNames.append(name)

这是剧本的有趣部分!

对于循环的每次迭代,我们将检测一张脸(或者可能是多张脸,并假设它是图像多个位置的同一个人——这个假设在你自己的图像中可能成立,也可能不成立,所以要小心 这里)。 例如,假设 rgb 包含一张(或多张)Ellie Sattler 脸部的图片。查找/定位了她的面孔,从而生成了面孔框列表。 我们将两个参数传递给 face_recognition.face_locations 方法:

  • rgb :我们的 RGB 图像。

  • model:cnn 或 hog(该值包含在与“detection_method”键关联的命令行参数字典中)。 CNN方法更准确但速度更慢。 HOG 速度更快,但准确度较低。

然后,我们将 Ellie Sattler 面部的边界框转换为 128 个数字的列表。这称为将面部编码为向量,而 face_recognition.face_encodings 方法会为我们处理它。 从那里我们只需要将 Ellie Sattler 编码和名称附加到适当的列表(knownEncodings 和 knownNames)。 我们将继续对数据集中的所有 218 张图像执行此操作。 除非我们可以在另一个处理识别的脚本中使用编码,否则对图像进行编码有什么意义? 现在让我们解决这个问题:

# dump the facial encodings + names to disk
print("[INFO] serializing encodings...")
data = {"encodings": knownEncodings, "names": knownNames}
f = open(args["encodings"], "wb")
f.write(pickle.dumps(data))
f.close()

构造了一个带有两个键的字典—— “encodings” 和 “names” 。

将名称和编码转储到磁盘以备将来调用。 我应该如何在终端中运行 encode_faces.py 脚本? 要创建我们的面部嵌入,请打开一个终端并执行以下命令:

python encode_faces.py --dataset dataset --encodings encodings.pickle
[INFO] quantifying faces...
[INFO] processing image 1/218
[INFO] processing image 2/218
[INFO] processing image 3/218
...
[INFO] processing image 216/218
[INFO] processing image 217/218
[INFO] processing image 218/218
[INFO] serializing encodings...
$ ls -lh encodings*
-rw-r--r--@ 1 adrian  staff   234K May 29 13:03 encodings.pickle

正如您从我们的输出中看到的,我们现在有一个名为 encodings.pickle 的文件——该文件包含我们数据集中每个人脸的 128 维人脸嵌入。

在我的 Titan X GPU 上,处理整个数据集需要一分钟多一点的时间,但如果您使用的是 CPU,请准备好等待此脚本完成!

在我的 Macbook Pro(无 GPU)上,编码 218 个图像需要 21 分 20 秒。

如果你有一个 GPU 并且编译的 dlib 支持 GPU,你应该期望更快的速度。

识别图像中的人脸

img

现在我们已经为数据集中的每个图像创建了 128 维人脸嵌入,现在我们可以使用 OpenCV、Python 和深度学习来识别图像中的人脸。 打开recognize_faces_image.py 并插入以下代码:

# import the necessary packages
import face_recognition
import argparse
import pickle
import cv2
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-e", "--encodings", required=True,
	help="path to serialized db of facial encodings")
ap.add_argument("-i", "--image", required=True,
	help="path to input image")
ap.add_argument("-d", "--detection-method", type=str, default="cnn",
	help="face detection model to use: either `hog` or `cnn`")
args = vars(ap.parse_args())

解析三个命令行参数:

–encodings :包含我们的面部编码的pickle文件的路径。

–image :这是正在进行面部识别的图像。

–detection-method :你现在应该很熟悉这个了——根据你系统的能力,我们要么使用 hog 方法,要么使用 cnn 方法。 为了速度,选择 hog ,为了准确,选择 cnn 。

然后,让我们加载预先计算的编码 + 人脸名称,然后为输入图像构建 128 维人脸编码:

# load the known faces and embeddings
print("[INFO] loading encodings...")
data = pickle.loads(open(args["encodings"], "rb").read())
# load the input image and convert it from BGR to RGB
image = cv2.imread(args["image"])
rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# detect the (x, y)-coordinates of the bounding boxes corresponding
# to each face in the input image, then compute the facial embeddings
# for each face
print("[INFO] recognizing faces...")
boxes = face_recognition.face_locations(rgb,
	model=args["detection_method"])
encodings = face_recognition.face_encodings(rgb, boxes)
# initialize the list of names for each face detected
names = []

从磁盘加载我们腌制的编码和人脸名称。 我们稍后将在实际的人脸识别步骤中需要这些数据。

然后,我们加载输入图像并将其转换为 rgb 颜色通道排序(就像我们在 encode_faces.py 脚本中所做的那样)。

然后我们继续检测输入图像中的所有人脸,并计算它们的 128 维编码(这些行看起来也应该很熟悉)。

现在是为检测到的每个人脸初始化名称列表的好时机——该列表将在下一步中填充。

接下来,让我们遍历面部编码:

# loop over the facial embeddings
for encoding in encodings:
	# attempt to match each face in the input image to our known
	# encodings
	matches = face_recognition.compare_faces(data["encodings"],
		encoding)
	name = "Unknown"

我们开始遍历从输入图像计算出的人脸编码。 然后面部识别魔术发生了! 我们尝试使用 face_recognition.compare_faces将输入图像(编码)中的每个人脸与我们已知的编码数据集(保存在 data[“encodings”] 中)进行匹配。

此函数返回 True / False 值列表,数据集中的每个图像对应一个值。 对于我们的侏罗纪公园示例,数据集中有 218 个图像,因此返回的列表将有 218 个布尔值。

在内部,compare_faces 函数正在计算候选嵌入与我们数据集中所有人脸之间的欧几里德距离:

  • 如果距离低于某个容差(容差越小,我们的面部识别系统就会越严格),那么我们返回 True ,表示面部匹配。
  • 否则,如果距离高于容差阈值,我们将返回 False,因为人脸不匹配。

本质上,我们正在利用“更花哨”的 k-NN 模型进行分类。 请务必参考 compare_faces 实现以获取更多详细信息。 name 变量最终将保存此人的姓名字符串——现在,我们将其保留为“Unknown”,以防没有“投票”。

给定我们的匹配列表,我们可以计算每个名字的“投票”数(与每个名字关联的 True 值的数量),统计投票数,并选择对应票数最多的人的名字:

# check to see if we have found a match
	if True in matches:
		# find the indexes of all matched faces then initialize a
		# dictionary to count the total number of times each face
		# was matched
		matchedIdxs = [i for (i, b) in enumerate(matches) if b]
		counts = {}
		# loop over the matched indexes and maintain a count for
		# each recognized face face
		for i in matchedIdxs:
			name = data["names"][i]
			counts[name] = counts.get(name, 0) + 1
		# determine the recognized face with the largest number of
		# votes (note: in the event of an unlikely tie Python will
		# select first entry in the dictionary)
		name = max(counts, key=counts.get)
	
	# update the list of names
	names.append(name)

如果匹配中有任何 True 投票,我们需要确定这些 True 值在匹配中的位置的索引。 我们就这样做了,在那里我们构造了一个简单的匹配Idxs 列表,对于 example_01.png 可能看起来像这样:

(Pdb) matchedIdxs

[35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75]

然后我们初始化一个名为 counts 的字典,它将以字符名称作为键,将投票数作为值。 从那里,让我们循环匹配的Idxs并设置与每个名称关联的值,同时根据需要在 counts 中增加它。 对于 Ian Malcolm 的高票数,counts 字典可能如下所示:

(Pdb) counts
{'ian_malcolm': 40}

回想一下,我们在数据集中只有 41 张 Ian 的照片,所以在没有给其他任何人投票的情况下,40 分是非常高的。 从 counts 中提取得票最多的名称,在本例中为 ‘ian_malcolm’ 。 主要面部编码循环的第二次循环(因为我们的示例图像中有两个人脸)为 counts 生成以下内容:

(Pdb) counts
{'alan_grant': 5}

这绝对是一个较小的投票分数,但字典中仍然只有一个名字,所以我们可能已经找到了艾伦格兰特。

如下图 5 所示,Ian Malcolm 和 Alan Grant 都已被正确识别,因此这部分脚本运行良好。 让我们继续并遍历每个人的边界框和标记名称,并将它们绘制在我们的输出图像上以进行可视化:

# loop over the recognized faces
for ((top, right, bottom, left), name) in zip(boxes, names):
	# draw the predicted face name on the image
	cv2.rectangle(image, (left, top), (right, bottom), (0, 255, 0), 2)
	y = top - 15 if top - 15 > 15 else top + 15
	cv2.putText(image, name, (left, y), cv2.FONT_HERSHEY_SIMPLEX,
		0.75, (0, 255, 0), 2)
# show the output image
cv2.imshow("Image", image)
cv2.waitKey(0)

我们开始遍历检测到的人脸边界框和预测的名称。

为了创建一个可迭代对象,以便我们可以轻松地遍历这些值,我们调用 zip(boxes, names) 生成元组,我们可以从中提取框坐标和名称。

我们使用框坐标绘制一个绿色矩形。 我们还使用坐标来计算应该在何处绘制人名文本,然后将姓名文本实际放置在图像上。如果人脸边界框在图像的最顶部,我们需要将文本移动到框顶部下方,否则文本将被截断。 然后我们继续显示图像,直到按下一个键。 您应该如何运行面部识别 Python 脚本? 使用您的终端,首先使用 workon 命令确保您在各自的 Python 正确虚拟环境中(当然,如果您使用的是虚拟环境)。

然后运行脚本,同时至少提供两个命令行参数。如果您选择使用 HoG 方法,请确保也通过 --detection-method hog(否则它将默认为深度学习检测器)。

加油吧! 要使用 OpenCV 和 Python 识别人脸,请打开您的终端并执行我们的脚本:

python recognize_faces_image.py --encodings encodings.pickle 
	--image examples/example_01.png

img

第二个人脸识别示例如下:

img

识别视频中的人脸

img

现在我们已经将人脸识别应用于图像,让我们也将人脸识别应用于视频(实时)。

重要的性能说明:只有在使用 GPU 时才能实时使用 CNN 面部识别器(您可以将它与 CPU 一起使用,但预计低于 0.5 FPS,这会导致视频断断续续)。

或者(您使用的是 CPU),您应该使用 HoG 方法(甚至在以后的博客文章中介绍的 OpenCV Haar 级联)并期望足够的速度。 以下脚本与之前的 identify_faces_image.py 脚本有很多相似之处。

因此,我将略过我们已经介绍过的内容,只查看视频组件,以便您了解正在发生的事情。

新建 identify_faces_video.py 并插入以下代码:

# import the necessary packages
from imutils.video import VideoStream
import face_recognition
import argparse
import imutils
import pickle
import time
import cv2
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-e", "--encodings", required=True,
	help="path to serialized db of facial encodings")
ap.add_argument("-o", "--output", type=str,
	help="path to output video")
ap.add_argument("-y", "--display", type=int, default=1,
	help="whether or not to display output frame to screen")
ap.add_argument("-d", "--detection-method", type=str, default="cnn",
	help="face detection model to use: either `hog` or `cnn`")
args = vars(ap.parse_args())

导入包,然后继续解析我们的命令行参数。 我们有四个命令行参数,其中两个您应该从上面识别(–encodings 和–detection-method)。 另外两个参数是:

–output : 输出视频的路径。

–display :指示脚本在屏幕上显示框架的标志。 值为 1 时显示,值为 0 时不会将输出帧显示到我们的屏幕上。

加载我们的编码并启动我们的 VideoStream :

# load the known faces and embeddings
print("[INFO] loading encodings...")
data = pickle.loads(open(args["encodings"], "rb").read())
# initialize the video stream and pointer to output video file, then
# allow the camera sensor to warm up
print("[INFO] starting video stream...")
vs = VideoStream(src=0).start()
writer = None
time.sleep(2.0)

为了访问我们的相机,我们使用了 imutils 的 VideoStream 类。

启动流。 如果您的系统上有多个摄像头(例如内置网络摄像头和外部 USB 摄像头),您可以将 src=0 更改为 src=1 等等。 稍后我们将有选择地将处理过的视频帧写入磁盘,因此我们将 writer 初始化为 None。 休眠 2 秒可以让我们的相机预热。 从那里我们将开始一个 while 循环并开始抓取和处理帧:

# loop over frames from the video file stream
while True:
	# grab the frame from the threaded video stream
	frame = vs.read()
	
	# convert the input frame from BGR to RGB then resize it to have
	# a width of 750px (to speedup processing)
	rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
	rgb = imutils.resize(frame, width=750)
	r = frame.shape[1] / float(rgb.shape[1])
	# detect the (x, y)-coordinates of the bounding boxes
	# corresponding to each face in the input frame, then compute
	# the facial embeddings for each face
	boxes = face_recognition.face_locations(rgb,
		model=args["detection_method"])
	encodings = face_recognition.face_encodings(rgb, boxes)
	names = []

我们采取的第一步是从视频流中抓取一帧。 上述代码块与前一个脚本中的行几乎相同,不同之处在于这是一个视频帧而不是静态图像。 本质上,我们读取帧,预处理,然后检测人脸边界框 + 计算每个边界框的编码。

接下来,让我们遍历与我们刚刚找到的人脸相关的人脸编码:

# loop over the facial embeddings
	for encoding in encodings:
		# attempt to match each face in the input image to our known
		# encodings
		matches = face_recognition.compare_faces(data["encodings"],
			encoding)
		name = "Unknown"
		# check to see if we have found a match
		if True in matches:
			# find the indexes of all matched faces then initialize a
			# dictionary to count the total number of times each face
			# was matched
			matchedIdxs = [i for (i, b) in enumerate(matches) if b]
			counts = {}
			# loop over the matched indexes and maintain a count for
			# each recognized face face
			for i in matchedIdxs:
				name = data["names"][i]
				counts[name] = counts.get(name, 0) + 1
			# determine the recognized face with the largest number
			# of votes (note: in the event of an unlikely tie Python
			# will select first entry in the dictionary)
			name = max(counts, key=counts.get)
		
		# update the list of names
		names.append(name)

在这个代码块中,我们遍历每个编码并尝试匹配人脸。 如果找到匹配项,我们会计算数据集中每个名字的投票数。 然后我们提取最高票数,即与人脸相关的名称。 这些行与我们查看的前一个脚本相同,所以让我们继续。

在下一个块中,我们遍历识别出的人脸并继续在人脸周围绘制一个框,并在人脸上方显示人的姓名:

# loop over the recognized faces
	for ((top, right, bottom, left), name) in zip(boxes, names):
		# rescale the face coordinates
		top = int(top * r)
		right = int(right * r)
		bottom = int(bottom * r)
		left = int(left * r)
		# draw the predicted face name on the image
		cv2.rectangle(frame, (left, top), (right, bottom),
			(0, 255, 0), 2)
		y = top - 15 if top - 15 > 15 else top + 15
		cv2.putText(frame, name, (left, y), cv2.FONT_HERSHEY_SIMPLEX,
			0.75, (0, 255, 0), 2)

这些行也是相同的,所以让我们关注与视频相关的代码。 或者,我们将帧写入磁盘,让我们看看如何使用 OpenCV 将视频写入磁盘:

# if the video writer is None *AND* we are supposed to write
	# the output video to disk initialize the writer
	if writer is None and args["output"] is not None:
		fourcc = cv2.VideoWriter_fourcc(*"MJPG")
		writer = cv2.VideoWriter(args["output"], fourcc, 20,
			(frame.shape[1], frame.shape[0]), True)
	# if the writer is not None, write the frame with recognized
	# faces to disk
	if writer is not None:
		writer.write(frame)

假设我们在命令行参数中提供了一个输出文件路径,并且我们还没有初始化视频编写器,让我们继续初始化它。 我们初始化 VideoWriter_fourcc 。 FourCC 是一个 4 个字符的代码,在我们的例子中,我们将使用“MJPG” 4 个字符的代码。 从那里,我们将该对象连同我们的输出文件路径、每秒帧数和帧尺寸一起传递到 VideoWriter。 最后,如果 writer 存在,我们可以继续将帧写入磁盘。

让我们来处理是否应该在屏幕上显示人脸识别视频帧:

# check to see if we are supposed to display the output frame to
	# the screen
	if args["display"] > 0:
		cv2.imshow("Frame", frame)
		key = cv2.waitKey(1) & 0xFF
		# if the `q` key was pressed, break from the loop
		if key == ord("q"):
			break

如果设置了 display 命令行参数,我们继续显示框架并检查是否按下了退出键(“q”),此时我们将跳出 循环。 最后,让我们履行我们的家政职责:

# do a bit of cleanup
cv2.destroyAllWindows()
vs.stop()
# check to see if the video writer point needs to be released
if writer is not None:
	writer.release()

我们清理并释放显示、视频流和视频编写器。 您准备好查看正在运行的脚本了吗?

要演示使用 OpenCV 和 Python 进行实时人脸识别,请打开终端并执行以下命令:

python recognize_faces_video.py --encodings encodings.pickle 
	--output output/webcam_face_recognition_output.avi --display 1
[INFO] loading encodings...
[INFO] starting video stream...

视频文件中的人脸识别

正如我在“人脸识别项目结构”部分中提到的,这篇博文的“下载”中包含一个额外的脚本——recognize_faces_video_file.py。

该文件与我们刚刚查看的网络摄像头文件基本相同,但如果您愿意,它会采用输入视频文件并生成输出视频文件。

我将我们的面部识别代码应用于原始侏罗纪公园电影中流行的“午餐场景”,其中演员围坐在桌子旁与公园分享他们的担忧:

python recognize_faces_video_file.py --encodings encodings.pickle 
	--input videos/lunch_scene.mp4 --output output/lunch_scene_output.avi 
	--display 0

总结

在本教程中,您学习了如何使用 OpenCV、Python 和深度学习执行人脸识别。 此外,我们利用了 Davis King 的 dlib 库和 Adam Geitgey 的 face_recognition 模块,该模块围绕 dlib 的深度度量学习,使面部识别更容易实现。 正如我们发现的,

我们的人脸识别实现是:

  • 准确的
  • 能够通过 GPU 实时执行

我希望你喜欢今天关于人脸识别的博文!

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>