与 Keras 进行面部检测和识别

2021-07-31

如果你是googlephotos的常客,你可能已经注意到了这个应用程序是如何从你备份到云端的照片中自动提取和分组人物的脸的。

Face Recognition in the Google Photos web applicationgooglephotos web应用中的人脸识别

像Google这样的照片应用程序通过检测人类(还有宠物)的脸来实现这一点在你的照片里,然后把相似的脸组合在一起。对图像中的人脸进行检测和分类是神经网络深度学习中的一项常见任务。

在本教程中,我们首先使用CNN训练的模型来检测人脸。一旦我们从图像中提取出人脸,我们将计算这些人脸之间的相似度,以确定它们是否属于同一个人。

先决条件

在开始检测和识别人脸之前,需要设置开发环境。首先,在对图像进行任何处理之前,需要通过Python“读取”图像。我们将使用绘图库matplotlib阅读和操纵图像。通过安装程序安装最新版本皮普 :

pip3 install matplotlib

要使用CNN算法的任何实现,您需要安装keras. 使用以下命令下载并安装最新版本:

pip3 install keras

我们的算法鈥檒用于人脸检测的是MTCNN(多任务卷积神经网络),基于本文鈥基于多任务级联卷积网络的联合人脸检测与对准“(Zhang等人,2016年)。张量流的MTCNN算法在Python3.4中的实现可作为套装提供. 运行以下命令将包安装到pip :

pip3 install mtcnn

要在从图像中提取人脸后进行比较,我们将使用VGGFace2算法由牛津大学视觉几何小组开发。VGG算法的基于TensorFlow的Keras实现作为一个软件包提供,供您安装:

pip3 install keras_vggface

虽然您可能觉得需要构建和训练您自己的模型,但您需要一个巨大的训练数据集和巨大的处理能力。由于本教程侧重于这些模型的实用性,因此它使用了该领域专家提供的、经过培训的现有模型。

既然您已经成功地安装了先决条件,让我们直接进入教程!

第一步:利用MTCNN模型进行人脸检测

此步骤的目标如下:

  • 检索本地服务器外部托管的映像
  • 通读图像matplotlib 读入()功能
  • 通过MTCNN算法检测和探索人脸
  • 从图像中提取面

1.1存储外部图像

您可能经常从托管在外部服务器上的图像执行分析。在这个例子中,我们将使用两个图像,Lee Iacocca,野马之父,在英国广播公司底特律新闻报地点

为了在本地临时存储图像以供分析,我们将从其URL检索每个图像并将其写入本地文件。让我们定义一个函数store_image为此目的:

import urllib.request

def store_image(url, local_file_name):
  with urllib.request.urlopen(url) as resource:
    with open(local_file_name, 'wb') as f:
      f.write(resource.read())

现在,您只需使用URL和要在其中存储图像的本地文件来调用函数:

store_image('https://ichef.bbci.co.uk/news/320/cpsprodpb/5944/production/_107725822_55fd57ad-c509-4335-a7d2-bcc86e32be72.jpg',
            'iacocca_1.jpg')
store_image('https://www.gannett-cdn.com/presto/2019/07/03/PDTN/205798e7-9555-4245-99e1-fd300c50ce85-AP_080910055617.jpg?width=540&height=&fit=bounds&auto=webp',
            'iacocca_2.jpg')

成功检索图像后,让我们检测其中的人脸。

1.2检测图像中的人脸

为此,我们鈥檒我有两个进口货鈥matplotlib用于阅读图像,以及mtcn对于检测图像中的人脸:

from matplotlib import pyplot as plt
from mtcnn.mtcnn import MTCNN

使用imread()读取图像的函数:

image = plt.imread('iacocca_1.jpg')

接下来,初始化MTCNN()对象放入探测器变量并使用.detect_faces()方法检测图像中的人脸。让我们看看它会返回什么:

detector = MTCNN()

faces = detector.detect_faces(image)
for face in faces:
  print(face)

对于每个面,都会返回一个Python字典,其中包含三个键。这个box键包含图像中面的边界。它有四个值:左上顶点的x和y坐标、包含面的矩形的宽度和高度。其他的钥匙是信心keypoints. 这个关键点key包含一个字典,其中包含检测到的面部特征及其坐标:

{'box': [160, 40, 35, 44], 'confidence': 0.9999798536300659, 'keypoints': {'left_eye': (172, 57), 'right_eye': (188, 57), 'nose': (182, 64), 'mouth_left': (173, 73), 'mouth_right': (187, 73)}}

1.3突出显示图像中的面

现在我们已经成功地检测到一个人脸,让我们在它上面画一个矩形来突出显示图像中的人脸,以验证检测是否正确。

