OpenCV 人脸识别
本教程将讨论使用 OpenCV 中的 face_recognition
库识别图像中存在的人脸。
在 OpenCV 中使用 face_recognition
库识别图像中的人脸
人脸识别用于识别图像或视频中存在的人脸。例如,Facebook 使用面部识别来标记帖子中的人。
如果我们在图片中标记我们的朋友,Facebook 算法将识别该人的姓名,并在我们下次上传该人的照片时自动标记他。我们还可以使用 face_recognition
库构建类似的算法。
人脸识别库分多个步骤工作以识别人脸。第一步,我们需要传递已知人的图片来训练模型,库将使用 HOG
或定向梯度直方图来查找给定图像中存在的人脸。
在人脸识别中,我们只需要一张人脸的图片,不需要任何其他数据,因为数据量大,会使算法变得更慢、更复杂。
HOG
算法将每个像素与其相邻像素进行比较,以找到强度方向,并在强度级别增加的方向上用梯度标记它。
该算法已经有一张平均人脸的梯度图像。该算法将梯度图像与人脸的已知梯度进行比较,以确定图像的哪个部分包含人脸。
例如,让我们使用人脸识别库的 face_locations()
函数查找图像中存在的人脸。请参阅下面的代码。
import cv2
import dlib
import face_recognition
img = cv2.imread("tom1.jpg")
known_img = face_recognition.load_image_file("tom1.jpg")
loc = face_recognition.face_locations(known_img)
cv2.rectangle(img, (loc[0][0], loc[0][3]), (loc[0][1], loc[0][2]), (255, 0, 0), 3)
print(loc)
cv2.imshow("locations", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出:
正如我们在上面的输出中看到的,在上面的图像中使用 HOG
算法检测到人脸。我们使用两个函数导入了相同的图像,因为 imread()
函数读取 BGR 色标中的图像,而 load_image_file()
函数读取 RGB 颜色空间中的图像。
人脸识别库使用 RGB 图像,而 OpenCV 使用 BGR 图像,我们在上面的代码中都需要。我们使用 OpenCV 的 rectangle()
函数在检测到的面部周围绘制一个矩形。
face_locations()
函数返回矩形的点或角位置,我们可以在 rectangle()
函数中使用它们来绘制矩形。face_locations()
函数还有两个可选参数,number_of_times_to_upsample
和 batch_size
。
计算机将图像存储为数字数组,因此如果人脸图像被旋转或图像中的光照发生变化,即使是同一张脸,计算机也会将其视为另一张图像。该库在第二步中使用人脸界标估计解决了这个问题。
在人脸界标估计中,我们使用机器学习算法来获得 68 个对人脸识别很重要的面部界标,例如眼睛和鼻子周围的界标。
使用这些地标,我们可以旋转和共享我们的图像,以创建一个完美居中的图像,眼睛和鼻子位于图像的中心。
我们不必担心面部的方向或角度。第三步,我们必须训练一个模型来进行预测。
我们不能简单地将未知图像与所有已知图像进行比较来识别人,因为这需要时间。
我们可以使用每张图像的一些特征,例如耳朵、眼睛和鼻子大小之间的距离,并将它们与未知的人脸图像进行比较,而不是使用整个人脸图像。
但是,我们不知道哪些特征最适合识别人脸。因此,我们将使用深度卷积神经网络从每个已知图像中找到 128 个测量值或面部特征。
为了训练模型,我们必须提供两张已知人的图像和一张未知人的图像,神经网络将通过比较给定的图像来找到 128 个测量值。训练一个模型也需要很多时间,因此人脸库使用 OpenFace
的预训练模型来获取所有已知人脸的 128 个测量值。
在最后一步,我们必须使用分类器来检查未知人脸是否与任何已知人脸相似。人脸识别库使用 SVM
或空间向量机分类器进行预测。
例如,让我们使用 Tom Cruise 的一张图像进行训练,另一张图像用于测试。请参阅下面的代码。
import cv2
import dlib
import face_recognition
known_img = face_recognition.load_image_file("tom1.jpg")
unknown_img = face_recognition.load_image_file("tom2.jpg")
known_en = face_recognition.face_encodings(known_img)[0]
unknown_en = face_recognition.face_encodings(unknown_img)[0]
result = face_recognition.compare_faces([known_en], unknown_en)
print(result)
cv2.imshow("Known Image", known_img)
cv2.imshow("Un_Known Image", unknown_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出:
[True]
输出结果为真
,这意味着未知图像是汤姆克鲁斯。我们在上面的代码中使用了人脸识别库的 face_encodings()
函数来查找 128 个测量值。
face_encodings()
函数的第一个参数是输入图像。第二个参数 known_face_locations
是可选的,它用于设置每个人脸的边界框,默认情况下,它的值设置为 none
。
第三个参数 num_jitters
也是可选的,它用于设置用于查找编码的重采样值,默认设置为 1
。第四个参数 model
也是可选的,用于设置用于查找编码的模型类型,默认设置为 small
。
小模型速度快但精度较低,大模型速度慢但精度更高。我们使用 compare_faces()
将未知面孔与已知面孔进行比较。
compare_faces()
函数的第一个参数包含已知人脸的编码,第二个参数包含未知人脸的编码。第三个参数 tolerance
是可选的,用于设置面之间的距离,默认情况下,其值设置为 0.6
。
在 OpenCV 中使用 putText()
函数将文本放的图像顶部
我们还可以使用 OpenCV 的 putText()
函数在图像上放置与已知人脸相似的文本。例如,让我们使用 Tom Cruise 图像来训练模型,然后使用 Dwayne Johnson 的图像来测试模型。
请参阅下面的代码。
import cv2
import dlib
import face_recognition
img = cv2.imread("rock1.jpg")
known_img = face_recognition.load_image_file("tom2.jpg")
unknown_img = face_recognition.load_image_file("rock1.jpg")
known_en = face_recognition.face_encodings(known_img)[0]
unknown_en = face_recognition.face_encodings(unknown_img)[0]
result = face_recognition.compare_faces([known_en], unknown_en)
loc = face_recognition.face_locations(unknown_img)
cv2.rectangle(img, (loc[0][0], loc[0][3]), (loc[0][1], loc[0][2]), (255, 0, 0), 3)
if result[0]:
text = "Tom Cruise"
else:
text = "Unknown"
cv2.putText(
img,
text,
(loc[0][0], loc[0][3] - 20),
cv2.FONT_HERSHEY_SIMPLEX,
1.2,
(0, 0, 255),
2,
cv2.LINE_AA,
)
cv2.imshow("locations", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出:
上面这张脸不像汤姆克鲁斯的脸。我们还可以使用不同人的多张图像来训练模型,我们还可以在视频中找到人脸。
对于视频,我们必须单独处理每一帧。查看此链接了解有关人脸识别库的更多详细信息。