June 8, 2022 | 5 最小读取

使用 MTCNN 进行人脸检测

MTCNN 是一种由 Github 用户 ipacz 编写的 Python (pip) 库,它实现了论文 Zhang, Kaipeng 等人,“使用多任务级联卷积网络的联合人脸检测和对齐”。IEEE 信号处理快讯 23.10 (2016): 1499–1503。Crossref. Web

本文中,他们提出了一种深度级联多任务框架,利用不同“子模型”的特征来增强它们的相关性。

尽管 S3FD 在 GPU 上运行仍然更快,但 MTCNN 在 CPU 上运行速度相当快——但这将是另一个主题。

本文使用了以下两个来源的代码,请查看它们,它们也很有趣:


MTCNN 基本用法


您可以访问以下链接获取完整的笔记本:

https://github.com/JustinGuese/mtcnn-face-extraction-eyes-mouth-nose-and-speeding-it-up

git clone https://github.com/JustinGuese/mtcnn-face-extraction-eyes-mouth-nose-and-speeding-it-up

幸运的是,MTCNN 可作为 pip 包使用,这意味着我们可以轻松地使用以下命令安装它:

pip install mtcnn

现在,切换到 Python/Jupyter Notebook,我们可以通过导入并进行快速验证来检查安装:

import mtcnn
# 打印版本
print(mtcnn.__version__)

之后,我们就可以使用 matplotlib 的 imread 函数 加载测试图像。

import matplotlib.pyplot as plt
# 从文件中加载图像
filename = "glediston-bastos-ZtmmR9D_2tA-unsplash.webp"
pixels = plt.imread(filename)
print("图像/数组形状:", pixels.shape)
imgplot = plt.imshow(pixels)
plt.show()

现在您的输出将如下所示:

{'box': [1942, 716, 334, 415], 'confidence': 0.9999997615814209, 'keypoints': {'左眼': (2053, 901), '右眼': (2205, 897), '鼻子': (2139, 976), '嘴巴左': (2058, 1029), '嘴巴右': (2206, 1023)}}
{'box': [2084, 396, 37, 46], 'confidence': 0.9999206066131592, 'keypoints': {'左眼': (2094, 414), '右眼': (2112, 414), '鼻子': (2102, 426), '嘴巴左': (2095, 432), '嘴巴右': (2112, 431)}}
{'box': [1980, 381, 44, 59], 'confidence': 0.9998701810836792, 'keypoints': {'左眼': (1997, 404), '右眼': (2019, 407), '鼻子': (2010, 417), '嘴巴左': (1995, 425), '嘴巴右': (2015, 427)}}
{'box': [2039, 395, 39, 46], 'confidence': 0.9993435740470886, 'keypoints': {'左眼': (2054, 409), '右眼': (2071, 415), '鼻子': (2058, 422), '嘴巴左': (2048, 425), '嘴巴右': (2065, 431)}}

这告诉我们很多,大部分是显而易见的,但它基本上返回坐标,或 MTCNN 算法检测到人脸的矩形的像素值。“box”值以上返回整个人脸的位置,后跟“置信度”级别。

如果您想进行更高级的提取或算法,您还可以访问其他面部标志,称为“关键点”。特别是,MTCNN 模型还定位了眼睛、嘴巴和鼻子!


在人脸上绘制方框


为了更好地演示这一点,让我们使用 matplotlib 在人脸上绘制一个方框:

# 描绘带有检测对象的图像
def draw_facebox(filename, result_list):
    # 加载图像
    data = plt.imread(filename)
    # 绘制图像
    plt.imshow(data)
    # 获取绘制方框的上下文
    ax = plt.gca()
    # 绘制每个方框
    for result in result_list:
    # 获取坐标
        x, y, width, height = result['box']
    # 创建形状
        rect = plt.Rectangle((x, y), width, height, fill=False, color='green')
    # 绘制方框
        ax.add_patch(rect)
    # 显示绘图
    plt.show()

    # filename = 'test1.webp' # filename 定义在上面,否则取消注释
    # 加载图像
    # pixels = plt.imread(filename) # 定义在上面,否则取消注释
    # detector 定义在上面,否则取消注释
    #detector = mtcnn.MTCNN()
    # 检测图像中的人脸
    faces = detector.detect_faces(pixels)
    # 在原始图像上显示人脸
    draw_facebox(filename, faces)


