人脸检测进阶:更快的5点面部标志检测器

今天在这里的目标是向您介绍新的 dlib 面部标志检测器,它比原始版本更快(提高 8-10%)、更高效、更小(10 倍)。

在这篇博文的第一部分,我们将讨论 dlib 的新的、更快、更小的 5 点面部标志检测器,并将其与随库分发的原始 68 点面部标志检测器进行比较。

然后我们将使用 Python、dlib 和 OpenCV 实现面部标志检测,然后运行它并查看结果。

最后,我们将讨论使用 5 点面部标志检测器的一些限制,并重点介绍一些您应该使用 5 点版本的 68 点面部标志检测器的场景。

68 点检测器定位沿眼睛、眉毛、鼻子、嘴巴和下颌线的区域共68个点,5 点面部标志检测器将此信息简化为:

  • 左眼2分

  • 右眼2分

  • 鼻子1分

5 点面部标志检测器最合适的用例是面部对齐。

在加速方面,我发现新的 5 点检测器比原始版本快 8-10%,但这里真正的胜利是模型大小:为 9.2MB 。

同样重要的是要注意面部标志检测器开始时往往非常快(特别是如果它们被正确实现,就像它们在 dlib 中一样)。

dlib的安装教程:

https://wanghao.blog.csdn.net/article/details/121470556

人脸检测器模型:

https://download.csdn.net/download/hhhhhhhhhhwwwwwwwwww/50939290

使用 dlib、OpenCV 和 Python 实现面部标志

打开一个新文件,将其命名为 fast_facial_landmarks.py ,并插入以下代码:

# import the necessary packages
from imutils.video import VideoStream
from imutils import face_utils
import argparse
import imutils
import time
import dlib
import cv2
复制

导入了必要的包,特别是 dlib 和 imutils 中的两个模块。

imutils 包已更新以处理 68 点和 5 点面部标志模型。 确保通过以下方式在您的环境中升级它:

  1. pip install upgrade imutils

同样,更新 imutils 将允许您使用 68 点和 5 点面部标志。

解析命令行参数:

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--shape-predictor", required=True,
	help="path to facial landmark predictor")
args = vars(ap.parse_args())
复制

我们有一个命令行参数:–shape-predictor。 此参数允许我们更改将在运行时加载的面部标志预测器的路径。

然后,让我们加载形状预测器并初始化我们的视频流:

# initialize dlib's face detector (HOG-based) and then create the
# facial landmark predictor
print("[INFO] loading facial landmark predictor...")
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(args["shape_predictor"])
# initialize the video stream and sleep for a bit, allowing the
# camera sensor to warm up
print("[INFO] camera sensor warming up...")
vs = VideoStream(src=1).start()
# vs = VideoStream(usePiCamera=True).start() # Raspberry Pi
time.sleep(2.0)
复制

初始化 dlib 的预训练 HOG + 线性 SVM 人脸检测器并加载 shape_predictor 文件。

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

您可以选择(通过注释/取消注释第 25 和 26 行)是否使用:

​ 1、内置/USB 网络摄像头

​ 2、或者,如果您将在 Raspberry Pi 上使用 PiCamera

从那里,让我们遍历帧并做一些工作:

# loop over the frames from the video stream
while True:
	# grab the frame from the threaded video stream, resize it to
	# have a maximum width of 400 pixels, and convert it to
	# grayscale
	frame = vs.read()
	frame = imutils.resize(frame, width=400)
	gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
 
	# detect faces in the grayscale frame
	rects = detector(gray, 0)
	# check to see if a face was detected, and if so, draw the total
	# number of faces on the frame
	if len(rects) > 0:
		text = "{} face(s) found".format(len(rects))
		cv2.putText(frame, text, (10, 20), cv2.FONT_HERSHEY_SIMPLEX,
			0.5, (0, 0, 255), 2)
复制

首先,我们从视频流中读取一帧,调整其大小,然后转换为灰度。

然后让我们使用我们的 HOG + 线性 SVM 检测器来检测灰度图像中的人脸。

从那里,我们首先确保至少检测到一张人脸,从而在原始帧上绘制图像中的人脸总数。

