在本文中,我将详细介绍如何使用face_recognition和Pillow从一堆照片中提取并识别人脸的模块。我想归功于布拉德特拉弗西,因为这个想法最初是从一个Traversy媒体视频,我有书签了一段时间,最近重新观看(链接在本文下面)。使用相同的功能,我调整了脚本以允许输入一个照片目录,最终,它将被合并到我的第二个PDM Django应用程序中。
它们是非常粗糙和现成的脚本来证明概念,这是我在一次每周的代码签入调用中向Bob演示的。
我创建了两个脚本,一个用于从一堆照片中提取人脸,并将它们存储为指定目录中的jpg文件。第二个脚本获取一组已知的面孔(我猜这是控件集),并将它们与照片进行比较,以识别随机照片中的面孔。总的来说,它在识别已知面孔方面非常准确和快速。
提取人脸
第一个脚本实现起来相当简单。我们有一个图像目录,在这个目录中我们要提取面部的所有图像,我们将这个目录称为未知目录。脚本本质上扫描每一张照片,识别脸部,并将这个脸图像作为一个新的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")
所以从这样的图像来看:
您将在提取目录中获得两个单独的图像,如下所示:
在我自己的照片上测试了这一点之后,这个模块是如此的好,以至于在我的照片中的一张海报上找到了一张脸,如果您从存储库下载代码,您就可以看到它。
人脸识别时间
第二个脚本做了所有聪明的事情,只要它将使用未知面孔的图像目录,将它们与已知的人脸图像进行比较,然后在原始图像上‘画’一个脸周围的正方形与被识别的人的名字,如果它确实识别了一个脸,那么它将在脸周围画一个以“未知人”代替这个名字的正方形。
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()
我玩过‘dra.矩形’函数的功能,试图尽可能多地捕捉正方形内部的脸,因为原来脸被正方形遮住了。
因此,从给定的具有未知面孔的图像来看:
使用Bob和Julian两种不同的图像进行匹配:
你最终会:
就像我前面说过的那样,精确度是惊人的,您可以调整face_recognition扩大或缩小匹配范围的包。它在扫描图像目录并在屏幕上显示结果或将结果保存到另一个目录时也非常快速,只要对脚本稍加调整就会非常容易。
我相信你也可以利用GPU处理,但我无法在我目前的环境中测试这一点。
我已经扩展了回购中的脚本,以包含更多已知/未知面孔的例子,所以可以随意下载并播放。
对于那些对我修改的资料感兴趣的人,请看一下布拉德的视频YouTube如果没有这些我就不会发现face_recognition模块。希望您可以像我一样修改这些代码,以适应您自己的目的。
我还不得不调整我的脚本,以增加匹配的机会,否则来自冰路卡车公司的托德·杜威(ToddDewey)被认定为我(我不确定谁会因此而受宠若惊!)这就是model和num_jitters选项用于在回购中找到的脚本。