如何使用OpenCV和Python从图像中检测和提取人脸

来自菜鸟教程
跳转至:导航、​搜索

作为 Write for DOnations 计划的一部分,作者选择了 Open Internet/Free Speech Fund 来接受捐赠。

介绍

图像构成了每天生成的大量数据,这使得处理这些图像的能力很重要。 一种处理图像的方法是通过人脸检测。 人脸检测是图像处理的一个分支,它使用机器学习来检测图像中的人脸。

Haar Cascade 是一种对象检测方法,用于定位图像中感兴趣的对象。 该算法在大量正负样本上进行训练,其中正样本是包含感兴趣对象的图像。 负样本是可能包含除所需对象之外的任何内容的图像。 一旦经过训练,分类器就可以在任何新图像中定位感兴趣的对象。

在本教程中,您将使用来自 OpenCVPython 的预训练 Haar Cascade 模型来检测和提取图像中的人脸。 OpenCV 是一个用于处理图像的开源编程库。

先决条件

第 1 步 — 配置本地环境

在开始编写代码之前,您将首先创建一个工作区来保存代码并安装一些依赖项。

使用 mkdir 命令为项目创建目录:

mkdir face_scrapper

切换到新创建的目录:

cd face_scrapper

接下来,您将为该项目创建一个虚拟环境。 虚拟环境隔离不同的项目,因此不同的依赖关系不会导致任何中断。 创建一个名为 face_scrapper 的虚拟环境以用于此项目:

python3 -m venv face_scrapper

激活隔离环境:

source face_scrapper/bin/activate

您现在将看到您的提示以您的虚拟环境名称为前缀:


现在您已经激活了虚拟环境,您将使用 nano 或您喜欢的文本编辑器来创建 requirements.txt 文件。 此文件指示必要的 Python 依赖项:

nano requirements.txt

接下来,您需要安装三个依赖项才能完成本教程:

  • numpynumpy 是一个 Python 库,增加了对大型多维数组的支持。 它还包括大量用于对数组进行操作的数学函数。
  • opencv-utils:这是 OpenCV 的扩展库,包含辅助函数。
  • opencv-python:这是 Python 使用的核心 OpenCV 模块。

将以下依赖项添加到文件中:

要求.txt

numpy 
opencv-utils
opencv-python

保存并关闭文件。

通过将 requirements.txt 文件传递给 Python 包管理器 pip 来安装依赖项。 -r 标志指定 requirements.txt 文件的位置。

pip install -r requirements.txt

在此步骤中,您为项目设置了一个虚拟环境并安装了必要的依赖项。 您现在已准备好开始编写代码以在下一步中从输入图像中检测人脸。

第 2 步 — 编写和运行人脸检测器脚本

在本节中,您将编写将图像作为输入并返回两件事的代码:

  • 在输入图像中找到的人脸数量。
  • 每个检测到的人脸周围都有一个矩形图的新图像。

首先创建一个新文件来保存您的代码:

nano app.py

在这个新文件中,首先导入必要的库,开始编写代码。 您将在此处导入两个模块:cv2syscv2 模块将 OpenCV 库导入程序,sys 导入您的代码将使用的常用 Python 函数,例如 argv

应用程序.py

import cv2
import sys

接下来,您将指定输入图像将在运行时作为参数传递给脚本。 读取第一个参数的 Pythonic 方式是将 sys.argv[1] 函数返回的值分配给一个变量:

应用程序.py

...
imagePath = sys.argv[1]

图像处理中的一个常见做法是首先将输入图像转换为灰度。 这是因为检测亮度,而不是颜色,通常会在对象检测中产生更好的结果。 添加以下代码以将输入图像作为参数并将其转换为灰度:

应用程序.py

...
image = cv2.imread(imagePath)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

.imread() 函数将输入图像作为参数传递给脚本,并将其转换为 OpenCV 对象。 接下来,OpenCV 的 .cvtColor() 函数将输入图像对象转换为灰度对象。

现在您已经添加了加载图像的代码,您将添加在指定图像中检测人脸的代码:

应用程序.py

...
faceCascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
faces = faceCascade.detectMultiScale(
        gray,
        scaleFactor=1.3,
        minNeighbors=3,
        minSize=(30, 30)
) 

print("Found {0} Faces!".format(len(faces)))

此代码将创建一个 faceCascade 对象,该对象将使用 cv2.CascadeClassifier 方法加载 Haar Cascade 文件。 这允许 Python 和您的代码使用 Haar Cascade。

接下来,代码将 OpenCV 的 .detectMultiScale() 方法应用于 faceCascade 对象。 这会为图像中所有检测到的人脸生成一个 矩形列表。 矩形列表是图像中像素位置的集合,形式为 Rect(x,y,w,h)

以下是您的代码使用的其他参数的摘要:

  • gray:这指定使用您之前加载的 OpenCV 灰度图像对象。
  • scaleFactor:此参数指定在每个图像比例下缩小图像大小的速率。 您的模型在训练期间具有固定比例,因此可以缩小输入图像以改进检测。 此过程在达到由 maxSizeminSize 定义的阈值限制后停止。
  • minNeighbors:此参数指定每个候选矩形应保留多少个邻居或检测。 较高的值可能会导致较少的误报,但过高的值可能会消除真阳性。
  • minSize:这允许您定义以像素为单位测量的最小可能对象大小。 小于此参数的对象将被忽略。

生成矩形列表后,然后使用 len 函数对面进行计数。 然后在运行脚本后将检测到的人脸数量作为输出返回。

接下来,您将使用 OpenCV 的 .rectangle() 方法在检测到的人脸周围绘制一个矩形:

应用程序.py

...
for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)

