python - Python + OpenCV 人脸识别
问题描述
我有一个test1.jpg - 它是原始图像,包含我们需要找到的面孔。
我的test2.jpg是一些要检查的图像。我们需要在test2.jpg 中检查 test1.jpg中的面孔,如果 test1.jpg 中的某些面孔存在于test2.jpg中,则输出true。
我之前没有在 OpenCV 和它对我来说是新技术方面的经验。
我非常简单的代码:
# faces which we need find
known_image = cv2.imread('test1.jpg')
# some random image
unknown_image = cv2.imread('test2.jpg')
gray_known = cv2.cvtColor(known_image, cv2.COLOR_BGR2GRAY)
gray_unknown = cv2.cvtColor(unknown_image, cv2.COLOR_BGR2GRAY)
faceCascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
known_faces = faceCascade.detectMultiScale(
gray_known,
scaleFactor=1.27,
minNeighbors=5,
minSize=(10, 10),
flags = cv2.CASCADE_SCALE_IMAGE
)
print("Found known {0} faces!".format(len(known_faces)))
unknown_faces = faceCascade.detectMultiScale(
gray_unknown,
scaleFactor=1.27,
minNeighbors=5,
minSize=(10, 10),
flags = cv2.CASCADE_SCALE_IMAGE
)
print("Found unknown {0} faces!".format(len(unknown_faces)))
# BELLOW NOT CORRECT CODE. I DONT KNOW HOW I CAN DO LIKE THIS:
for face in known_faces:
if face in unknown_faces:
print(TRUE)
break
解决方案
就目前而言,您的代码的主要问题是它希望面部补丁在两个不同的图像中是相同的。几乎可以肯定不是这种情况——即使一个只是另一个图像的裁剪图像,如果级联分类器在一个图像中发现边界框比另一个图像更左 1 个像素,则结果并不相同。
级联分类器的结果是一组代表人脸的边界框(有时会得到错误检测)。然后,您需要在这些边界框中提取子图像,并使用某种比较技术来确定两个人脸图像是否相同。我将在下面讨论这些。
你的问题实际上有两个阶段,区分它们很重要,因为有不同的技术来解决这两个问题。
第 1 阶段:人脸检测
这是在图像中实际找到人脸的问题。您的代码应该可以很好地处理这个问题 - OpenCV 的级联分类器是最常见的方法之一(另一种方法是DLib 中的对齐人脸检测器)。
第二阶段:人脸识别
这是比较困难的部分。人脸识别技术可以有很大的不同,而且很多都取决于情况。其中最准确的是使用深度学习模块,因此如果您的硬件能够胜任这项任务,我建议您这样做。看起来代码实际上是OpenFace 的实现——我以前用过它,它可以在很少的训练图像上获得准确的识别。我建议阅读链接的帖子,以及 DNN 示例,因为代码可能太深而无法进入此处。
主要步骤如下:
- 如上图1中的人脸检测和定位
- 使用预训练的 DNN 将人脸转换为可线性分离的特征向量(称为嵌入)。
- 如上图 2 中的人脸检测和定位
- 同样,使用 DNN 将人脸转换为特征向量。
- 比较特征向量 - 而不是原始图像,并选择欧几里得距离足够低的那些。
DNN 嵌入步骤在这里是较慢的部分,但如果您有可用的 GPU,应该仍然非常有效。
如果您不是直接进行图像-图像比较,而是在寻找一组已知的面孔,您可以训练一个现成的线性分类器,例如对您想要寻找的实际人的 SVM,然后使用这个在您在图像中找到的特征向量上查看它们是否属于任何类别。
阶段 2(a):没有深度学习的人脸识别
OpenCV 还带有一个人脸识别模块,它利用了更经典的技术,这些技术往往更快、更便携,但以准确性为代价。
OpenCV 文档中有一个非常好的教程。同样,代码太长,无法直接放入帖子中,但该链接描述了 3 种面部检测方法。Fisherfaces和Eigenfaces都依赖于查看同一张脸的多个示例并在低维空间中对它们进行建模,在该空间中可以比较它们的基本属性,而不是原始像素数据。
我不确定其中任何一个都适用于您的用例,因为每张面孔只有一个示例。
使用局部二进制模式 (LBP) 直方图可能会给您一个更好的起点。LBP 是一种描述图像纹理细节的方法——我在上面链接的教程中有更多信息。我将在这里再次提供一些基本步骤以帮助您入门:
- 对于每个检测到的人脸,使用该人脸的边界框提取小的子图像(感兴趣区域)。
- 将该图像分解为更小的“块” - 本质上是将图像分解为一个统一的网格(例如,一个 100x100 像素的 ROI 可能被分解为 10x10 个 10x10 像素的块)。
- 对于每个补丁,计算 LBP 直方图(本质上是一个数字列表)
- 将这些直方图连接(连接)在一起以获得面部的表示。这个连接的直方图成为你的特征向量来表示那个特定的脸。
- 然后,您可以对图像 2 执行相同的操作。
- 对于图像 2 中的所有特征向量,将它们与图像 1 中的特征向量进行比较,并尝试挑选出距离较小的特征向量。
笔记:
任何使用单个图像的识别技术都可能容易出错。我没有测试过上面的算法,但是在过去使用 OpenFace、Fisherfaces 和 LBPH 进行人脸识别,遵循这些教程,并发现它们可以通过一些人脸示例进行识别。
推荐阅读
- database - 在我们重新保存产品之前,Magento2 自定义产品属性值不会显示在前端
- swift - 如何使用 RxSwift 订阅数组更改?
- git - 如何签出到另一个分支并强制覆盖更改
- php - 使用 JQuery blueimp 上传多个文件
- python - 从 Dataframe 时间序列中提取每月日期
- ios - UITableViewWrapperView 在 tvOS 上具有超级视图的前导和尾随边距
- angular - Angular 6 的 Karma-Jasmine 上的“TypeError:无法读取属性‘routeConfig’ of null”
- c# - 将json字符串反序列化为变体的变体数组时如何控制变体类型
- codeblocks - 尝试调试 [C++] [Code::Blocks] 时出现“未知选项‘全名’”
- vba - 无法检查范围是否为空