在本教程中,我将解释 Python face_recognition 库的设置和使用。该库可用于使用 Python 检测人脸并识别面部特征。
在本教程中,我将介绍 Python face_recognition 库的一些示例用法:
这篇文章提供了所有图像和代码片段,以及有关正在发生的事情的分步说明和解释。本教程针对 Windows 10,但 Linux 和 macOS 用户很可能会发现这更容易,因为他们可以跳过一些先决条件。
如果您需要/想要它们,以下是 face_recognition 的一些相关链接:
要在 Windows 上安装 face_recognition 库,您需要安装以下内容:
如果你没有这些,你会得到这样的错误,
CMake must be installed to build the following extensions: _dlib_pybind11
这告诉你没有安装 CMake,或者,
You must use Visual Studio to build a python extension on windows. If you
are getting this error it means you have not installed Visual C++. Note
that there are many flavours of Visual Studio, like Visual Studio for C#
development. You need to install Visual Studio for C++.
这告诉您您需要 Visual Studio C++ 构建工具。
制作
要安装 CMake,请转到cmake.org/download/并下载适合您机器的安装程序。我使用的是 64 位 Windows 10,所以我会得到cmake-
. 下载安装文件后,安装它。
在安装 CMake 时,将 CMake 添加到所有用户或当前用户的系统 PATH 环境变量中,以便轻松找到它。
安装完成后,打开终端并执行cmake
。这应该显示 CMake 的用法。如果没有,请确保您选择了将其添加到 PATH 环境变量的选项。
您需要关闭并重新打开终端/应用程序以更新 PATH 变量,以便
cmake
识别二进制文件。
Visual Studio C++ 构建工具
与 Linux 不同,操作系统中默认不包含适用于 Windows 的 C++ 编译器。如果我们访问 Python wiki 上的 WindowsCompilers 页面,我们可以看到有关获取独立版本的 Visual C++ 14.2 编译器而无需 Visual Studio 的信息。如果我们访问该wiki 部分的链接,我们将被带到 Microsoft 下载页面。在此下载页面上,您需要下载“Visual Studio 2019 的构建工具”。
当vs_buildtools__
下载完成,运行exe并允许它之前,我们得到下面的屏幕安装的几件事情。当您到达此屏幕时,请进行我的选择:
单击“安装”后,等待安装完成并重新启动。
现在安装了 CMake 和所需的构建工具,我们可以继续安装 face_recognition 库。
要安装 face_recognition 库,请在终端中执行以下操作:
python -m pip install face-recognition
这可能需要比平时更长的时间来安装,因为 dlib 需要使用从上面安装的工具来构建。要验证库是否已成功安装,请尝试使用以下命令在 Python 中导入库:
import face_recognition
不应引发任何错误。
在本教程中,我们还将使用Pillow / PIL 来帮助我们裁剪和绘制图像。这不是使用 face_recognition 库所必需的,但在本教程中需要以证明/显示结果。要安装它,请执行以下操作:
python -m pip install Pillow
要验证库是否已安装,请尝试使用以下命令在 Python 中导入 PIL:
import PIL
不应引发任何错误。
现在我们已经设置了 face_recognition 库和 PIL,我们现在可以开始检测人脸了。首先,我们将在只有一个人的图像中检测人脸。
单人.jpg
首先,我们要从 PIL 导入 face_recognition 和一些助手。
import face_recognition
from PIL import Image, ImageDraw
现在使用face_recognition.load_image_file.
image = face_recognition.load_image_file('single-person.jpg')
image
现在以 face_recognition 可以检测人脸的格式包含我们的图像。要识别此图像中人脸的位置,请调用face_recognition.face_locations并传递图像。
face_locations = face_recognition.face_locations(image)
face_locations
现在将包含面部位置列表。每个人脸位置都是一个像素位置元组(top, right, bottom, left)
- 我们需要记住这一点,以便我们以后使用它。
由于此图像中只有一张脸,因此我们希望此列表中只有一个项目。要检查检测到多少人脸,我们可以获取列表的长度。
amount = len(face_locations)
print(f'There are {amount} face locations')
对于我在上面提供并用于本教程的示例图像,这告诉我检测到一张脸。
为了以后使用这个面的位置,我们可以只从列表中取出第一个元素。
first_face_location = face_locations[0]
要查看其中的内容,您可以调用:
print(first_face_location)
这将打印出如下内容:
(400, 1221, 862, 759)
这些是(top, right, bottom, left)
我们将用于创建框和裁剪的像素位置。
为了识别图像中检测到的人脸的位置,我们将在由 返回的边界上绘制一个红色框face_recognition.face_locations
。
首先,我们需要从使用加载的图像创建一个 PIL 图像face_recognition.load_image_file
。这样做将允许我们使用 PIL 提供的功能。
img = Image.fromarray(image, 'RGB')
现在我们有了 PIL 图像,我们需要创建一个对象来帮助我们在图像上绘制。在我们这样做之前,我们还将把图像复制到一个新对象中,这样当我们以后裁剪脸部时,它周围就不会再有一个红色框了。
img_with_red_box = img.copy()
img_with_red_box_draw = ImageDraw.Draw(img_with_red_box)
现在我们有一个对象可以帮助我们在图像上绘制,我们将使用之前返回的尺寸绘制一个矩形。
要绘制一个框,我们需要两个点,左上角和右下角作为 x 和 y 坐标。既然我们回来了(top, right, bottom, left)
,我们就需要做这些(left, top), (right, bottom)
;基本翻译如下。
img_with_red_box_draw.rectangle(
[
(first_face_location[3], first_face_location[0]),
(first_face_location[1], first_face_location[2])
],
outline="red",
width=3
)
我们需要
(left, top), (right, bottom)
得到 (x, y) (x, y) 点。
在该步骤中,我们还设置outline="red"
了使框为红色width=3
并使框为 3 像素宽。
要查看最终结果,我们调用:
img_with_red_box.show()
这将在默认图像查看器中打开图像。图像应如下所示:
除了绘制一个框外,我们还可以将人脸裁剪成另一幅图像。
使用我们没有绘制的原始图像(因为我们在复制的图像上绘制),我们可以调用img.crop
提供之前的尺寸。
img_cropped = img.crop((
first_face_location[3], # Left x
first_face_location[0], # Top y
first_face_location[1], # Right x
first_face_location[2] # Bottom y
))
img.crop
返回正在复制的原始图像的副本,因此如果您想对原始图像执行其他操作,则无需事先复制。
img_cropped
现在包含一个新的裁剪图像,要显示它,我们可以.show()
再次调用。
img_cropped.show()
import face_recognition
from PIL import Image, ImageDraw
# Detecting the faces
image = face_recognition.load_image_file('single-person.jpg') # Load the image
face_locations = face_recognition.face_locations(image) # Detect the face locations
first_face_location = face_locations[0] # Get the first face
# Convert the face_recognition image to a PIL image
img = Image.fromarray(image, 'RGB')
# Creating the image with red box
img_with_red_box = img.copy() # Create a copy of the original image so there is not red box in the cropped image later
img_with_red_box_draw = ImageDraw.Draw(img_with_red_box) # Create an image to draw with
img_with_red_box_draw.rectangle( # Draw the rectangle on the image
[
(first_face_location[3], first_face_location[0]), # (left, top)
(first_face_location[1], first_face_location[2]) # (right, bottom)
],
outline="red", # Make the box red
width=3 # Make the box 3px in thickness
)
img_with_red_box.show() # Open the image in the default image viewer
# Creating the cropped image
img_cropped = img.crop(( # Crop the original image
first_face_location[3],
first_face_location[0],
first_face_location[1],
first_face_location[2]
))
img_cropped.show() # Open the image in the default image viewer
我们之前看到它face_recognition.face_locations
返回一个与人脸位置对应的元组数组。这意味着我们可以使用与上面相同的方法,但循环face_recognition.face_locations
绘制和裁剪时的结果。
我将使用以下作为我的形象。它有 5 个可见的面,其中 2 个略微模糊。
一群人.jpg
再一次,我们想从 PIL 导入 face_recognition 和一些助手。
import face_recognition
from PIL import Image, ImageDraw
然后使用face_recognition.load_image_file
与以前相同的方法加载新图像并检测人脸。
image = face_recognition.load_image_file('group-of-people.jpg')
face_locations = face_recognition.face_locations(image)
如果我们打印出face_locations( print(face_locations)
),我们可以看到已经检测到了5张脸。
[
(511, 1096, 666, 941),
(526, 368, 655, 239)
(283, 1262, 390, 1154),
(168, 1744, 297, 1615),
(271, 390, 378, 282)
]
由于我们现在有多个面,取第一个没有意义——我们应该遍历它们并在循环中执行我们的操作。
在我们继续之前,我们还应该创建我们将使用的 PIL 图像。
img = Image.fromarray(image, 'RGB')
像以前一样,我们需要复制原始图像以备后用(可选)并创建一个对象来帮助我们绘制。
img_with_red_box = img.copy()
img_with_red_box_draw = ImageDraw.Draw(img_with_red_box)
现在我们可以循环所有面并创建矩形。
for face_location in face_locations:
img_with_red_box_draw.rectangle(
[
(face_location[3], face_location[0]),
(face_location[1], face_location[2])
],
outline="red",
width=3
)
再一次,看看图像:
img_with_red_box.show()
不错诶!
就像绘制许多框一样,我们也可以裁剪所有检测到的人脸。再次使用 for 循环,在每个循环中裁剪图像,然后显示图像。
for face_location in face_locations:
img_cropped = img.crop((face_location[3], face_location[0], face_location[1], face_location[2]))
img_cropped.show()
您将在您的机器上在单独的窗口中打开许多图像;在这里,他们都在一起:
我已经为教程缩小了这些图像的尺寸,但您的图像将以您输入的任何分辨率进行裁剪。
import face_recognition
from PIL import Image, ImageDraw
# Load image and detect faces
image = face_recognition.load_image_file("group-of-people.jpg")
face_locations = face_recognition.face_locations(image)
# Create the PIL image to copy and crop
img = Image.fromarray(image, 'RGB')
img_with_red_box = img.copy() # Make a single copy for all the red boxes
img_with_red_box_draw = ImageDraw.Draw(img_with_red_box) # Get our drawing object again
for face_location in face_locations: # Loop over all the faces detected this time
img_with_red_box_draw.rectangle( # Draw a rectangle for the current face
[
(face_location[3], face_location[0]),
(face_location[1], face_location[2])
],
outline="red",
width=3
)
img_with_red_box.show() # Open the image in the default image viewer
for face_location in face_locations: # Loop over all the faces detected
img_cropped = img.crop(( # Crop the current image like we did last time
face_location[3],
face_location[0],
face_location[1],
face_location[2]
))
img_cropped.show() # Show the image for the current iteration
face_recognition 也有一个函数face_recognition.face_landmarks,它的工作原理类似,face_recognition.face_locations
但会返回一个包含人脸特征位置的字典列表,而不是检测到的人脸本身的位置。
回到只有一个人的图像,我们可以再次导入所有内容,加载图像并调用face_recognition.face_landmarks
.
import face_recognition
from PIL import Image, ImageDraw
image = face_recognition.load_image_file('single-person.jpg')
face_landmarks_list = face_recognition.face_landmarks(image) # The new call
现在如果我们打印face_landmarks_list
,对象看起来会有点不同。
[
{
'chin': [(315, 223), (318, 248), (321, 273), (326, 296), (335, 319), (350, 339), (370, 354), (392, 365), (415, 367), (436, 363), (455, 351), (469, 336), (479, 318), (486, 296), (488, 273), (490, 251), (489, 229)],
'left_eyebrow': [(329, 194), (341, 183), (358, 180), (375, 182), (391, 189)],
'right_eyebrow': [(434, 189), (448, 184), (461, 182), (474, 184), (483, 194)],
'nose_bridge': [(411, 209), (411, 223), (412, 238), (412, 253)],
'nose_tip': [(394, 269), (403, 272), (412, 275), (421, 272), (428, 269)],
'left_eye': [(349, 215), (360, 208), (373, 207), (384, 216), (372, 218), (359, 219)],
'right_eye': [(436, 216), (446, 208), (458, 208), (467, 216), (459, 219), (447, 219)],
'top_lip': [(374, 309), (388, 300), (402, 296), (411, 298), (420, 296), (434, 301), (448, 308), (442, 308), (420, 307), (411, 308), (402, 307), (380, 309)],
'bottom_lip': [(448, 308), (434, 317), (421, 321), (411, 322), (401, 321), (388, 317), (374, 309), (380, 309), (402, 309), (411, 310), (421, 309), (442, 308)]
}
]
这里有很多东西。对于每个面部特征(即下巴、左眉、右眉等),相应的列表包含 x 和 y 元组 - 这些 x 和 y 点是图像上的 x 和 y 坐标。
PIL 为.line()
我们一直使用的绘图对象提供了一种方法,它采用 x 和 y 点列表,非常适合这种情况。首先,我们需要一个绘图对象。
img = Image.fromarray(image, 'RGB') # Make a PIL image from the loaded image
img_draw = ImageDraw.Draw(img) # Create the draw object
在这个例子中,我们不会复制图像,因为这是我们唯一一次使用它
现在我们有了帮助我们绘制的对象,使用上面返回的列表中的第一个字典绘制所有这些线。
face_landmarks = face_landmarks_list[0] # Get the first dictionary of features
img_draw.line(face_landmarks['chin'])
img_draw.line(face_landmarks['left_eyebrow'])
img_draw.line(face_landmarks['right_eyebrow'])
img_draw.line(face_landmarks['nose_bridge'])
img_draw.line(face_landmarks['nose_tip'])
img_draw.line(face_landmarks['left_eye'])
img_draw.line(face_landmarks['right_eye'])
img_draw.line(face_landmarks['top_lip'])
img_draw.line(face_landmarks['bottom_lip'])
现在我们可以调用.show()
我们的图像来查看它:
img_draw.show()
import face_recognition
from PIL import Image, ImageDraw
# Load the image and detect face landmarks for each face within
image = face_recognition.load_image_file('single-person.jpg')
face_landmarks_list = face_recognition.face_landmarks(image)
# Make a PIL image from the loaded image and then get a drawing object
img = Image.fromarray(image, 'RGB')
img_draw = ImageDraw.Draw(img)
# Draw all the features for the first face
face_landmarks = face_landmarks_list[0] # Get the first object corresponding to the first face
img_draw.line(face_landmarks['chin'])
img_draw.line(face_landmarks['left_eyebrow'])
img_draw.line(face_landmarks['right_eyebrow'])
img_draw.line(face_landmarks['nose_bridge'])
img_draw.line(face_landmarks['nose_tip'])
img_draw.line(face_landmarks['left_eye'])
img_draw.line(face_landmarks['right_eye'])
img_draw.line(face_landmarks['top_lip'])
img_draw.line(face_landmarks['bottom_lip'])
img_with_face_landmarks.show() # Show the image for the current iteration
face_recognition 库还提供了face_recognition.compare_faces可用于比较检测到的人脸以查看它们是否匹配的功能。
我们将使用此函数的两个参数:
known_face_encodings
:已知人脸编码列表face_encoding_to_check
:要与列表进行比较的单个人脸编码在本节中,我们将为同一个人获取 2 个面部编码,并检查它们是否在另一张图像中。
以下是两张图片,每张图片中都有一张已知人脸:
elon-musk-1.jpg elon-musk-2.png
以下是我们将检查 Elon 是否在其中的图像:
elon-musk-in-group.jpg group-of-people.jpg
要获得已知的人脸编码,我们可以使用face_recognition.face_encodings. 此函数获取包含要使用的人脸和图像中人脸位置的图像。
通常,您只会使用一张图像中人脸的一个位置来创建一种编码,但如果您在一张图像中有多个相同的人脸,则可以提供多个位置。
我们需要做的来获得我们已知的人脸编码的过程是:
face_recognition.face_encodings
使用图像和单人脸位置调用我们之前已经完成了步骤 1-3,所以我们可以在这里再次执行:
import face_recognition
# Load image and detect faces
image = face_recognition.load_image_file("elon-musk-1.jpg")
face_locations = face_recognition.face_locations(image)
并验证检测到一张脸:
print(len(face_locations)) # Should be 1
现在我们可以调用face_recognition.face_encodings
并提供图像和找到的位置。
face_location = face_locations[0] # We only want an encoding for the first face. There may be more than one face in images you use so I am leaving this here as a note.
face_encodings = face_recognition.face_encodings(image, [face_location])
该参数
known_face_locations
是可选的,如果known_face_locations
未提供,face_recognition 将在获取人脸编码时自动检测图像中的所有人脸。对于这一部分,我将通过这种方式进行演示,以验证图像中仅检测到一张人脸。
由于我们指定了一个数组known_face_locations
,我们知道将只返回一个编码,因此我们可以采用第一个。
elon_musk_knwon_face_encoding_1 = face_encodings[0]
我们现在可以对另一个图像重复这个过程
image = face_recognition.load_image_file("elon-musk-2.png") # Load the image
face_locations = face_recognition.face_locations(image) # Get face locations
face_location = face_locations[0] # Only use the first detected face
face_encodings = face_recognition.face_encodings(image, [face_location]) # Get all face encodings
elon_musk_knwon_face_encoding_2 = face_encodings[0] # Pull out the one returned face encoding
现在我们有了elon_musk_knwon_face_encoding_1
和elon_musk_knwon_face_encoding_2
,我们可以看看它们是否存在于我们的另外两个图像中。
要检查图像中的匹配项face_recognition.compare_faces
,我们需要已知的人脸编码(我们刚刚在上面获得)和要检查的单个人脸编码。
由于我们正在处理一组图像,我们将不得不循环检测到的人脸——尽管这也适用于图像中只有一个人的情况。
首先,我们需要从要比较的第一张图像中获取所有面部解码。我在上面已经注意到第二个参数 , known_face_locations
toface_recognition.face_encodings
是可选的,省略它会自动检测图像中的所有面部并返回图像中每个面部的面部编码;这正是我们想要的,并将删除检测人脸的中间步骤。
image = face_recognition.load_image_file("elon-musk-in-group.jpg") # Load the image we are comparing
unknwon_face_encodings = face_recognition.face_encodings(image) # Get face encodings for everyone in the image
现在我们有了组图像中所有人脸的未知人脸编码,我们可以遍历它们并检查是否匹配:
for unknwon_face_encoding in unknwon_face_encodings:
matches = face_recognition.compare_faces(
[elon_musk_knwon_face_encoding_1, elon_musk_knwon_face_encoding_2], # The known face encodings (can be only 1 - less is faster)
unknwon_face_encoding # The single unknown face encoding
)
print(matches)
如果你运行这个,你会看到类似的东西:
[True, True]
[False, False]
[False, False]
[False, False]
每行是一个比较(存储在 中matches
),每个布尔值对应一个已知的人脸编码以及它是否与未知的人脸编码匹配。
从上面的值,我们可以看到组图像中的第一个未知人脸与已知人脸编码都匹配,而其他三个未知人脸与任何一个编码都不匹配。使用多次面部编码可以让您计算出更好的概率,但会降低速度。
如果你在另一个图像上运行这个,一切都会返回 false。
import face_recognition
# Load elon-musk-1.jpg and detect faces
image = face_recognition.load_image_file("elon-musk-1.jpg")
face_locations = face_recognition.face_locations(image)
# Get the single face encoding out of elon-musk-1.jpg
face_location = face_locations[0] # Only use the first detected face
face_encodings = face_recognition.face_encodings(image, [face_location])
elon_musk_knwon_face_encoding_1 = face_encodings[0] # Pull out the one returned face encoding
# Load elon-musk-2.jpg and detect faces
image = face_recognition.load_image_file("elon-musk-2.png")
face_locations = face_recognition.face_locations(image)
# Get the single face encoding out of elon-musk-2.jpg
face_location = face_locations[0]
face_encodings = face_recognition.face_encodings(image, [face_location])
elon_musk_knwon_face_encoding_2 = face_encodings[0]
# Load the image with unknown to compare
image = face_recognition.load_image_file("elon-musk-in-group.jpg") # Load the image we are comparing
unknwon_face_encodings = face_recognition.face_encodings(image)
# Loop over each unknwon face encoding to see if the face matches either known encodings
print('Matches for elon-musk-in-group.jpg')
for unknwon_face_encoding in unknwon_face_encodings:
matches = face_recognition.compare_faces(
[elon_musk_knwon_face_encoding_1, elon_musk_knwon_face_encoding_2], # The known face encodings (can be only 1 - less is faster)
unknwon_face_encoding # The single unknown face encoding
)
print(matches)
# Load the other image with unknown to compare
image = face_recognition.load_image_file("group-of-people.jpg") # Load the image we are comparing
unknwon_face_encodings = face_recognition.face_encodings(image)
# Loop over each unknwon face encoding to see if the face matches either known encodings
print('Matches for group-of-people.jpg')
for unknwon_face_encoding in unknwon_face_encodings:
matches = face_recognition.compare_faces(
[elon_musk_knwon_face_encoding_1, elon_musk_knwon_face_encoding_2],
unknwon_face_encoding
)
print(matches)
本教程不关注 PIL,但您可能会发现有用的一个功能是img.save();这将保存一个文件。其用法的一个示例是img.save('my_image.png')
将 PIL 图像保存到 my_image.png。
你可以在它的文档中找到更多关于 PIL 的信息,还有很多其他的在线帮助,因为它是一个非常古老的图书馆。