用Python进行人脸识别的代码示例

118 阅读4分钟

识别面孔

Bob请我为PyBites博客写一篇客座文章,虽然这不是我的第一篇博客文章,但却是我有史以来的第一篇客座文章,我为能为Pybites写这篇文章感到无比的自豪和高兴。

在这篇文章中,我将详细介绍我是如何使用face_recognitionPillow 模块来提取并从一堆照片中识别人脸的。 我想归功于Brad Traversy,因为这个想法最初来自于我不久前收藏的Traversy Media的视频,最近我又重新看了一遍(本文下面的链接)。利用同样的功能,我对脚本进行了调整,允许输入照片目录,最终,它将被纳入我的第二个PDM Django应用程序。

这些脚本是非常粗略的概念验证,我在每周的代码检查电话中向Bob演示了这一概念。

我创建了两个脚本,一个是从一堆照片中提取人脸,并将其作为jpeg文件存储在一个指定的目录中。第二个脚本从一堆已知的人脸(我猜这些是控制集)中提取,并将它们与照片进行比较,以识别随机照片中的人脸。总的来说,它在识别已知面孔方面是非常准确和快速的。

提取人脸

第一个脚本的实现相当简单。我们有一个图片目录,我们想提取其中所有的人脸图片,我们将这个目录称为未知。这个脚本主要是扫描每张照片,识别人脸,并将这个人脸图像作为一个新的jpeg文件存储在另一个目录中,我们称之为 "提取"。这个文件是以原始图片的标题和图片中人脸的位置创建的:

import face_recognition
from PIL import Image
import os

unknown_faces = os.listdir("../frec/unknown/")

for image in unknown_faces:
    image_of_people = face_recognition.load_image_file(f"../frec/unknown/{image}")
    unknown_face_locations = face_recognition.face_locations(image_of_people)

    for face_location in unknown_face_locations:
        top, right, bottom, left = face_location

        face_image = image_of_people[top:bottom, left:right]
        pil_image = Image.fromarray(face_image)
        pil_image.save(f"../frec/extract/{image}_{top}.jpg")

因此,从这样的图像中:

IMG1 bob and julian small 1

你会在提取目录中得到两个独立的图像,如图所示:

IMG2 bob and julian small.jpeg 32

IMG3 bob and julian small.jpeg 72

在我自己的照片上进行测试后,这个模块非常好,它能在我的一张照片的海报中识别出一张脸,如果你从资源库中下载代码,你就能看到。

面部识别时间

第二个编写的脚本做了所有聪明的事情,它将采取未知面孔的图像目录,将它们与已知面孔的图像进行比较,然后在原始图像上 "画 "出一个方形的面孔,并标明被识别者的名字,如果它确实识别了一个面孔,否则它将在面孔周围画一个方形,用 "未知人物 "来代替名字:

import face_recognition
import os
from PIL import Image, ImageDraw

unknown_faces = os.listdir("../frec/unknown/")
Bob_image = face_recognition.load_image_file("../frec/known/Bob.jpeg")
Bob_encoding = face_recognition.face_encodings(Bob_image)[0]
Julian_image = face_recognition.load_image_file("../frec/known/Julian.jpeg")
Julian_encoding = face_recognition.face_encodings(Julian_image)[0]

known_face_encodings = [
    Bob_encoding,
    Julian_encoding,
]

known_face_names = [
    "Bob",
    "Julian",
]

for ukface in unknown_faces:
    ukimage = face_recognition.load_image_file(f"../frec/unknown/{ukface}")
    ukface_locations = face_recognition.face_locations(ukimage)
    ukface_encodings = face_recognition.face_encodings(ukimage, ukface_locations)

    # Convert to PIL format
    pil_image = Image.fromarray(ukimage)

    # Set up drawing on image
    draw = ImageDraw.Draw(pil_image)
    for (top, right, bottom, left), ukface_encoding in zip(
        ukface_locations, ukface_encodings
    ):
        matches = face_recognition.compare_faces(known_face_encodings, ukface_encoding)

        name = "Unknown Person"

        if True in matches:
            first_match_index = matches.index(True)
            name = known_face_names[first_match_index]

        # Draw Box
        draw.rectangle(
            ((left - 10, top - 10), (right + 10, bottom + 10)), outline=(227, 236, 75)
        )

        # Draw Label
        text_width, text_height = draw.textsize(name)
        draw.rectangle(
            ((left - 10, bottom - text_height + 2), (right + 10, bottom + 10)),
            fill=(227, 236, 75),
            outline=(227, 236, 75),
        )
        draw.text((left, bottom - text_height + 5), name, fill=(0, 0, 0, 0))

    del draw
    pil_image.save(f"../frec/identified/{ukface}_scanned.jpg")
    #pil_image.show()

我对'draw.rectangle'函数的功能进行了调整,试图在正方形内尽可能多地捕捉人脸,因为最初人脸是被正方形遮住的。

因此,再次从给定的图像中找出未知的面孔:

IMG1 bob and julian small

使用鲍勃和朱利安的两张不同的图像来进行匹配:

IMG4 Bob

IMG5 Julian

你最终会得到:

IMG6 bob and julian small.jpeg scanned

正如我之前所说,其准确性是惊人的,你可以调整face_recognition 包的值来扩大或缩小匹配。它扫描图片目录的速度也非常快,并将结果显示在屏幕上或保存到另一个目录中,只要对脚本稍作调整,就会非常容易。

我相信你也能够利用GPU处理的优势,但我无法在我目前的环境中测试这个。

我已经扩展了软件库中的脚本,以包含更多已知/未知面孔的例子,所以请随时下载并玩一玩。

对于那些对我修改过的源材料感兴趣的人,请看一下YouTube上Brad的视频,如果没有它,我就不会发现face_recognition 模块。希望你能像我一样修改这段代码以适应你自己的目的。

我还不得不调整我的脚本,以增加匹配的机会,否则冰路卡车司机的托德-杜威就会被识别为我(我不知道谁应该对此感到更荣幸!)。这就是modelnum_jitters 选项的作用,这些选项可以在repo中找到。