显示人脸上眼睛、嘴巴和鼻子周围


现在让我们看看 MTCNN 模型返回的上述“关键点”。

我们将使用这些来绘制鼻子、嘴巴和眼睛。我们将向上面的代码添加以下代码片段:

# 绘制点
for key, value in result['keypoints'].items():
    # 创建并绘制点
    dot = plt.Circle(value, radius=20, color='orange')
    ax.add_patch(dot)

完整的代码如下:

# 描绘带有检测对象的图像
def draw_facebox(filename, result_list):
    # 加载图像
    data = plt.imread(filename)
    # 绘制图像
    plt.imshow(data)
    # 获取绘制方框的上下文
    ax = plt.gca()
    # 绘制每个方框
    for result in result_list:
    # 获取坐标
        x, y, width, height = result['box']
    # 创建形状
        rect = plt.Rectangle((x, y), width, height, fill=False, color='orange')
    # 绘制方框
        ax.add_patch(rect)
    # 绘制点
        for key, value in result['keypoints'].items():
        # 创建并绘制点
            dot = plt.Circle(value, radius=20, color='red')
            ax.add_patch(dot)
    # 显示绘图
    plt.show()

    # filename = 'test1.webp' # filename 定义在上面,否则取消注释
    # 加载图像
    # pixels = plt.imread(filename) # 定义在上面,否则取消注释
    # detector 定义在上面,否则取消注释
    #detector = mtcnn.MTCNN()
    # 检测图像中的人脸
    faces = detector.detect_faces(pixels)
    # 在原始图像上显示人脸
    draw_facebox(filename, faces)


高级 MTCNN:加速(~x100)!


现在让我们进入有趣的部分。如果您要处理数百万张图片,则需要加速 MTCNN,否则,您要么会睡着,要么您的 CPU 会在完成之前烧坏。

我们到底在谈论什么?如果您正在运行上面的代码,它将花费大约一秒钟,这意味着我们将每秒处理大约一张图片。如果您在 GPU 上运行 MTCNN 并使用加速版本,它将达到每秒 60-100 张图片/帧的速度。这是一个高达 100 倍 的提升!

例如,如果您要从电影中提取所有面部,其中您每秒提取 10 个面部(电影的每一秒平均大约有 24 帧,所以每隔一帧),它将是 10 * 60(秒)* 120(分钟)= 72,000 帧。

这意味着如果处理一帧需要一秒钟,它将花费 72,000 * 1(秒)= 72,000 秒 / 60 秒 = 1,200 分钟 = 20 小时

使用加速版 MTCNN,这项任务将需要 72,000(帧)/ 100(帧/秒)= 720 秒 = 12 分钟

要在 GPU 上使用 MTCNN,您需要设置 CUDA、cuDNN、PyTorch 等。PyTorch 编写了一个关于该部分的良好教程

安装完成后,我们将执行必要的导入,如下所示:

from facenet_pytorch import MTCNN
from PIL import Image
import torch
from imutils.video import FileVideoStream
import cv2
import time
import glob
from tqdm.notebook import tqdm

device = 'cuda' if torch.cuda.is_available() else 'cpu'

filenames = ["glediston-bastos-ZtmmR9D_2tA-unsplash.webp","glediston-bastos-ZtmmR9D_2tA-unsplash.webp"]

# ... (其他代码)

您如何在代码中定义设备?如果您不想或无法设置 CUDA,您也可以在 CPU 上运行所有内容。

接下来,我们将定义提取器:

# 定义我们的提取器
fast_mtcnn = FastMTCNN(
stride=4,
resize=0.5,
margin=14,
factor=0.6,
keep_all=True,
device=device
)

在此片段中,我们传递了一些参数,例如,我们只使用图像大小的一半,这是加速的主要影响因素之一。

最后,让我们运行人脸提取脚本:

# ... (其他代码)

(图片输出省略)

上述图像显示了在 NVIDIA Tesla P100 上运行代码的输出,因此,根据源材料、GPU 和处理器,您可能会体验到更好的或更差的性能。


[您正在进行类似的项目?您对类似的东西感兴趣?现在联系我们 进行免费的 15 分钟咨询。](/contact/)

comments powered by Disqus