此代码使用 for 循环 遍历从 faceCascade.detectMultiScale 方法返回的每个检测到的对象的像素位置列表。 rectangle 方法将采用四个参数:

  • image 告诉代码在原始输入图像上绘制矩形。
  • (x,y), (x+w, y+h) 是检测到的对象的四个像素位置。 rectangle 将使用这些来定位和绘制输入图像中检测到的对象周围的矩形。
  • (0, 255, 0) 是形状的颜色。 此参数作为 BGR 的元组传递。 例如,您可以将 (255, 0, 0) 用于蓝色。 在这种情况下,我们使用绿色。
  • 2 是以像素为单位测量的线条粗细。

现在您已经添加了绘制矩形的代码,使用 OpenCV 的 .imwrite() 方法将新图像作为 faces_detected.jpg 写入本地文件系统。 如果写入成功,此方法将返回 true,如果无法写入新图像,则返回 false

应用程序.py

...
status = cv2.imwrite('faces_detected.jpg', image)

最后,添加此代码以将 .imwrite() 函数的 truefalse 状态返回到控制台。 这将让您知道运行脚本后写入是否成功。

应用程序.py

...
print ("Image faces_detected.jpg written to filesystem: ",status)

完成的文件将如下所示:

应用程序.py

import cv2
import sys

imagePath = sys.argv[1]

image = cv2.imread(imagePath)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

faceCascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
faces = faceCascade.detectMultiScale(
    gray,
    scaleFactor=1.3,
    minNeighbors=3,
    minSize=(30, 30)
)

print("[INFO] Found {0} Faces!".format(len(faces)))

for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)

status = cv2.imwrite('faces_detected.jpg', image)
print("[INFO] Image faces_detected.jpg written to filesystem: ", status)

确认所有内容输入正确后,保存并关闭文件。

注意: 此代码来源于公开可用的 OpenCV 文档


您的代码已完成,您已准备好运行脚本。

第 3 步 — 运行脚本

在此步骤中,您将使用图像来测试您的脚本。 当您找到要用于测试的图像时,将其保存在与 app.py 脚本相同的目录中。 本教程将使用以下图像:

如果您想使用相同的图像进行测试,请使用以下命令下载它:

curl -O https://assets.digitalocean.com/articles/CART-63965/people_with_phones.png

一旦你有一个图像来测试脚本,运行脚本并提供图像路径作为参数:

python app.py path/to/input_image

脚本完成运行后,您将收到如下输出:

Output[INFO] Found 4 Faces!
[INFO] Image faces_detected.jpg written to filesystem:  True

true 输出告诉您更新的图像已成功写入文件系统。 在本地计算机上打开图像以查看新文件的更改:

您应该看到您的脚本在输入图像中检测到了四个人脸并绘制了矩形来标记它们。 在下一步中,您将使用像素位置从图像中提取人脸。

第 4 步 — 提取人脸并在本地保存(可选)

在上一步中,您编写了代码以使用 OpenCV 和 Haar Cascade 来检测和绘制图像中人脸周围的矩形。 在本节中,您将修改代码以将检测到的人脸从图像中提取到他们自己的文件中。

首先使用文本编辑器重新打开 app.py 文件:

nano app.py

接下来,在 cv2.rectangle 行下添加突出显示的行:

应用程序.py

...
for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
    roi_color = image[y:y + h, x:x + w] 
    print("[INFO] Object found. Saving locally.") 
    cv2.imwrite(str(w) + str(h) + '_faces.jpg', roi_color) 
...

roi_color 对象在原始输入图像上绘制 faces 列表中的像素位置。 xyhw 变量是从 faceCascade.detectMultiScale 方法检测到的每个对象的像素位置。 然后代码打印输出,说明找到了一个对象并将在本地保存。

完成后,代码使用 cv2.imwrite 方法将绘图保存为新图像。 它将绘图的宽度和高度附加到要写入的图像的名称上。 如果检测到多个面孔,这将保持名称唯一。

更新后的 app.py 脚本将如下所示:

应用程序.py

import cv2
import sys

imagePath = sys.argv[1]

image = cv2.imread(imagePath)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

faceCascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
faces = faceCascade.detectMultiScale(
    gray,
    scaleFactor=1.3,
    minNeighbors=3,
    minSize=(30, 30)
)

print("[INFO] Found {0} Faces.".format(len(faces)))

for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
    roi_color = image[y:y + h, x:x + w]
    print("[INFO] Object found. Saving locally.")
    cv2.imwrite(str(w) + str(h) + '_faces.jpg', roi_color)

status = cv2.imwrite('faces_detected.jpg', image)
print("[INFO] Image faces_detected.jpg written to filesystem: ", status)

总而言之,更新后的代码使用像素位置将图像中的人脸提取到新文件中。 完成代码更新后,保存并关闭文件。

现在您已经更新了代码,您可以再次运行脚本:

python app.py path/to/image

脚本处理完图像后,您将看到类似的输出:

Output[INFO] Found 4 Faces.
[INFO] Object found. Saving locally.
[INFO] Object found. Saving locally.
[INFO] Object found. Saving locally.
[INFO] Object found. Saving locally.
[INFO] Image faces_detected.jpg written to file-system: True

根据样本图像中有多少人脸,您可能会看到更多或更少的输出。

在执行脚本后查看工作目录的内容,您将看到输入图像中找到的所有面部的头像文件。

您现在将看到从工作目录中收集的输入图像中提取的头像:

在此步骤中,您修改了脚本以从输入图像中提取检测到的对象并将其保存在本地。

结论

在本教程中,您编写了一个脚本,该脚本使用 OpenCV 和 Python 从输入图像中检测、计数和提取人脸。 您可以使用 OpenCV 库中不同的预训练 Haar Cascade 更新此脚本以检测不同的对象,或者您可以学习如何 训练自己的 Haar Cascade。