接下来,让我们循环面部检测并绘制标记:

	# loop over the face detections
	for rect in rects:
		# compute the bounding box of the face and draw it on the
		# frame
		(bX, bY, bW, bH) = face_utils.rect_to_bb(rect)
		cv2.rectangle(frame, (bX, bY), (bX + bW, bY + bH),
			(0, 255, 0), 1)
		# determine the facial landmarks for the face region, then
		# convert the facial landmark (x, y)-coordinates to a NumPy
		# array
		shape = predictor(gray, rect)
		shape = face_utils.shape_to_np(shape)
 
		# loop over the (x, y)-coordinates for the facial landmarks
		# and draw each of them
		for (i, (x, y)) in enumerate(shape):
			cv2.circle(frame, (x, y), 1, (0, 0, 255), -1)
			cv2.putText(frame, str(i + 1), (x - 10, y - 10),
				cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 0, 255), 1)
复制

循环遍历 rects 。

我们使用 imutils 中的 face_utils 模块在原始框架上绘制人脸边界框(您可以在此处阅读更多信息)。

然后我们将面部传递给预测器以确定面部标志,随后我们将面部标志坐标转换为 NumPy 数组。

现在是有趣的部分。 为了可视化标记,我们将使用 cv2.circle 绘制小点并对每个坐标进行编号。

遍历标记坐标。 然后我们在原始帧上绘制一个小的实心圆圈以及标记编号。

让我们完成我们的面部标记脚本:

	# show the frame
	cv2.imshow("Frame", frame)
	key = cv2.waitKey(1) & 0xFF
 
	# if the `q` key was pressed, break from the loop
	if key == ord("q"):
		break
# do a bit of cleanup
cv2.destroyAllWindows()
vs.stop()
复制

运行我们的面部标记检测器,执行命令

  1. python fast_facial_landmarks.py shape-predictor shape_predictor_5_face_landmarks.dat

image-20211206170732808

dlib 的 5 点比68 点面部标志检测器更快吗?

在我自己的测试中,我发现 dlib 的 5 点面部标志检测器比原来的 68 点面部标志检测器快 8-10%。

8-10% 的加速是显着的; 然而,这里更重要的是模型的大小。

原来的68点人脸标记检测器将近100MB。

5 点面部标志检测器不到 10MB,只有 9.2MB——这是一个小 10 倍以上的模型!

当您构建自己的使用面部标志的应用程序时,您现在拥有一个小得多的模型文件,可以与应用程序的其余部分一起分发。

5 点面部标志检测器的局限性

对于面部对齐,可以将 5 点面部标志检测器视为 68 点检测器的直接替代品——适用相同的通用算法:

计算 5 点面部标志

分别根据每只眼睛的两个界标计算每只眼睛的中心

利用眼睛之间的中点计算眼睛质心之间的角度

通过应用仿射变换获得人脸的规范对齐

虽然 68 点面部标志检测器可能会为我们提供更好的眼睛中心近似值,但在实践中您会发现 5 点面部标志检测器也能正常工作。

5 点面部标志检测器肯定更小(分别为 9.2MB 和 99.7MB),但它不能在所有情况下使用。比如睡意检测时,我们需要计算眼睛纵横比 (EAR),它是眼睛界标宽度与眼睛界标高度的比率。

当使用 68 点面部标志检测器时,我们每只眼睛有六个点,使我们能够执行此计算。

然而,使用 5 点面部标志检测器,我们每只眼睛只有两个点——这不足以计算眼睛纵横比。

如果您的计划是构建一个睡意检测器或任何其他需要面部更多点的应用程序,包括沿以下方向的面部标志:

眼睛

眉毛

鼻子

下颌线

总结

在今天的博客文章中,我们讨论了 dlib 新的、更快、更紧凑的 5 点面部标志检测器。

这个 5 点面部标志检测器可以被认为是最初与 dlib 库一起分发的 68 点标志检测器的替代品。

在讨论了两个面部标志检测器之间的差异后,我提供了一个应用 5 点版本来检测我面部的眼睛和鼻子区域的示例脚本。

在我的测试中,我发现 5 点面部标志检测器比 68 点版本快 8-10%,同时小 10 倍。
完整的代码:
https://download.csdn.net/download/hhhhhhhhhhwwwwwwwwww/57183149