若要绘制矩形,请导入Rectangle对象来自 Matplotlib库 :

from matplotlib.patches import Rectangle

让我们定义一个函数highlight_faces首先显示图像,然后在检测到的面上绘制矩形。首先,通读图像 读入()把它画出来imshow(). 对于检测到的每个面,使用矩形()班级

最后,使用.show()方法。如果您使用的是Jupyter笔记本,您可以使用%matplotlib内联在线显示绘图的魔术命令:

def highlight_faces(image_path, faces):
  # display image
  image = plt.imread(image_path)
  plt.imshow(image)

  ax = plt.gca()

  # for each face, draw a rectangle based on coordinates
  for face in faces:
    x, y, width, height = face['box']
    face_border = Rectangle((x, y), width, height,
                          fill=False, color='red')
    ax.add_patch(face_border)
  plt.show()

现在让我们使用highlight_faces()功能:

highlight_faces('iacocca_1.jpg', faces)
Detected face in an image of Lee Iacocca在李·艾科卡的照片中发现了一张脸。资料来源:英国广播公司

让我们显示第二个图像和其中检测到的人脸:

image = plt.imread('iacocca_2.jpg')
faces = detector.detect_faces(image)

highlight_faces('iacocca_2.jpg', faces)
The Detroit News底特律新闻报

在这两张图片中,您可以看到MTCNN算法正确地检测到人脸。现在让我们从图像中提取这张脸,对其进行进一步的分析。

1.4提取人脸进行进一步分析

在这一点上,你从探测器上知道了这些面的坐标。使用列表索引提取人脸是一项相当简单的任务。然而,我们使用的VGGFace2算法需要将人脸大小调整为224x224像素。我们将使用PIL库来调整图像的大小。

功能extract_face_from_image()从图像中提取所有面:

from numpy import asarray
from PIL import Image

def extract_face_from_image(image_path, required_size=(224, 224)):
  # load image and detect faces
  image = plt.imread(image_path)
  detector = MTCNN()
  faces = detector.detect_faces(image)

  face_images = []

  for face in faces:
    # extract the bounding box from the requested face
    x1, y1, width, height = face['box']
    x2, y2 = x1 + width, y1 + height

    # extract the face
    face_boundary = image[y1:y2, x1:x2]

    # resize pixels to the model size
    face_image = Image.fromarray(face_boundary)
    face_image = face_image.resize(required_size)
    face_array = asarray(face_image)
    face_images.append(face_array)

  return face_images

extracted_face = extract_face_from_image('iacocca_1.jpg')

# Display the first face from the extracted faces
plt.imshow(extracted_face[0])
plt.show()

下面是从第一张图像中提取的人脸的外观。

Extracted and resized face from first image从第一幅图像中提取并调整大小的人脸

第二步:利用VGGFace2模型进行人脸识别

在本节中,让我们首先在我们检索到的Lee Iacocca的两幅图像上测试模型。然后,我们将继续比较2018年和2019年切尔西足球队11名首发球员的照片中的人脸。然后,您将能够评估该算法是否能够识别图像中普通球员的面部。

2.1比较两个面

在本节中,您需要导入三个模块:VGGFace准备要用于人脸识别模型的提取的人脸,以及余弦函数SciPy计算两个面之间的距离:

from keras_vggface.utils import preprocess_input
from keras_vggface.vggface import VGGFace
from scipy.spatial.distance import cosine

让我们定义一个函数,该函数将提取的面作为输入并返回计算的模型分数。模型将返回一个向量,该向量表示面的特征:

def get_model_scores(faces):
  samples = asarray(faces, 'float32')

  # prepare the data for the model
  samples = preprocess_input(samples, version=2)

  # create a vggface model object
  model = VGGFace(model='resnet50',
      include_top=False,
      input_shape=(224, 224, 3),
      pooling='avg')

  # perform prediction
  return model.predict(samples)

faces = [extract_face_from_image(image_path)
         for image_path in ['iacocca_1.jpg', 'iacocca_2.jpg']]

model_scores = get_model_scores(faces)

由于每个人脸的模型分数都是向量,所以我们需要找出两个人脸得分之间的相似度。我们通常可以使用欧几里德函数或余弦函数来计算相似度。

人脸的矢量表示适合于余弦相似度。下面详细比较余弦距离和欧几里德距离举例 .

这个cosine()函数计算两个向量之间的余弦距离。这个数字越低,你的脸就越匹配。在我们的例子中,我们将阈值设置在 zero point four. 这个阈值是值得商榷的,并且将随您的用例而变化。应根据数据集的案例研究设置此阈值:

if cosine(model_scores[0], model_scores[1]) <= 0.4:
  print("Faces Matched")

在这种情况下,Lee Iacocca的两张脸匹配:

Faces Matched

2.2比较两个图像中的多个面

让我们在本教程的这一节中充分利用该模型。我们将比较两张照片中切尔西足球俱乐部的伊莱文欧罗巴联赛对阵布拉格斯拉维亚2018-19赛季联盟超级杯对利物浦的比赛在2019-20赛季。虽然许多玩家在两个比赛日小组中都有功能,但是让我们看看算法是否能够检测到所有的普通玩家。

首先,让我们从URL中检索资源,检测每个图像中的人脸并高亮显示它们:

store_image('https://cdn.vox-cdn.com/thumbor/Ua2BXGAhneJHLQmLvj-ZzILK-Xs=/0x0:4872x3160/1820x1213/filters:focal(1877x860:2655x1638):format(webp)/cdn.vox-cdn.com/uploads/chorus_image/image/63613936/1143553317.jpg.5.jpg',
            'chelsea_1.jpg')

image = plt.imread('chelsea_1.jpg')
faces_staring_xi = detector.detect_faces(image)

highlight_faces('chelsea_1.jpg', faces_staring_xi)

store_image('https://cdn.vox-cdn.com/thumbor/mT3JHQtZIyInU8_uGxVH-TCbF50=/0x415:5000x2794/1820x1213/filters:focal(1878x1176:2678x1976):format(webp)/cdn.vox-cdn.com/uploads/chorus_image/image/65171515/1161847141.jpg.0.jpg',
            'chelsea_2.jpg')

image = plt.imread('chelsea_2.jpg')
faces = detector.detect_faces(image)

highlight_faces('chelsea_2.jpg', faces)
Comparison of faces 国家

在我们继续之前,以下是两场比赛的起跑线:

  • 布拉格斯拉维亚比赛首发:凯帕、阿兹皮利库塔、路易斯、克里斯滕森、爱默生、康德、巴克利、科瓦西奇、哈扎德、佩德罗、吉鲁德
  • 布拉格斯拉维亚比赛首发 :凯帕、阿兹皮利库埃塔、克里斯滕森、祖玛、爱默生、康德、乔吉诺、科瓦奇、佩德罗、吉鲁德、普利希克

我们有八个球员,他们都是首发的XIs球员,理想情况下他们应该通过算法匹配。

我们先计算分数:

slavia_faces = extract_face_from_image('chelsea_1.jpg')
liverpool_faces = extract_face_from_image('chelsea_2.jpg')

model_scores_starting_xi_slavia = get_model_scores(slavia_faces)
model_scores_starting_xi_liverpool = get_model_scores(liverpool_faces)
``
for idx, face_score_1 in enumerate(model_scores_starting_xi_slavia):
  for idy, face_score_2 in enumerate(model_scores_starting_xi_liverpool):
    score = cosine(face_score_1, face_score_2)
    if score <= 0.4:
      # Printing the IDs of faces and score
      print(idx, idy, score)
      # Displaying each matched pair of faces
      plt.imshow(slavia_faces[idx])
      plt.show()
      plt.imshow(liverpool_faces[idy])
      plt.show()

下面是算法匹配的人脸对列表。请注意,它已经能够匹配所有八对脸。

Eight Correctly Recognized Faces八张正确识别的脸(Kepa、Azpilicueta、Emerson、Giroud、Kante、Pedro、Christensen、Kovacic)

虽然我们能够成功地匹配图像中的每个人脸,但我想退一步讨论分数的影响。如前所述,没有通用的阈值可以将两个图像匹配在一起。您可能需要在分析中使用新数据重新定义这些阈值。例如,即使是googlephotos,当它无法以编程方式确定一对照片的最佳阈值时,它也会接受你的输入。

Google Photos taking user inputs for face matching谷歌照片拍摄用户输入的面部匹配

最好的方法是在匹配不同类型的人脸时仔细评估案例。面部表情和角度也在决定精度方面起着重要作用。在我们的用例中,请注意我是如何故意使用启动eleven的照片的,因为玩家正盯着相机看!你可以试着把11张开始的脸与奖杯庆典的脸相匹配,我很确定准确度会下降。

结论

在本教程中,我们首先使用MTCNN模型检测图像中的人脸,并在图像中突出显示它们,以确定模型是否正常工作。接下来,我们使用VGGFace2算法以向量的形式从人脸中提取特征,并将不同的人脸匹配在一起。

你用不同的算法来检测和匹配人脸吗?告诉我推特 !