brainxiao 2019-04-11
我在过去的一年里写了不少人脸识别的教程,包括:
但在我的邮件和人脸识别相关帖子下面的评论中经常会出现以下问题:
我该如何识别真假人脸呢?想想如果有坏人试图攻破你的人脸识别系统会发生什么?
这样的用户可能会拿到另一个人的照片。甚至可能他们的手机上就有其他人的照片或视频,他们可以用这样的照片或视频来欺骗识别人脸的相机(就像本文开头的图片那样)。
在这种情况下,照相机完全有可能将其识别为正确的人脸,从而让未经授权的用户骗过人脸识别系统!
如何识别这些真假人脸呢?如何在人脸识别应用中使用反人脸欺骗算法?
答案是用 OpenCV 实现活体检测——这也是我今天要介绍的内容。
要了解如何用 OpenCV 将活体检测结合到你自己的人脸识别系统中,请继续往下读。
你可以在文末的下载部分下载源代码:
https://www.pyimagesearch.com/2019/03/11/liveness-detection-with-opencv/#
用 OpenCV 实现活体检测
本教程第一部分将讨论什么是活体检测以及为什么要借助活体检测提升我们的人脸识别系统。
从这里开始要先研究一下用于活体检测的数据集,包括:
我们还将回顾用于活体检测器项目的项目结构。
为了创建活体检测器,我们要训练一个能分辨真假人脸的深度神经网络。
因此,我们还需要:
那我们就开始吧!
什么是活体检测?我们为什么需要活体检测?
图 1:用 OpenCV 进行活体检测。左图是我的实时(真实)视频,而右图中我拿着自己的 iPhone(欺骗)。
人脸识别系统与以往任何时候相比都更加普遍。从 iPhone(智能手机)中的人脸识别,到中国大规模监控中的人脸识别,人脸识别系统的应用无处不在。
但人脸识别系统也很容易被「伪造」和「不真实」的面部所欺骗。
在面部识别相机前拿着一个人的照片(无论是印出来的还是手机上的)可以轻而易举地骗过人脸识别系统。
为了让人脸识别系统更加安全,我们需要检测出这样伪造的面部——活体检测(术语)指的就是这样的算法。
活体检测的方法有很多,包括:
结合以上算法,这种方法可以让面部识别系统工程师挑选适用于自己应用的活体检测模型。
Chakraborty 和 Das 2014 年的论文(《An Overview of Face liveness Detection》)对活体检测算法做了全面的综述。
我们在本教程中将活体检测视为一个二分类问题。
给定输入图像,我们要训练一个能区分真实面部和伪造面部的卷积神经网络(Convolutional Neural Network)。
但在训练活体检测模型之前,我们要先检查一下数据集。
我们的活体检测视频
图 2:真实面部和伪造面部的样例。左边的视频是我的面部的真实视频,右边是在播放同样的视频时笔记本录制的视频。
为了让例子更直观,本文建立的活体检测器侧重于区分真实面部和屏幕上的伪造面部。
这一算法可以轻易扩展到其他类型的伪造面部上,比如打印输出的伪造面部和高分辨率输出的伪造面部等。
为了建立活体检测数据集,我做了下列工作:
我在本文的「下载」部分提供了真实面部和伪造面部的视频文件。
你可以将这些视频作为数据集的起点,但我建议你多收集一些数据,这可以让你的活体检测器更鲁棒也更安全。
通过测试,我确定模型有些偏向我的脸,这是意料之中的结果,因为所有的模型都是基于我的面部训练出来的。此外,由于我是白人(高加索人),所以如果数据集中有其他肤色或其他人种的面部时,这个模型效果会没有那么好。
在理想情况下,你应该用不同肤色和不同人种的面部来训练模型。请参考本文的「限制和后续工作」部分,来了解其他改善活体检测模型的建议。
你将在本教程剩下的部分学习如何获取我录制的数据集以及如何将它实际应用于通过 OpenCV 和深度学习建立的活体检测器。
项目结构
你可以通过本教程的「Downloads」部分下载代码、数据和活体模型,然后解压缩存档。
进入项目目录后,你能看到这样的结构:
目录中有四个主目录:
1. 在播放我的面部视频时通过录制屏幕得到的伪造图像;
2. 手机直接拍摄我的面部视频得到的真实图像。
今天我们会详细地学习三个 Python 脚本。在文章结束后,你可以在自己的数据和输入视频上运行这三个脚本。按在教程中出现的顺序,这三个脚本分别是:
1. gather_examples.py:这个脚本从输入的视频文件中提取了面部 ROI,帮助我们创建了深度学习面部活体数据集;
2. train_liveness.py:如文件名所示,这个脚本用来训练 LivenessNet 分类器。我们将用 Keras 和 TensorFlow 训练模型。在训练过程中会产生一些文件:
3. liveness_demo.py:演示脚本,它会启动你的网络摄像头抓取帧,可以进行实时的面部活体检测。
从训练(视频)数据集中检测并提取面部 ROI
图 3:为了构建活体检测数据集,在视频中检测面部 ROI。
现在有机会看到初始数据集和项目结构了,让我们看看该如何从输入视频中提取出真实面部图像和伪造面部图像吧。
最终目标是用这个脚本填充两个目录:
根据这些帧,我们后续将在这些图像上训练基于深度学习的活体检测器。
打开 gataer_examples.py,插入下面的代码:
2~5 行导入了我们需要的包。除了内置的 Python 模块外,该脚本只需要 OpenCV 和 NumPy。
8~19 行解析了命令行参数:
继续加载面部检测器并初始化视频流:
23~26 行加载了 OpenCV 的深度学习面部检测器:
https://www.pyimagesearch.com/2018/02/26/face-detection-with-opencv-and-deep-learning/
从 30 行开始打开视频流。
我们还初始化了两个参数——读取的帧的数量和执行循环时保存的帧的数量(31 和 32 行)。
接着要创建处理帧的循环:
while 循环是从 35 行开始的。
从这里开始我们抓取一帧并进行验证(37~42 行)。
此时,因为已经读取了一个帧,我们将增加读取计数器(48 行)。如果我们跳过特定的帧,也会跳过后面的处理,再继续下一个循环(48 和 49 行)。
接着检测面部:
为了进行面部检测,我们要在 53 和 54 行根据图像创建一个 blob。为了适应 Caffe 面部识别器,这个 blob 是 300*300 的。之后还要缩放边界框,因此 52 行抓取了帧的维度。
58 和 59 行通过深度学习面部识别器执行了 blob 的前向传输。
我们的脚本假设视频的每一帧中只有一张面部(62~65 行)。这有助于减少假阳性。如果你要处理的视频中不止有一张面部,我建议你根据需要调整逻辑。
因此,第 65 行抓取了概率最高的面部检测索引。66 行用这个索引计算了检测的置信度。
接下来要过滤弱检测并将面部 ROI 写进磁盘:
71 行确保我们的面部检测 ROI 满足最小阈值,从而减少假阳性。
在 74~76 行提取了面部 ROI 和相应的边界框。
在 79~81 行为面部 ROI 生成了路径和文件名,并将它写在磁盘上。此时,我们就可以增加保存的面部图像数量了。
处理完成后,我们将在 86 和 87 行执行清理工作。
建立活体检测图像数据集
图 4:OpenCV 面部活体检测数据集。我们要用 Keras 和 OpenCV 来训练并演示活体模型。
现在我们已经实现了 gather_example.py 脚本,接下来要让它开始工作。
确保你已经用这篇教程的「Downloads」部分获取了源代码和输入视频样例。
打开终端并执行下面的命令来提取「伪造」类的面部:
也可以对「真实」类别的面部执行同样的操作:
因为「真」视频比「假」视频长,因此我们得把跳过帧的值设置得更长,来平衡每一类输出的面部 ROI 数量。
在执行这个脚本之后,你的图像数量应该如下:
实现「LivenessNet」——我们的深度学习活体检测器
图 5:LivenessNet(一个用来检测图片和视频中面部活性的 CNN)的深度学习架构。
下一步就要实现基于深度学习的活体检测器「LivenessNet」了。
从核心上讲,LivenessNet 实际上就是一个简单的卷积神经网络。
我们要让这个网络尽可能浅,并用尽可能少的参数,原因如下:
现在来实现 LivenessNet 吧。打开 livenessnet.py 并插入下面的代码:
所有导入(import)的包都来自 Keras(2~10 行)。要深入了解这些层和函数,请参考《Deep Learning for Computer Vision with Python》。
第 12 行定义了 LivenessNet 的类。这里用了一种静态方法——build(14 行)。build 方法接受 4 个参数:
在 17 行初始化模型。
在 18 行定义了 inputShape,在 23~25 行确定了通道顺序。
接着给 CNN 添加层:
我们的 CNN 展现了 VGGNet 特有的品质——只学习了少量的过滤器。在理想情况下,我们不需要能区分真实面部和伪造面部的深度网络。
28~36 行是第一个层的集合——CONV => RELU => CONV => RELU => POOL,这里还添加了批归一化和 dropout。
39~46 行添加了另一个层集合——CONV => RELU => CONV => RELU => POOL。
最后,我们还要添加 FC => RELU 层:
49~57 行添加了全连接层和带有 softmax 分类器 head 的 ReLU 激活层。
模型在 60 行返回到训练脚本。
创建训练活体检测器的脚本
图 6:LivenessNet 的训练过程。同时用「真实」图像和「伪造」图像作为数据集,可以用 Op
鉴于我们已经有了真实/伪造图像,且已经实现了 LivenessNet,我们现在准备训练网络了。
打开 train_liveness.py 文件,插入下列代码:
训练面部活体检测器的脚本要导入大量的包(2~19 行)。大概了解一下:
现在你知道导入的都是些什么了,可以更直接地查看脚本剩余的部分。
这个脚本接受四个命令行参数:
下面的代码块要进行大量的初始化工作,还要构建数据:
在 35~37 行要设置训练参数,包含初始化学习率、批大小和 epoch 的数量。
在 42~44 行要抓取 imagePaths。我们还要初始化两个列表来存放数据和类别标签。
46~55 行的循环用于建立数据和标签列表。数据是由加载并将尺寸调整为 32*32 像素的图像组成的,标签列表中存储了每张图相对应的标签。
在 59 行将所有像素缩放到 [0,1] 之间,并将列表转换为 NumPy 数组。
现在来编码标签并划分数据:
63~65 行对标签进行 one-hot 编码处理。
在 69 和 70 行用 scikit-learn 划分数据————将数据的 75% 用来训练,剩下的 25% 用来测试。
接下来要初始化数据增强对象、编译和训练面部活性模型:
73~75 行构造了数据增强对象,这个过程通过随机的旋转变换、缩放变换、平移变换、投影变换以及翻转变换来生成图像。
在 79~83 行中建立并编译了我们的 LivenessNet 模型。
在 87~89 行着手训练。考虑到模型较浅且数据集较小,因此这个过程相对而言会快一些。
模型训练好后,就可以评估结果并生成训练图了:
在测试集上作出预测(93 行)。94 和 95 行生成了 classification_report,并将结果输出在终端上。
99~104 行将 LivenessNet 模型和标签编码器一起序列化到磁盘上。
剩下的 107~117 行则为后续的检查生成了训练历史图。
训练活体检测器
我们现在准备训练活体检测器了。
确保你已经通过本教程的「Downloads」部分下载了源代码和数据集,执行以下命令:
图 6:用 OpenCV、Keras 和深度学习训练面部活体模型的图。
结果表明,我们的活体检测器在验证集上的准确率高达 99%!
将各个部分组合在一起:用 OpenCV 做活体检测
图 7:用 OpenCV 和深度学习做面部活性检测。
最后一步是将各个部分组合在一起:
打开 liveness_demo.py 并插入以下代码:
2~11 行导入了需要的包。值得注意的是:
解析 14~23 行命令行的参数:
现在要继续初始化面部检测器、LivenessNet 模型和标签编码器,以及视频流:
27~30 行加载 OpenCV 人脸检测器。
34 和 35 行加载序列化的预训练模型(LivenessNet)和标签编码器。
39 和 40 行实例化 VideoStream 对象,允许相机预热两秒。
此时开始遍历帧来检测真实和虚假人脸:
43 行开启了无限的 while 循环块,从这里开始捕获并调整各个帧的大小(46 和 47 行)。
调整帧的大小后,抓取帧的维度,以便稍后进行缩放(50 行)。
用 OpenCV 的 blobFromImage 函数可以生成 blob(51 和 52 行),然后将其传到面部检测器网络,再继续推理(56 和 57 行)。
现在可以进行有意思的部分了——用 OpenCV 和深度学习做活性检测:
在 60 行开始循环遍历面部检测。在这个过程中,我们:
展示结果并清理:
当捕获按键时,在循环的每一次迭代中显示输出帧。无论用户在什么时候按下「q」(「退出」),都会跳出循环、释放指针并关闭窗口(105~110 行)。
在实时视频中部署活体检测器
要继续本教程,请确保你已经通过本教程的「Downloads」部分下载了源代码和预训练的活体检测模型。
打开终端并执行下列命令:
在这里可以看到我们的活性检测器成功地分辨出真实面部和伪造面部。
下面的视频中有更长的演示:
限制、改进和进一步工作
本教程中的活体检测器的主要限制在于数据集的限制——数据集中只有 311 张图片(161 个「真实」类和 150 个「伪造」类)。
这项工作第一个要扩展的地方就是要收集更多的训练数据,更具体地说,不只是要有我或你自己的图像(帧)。
记住,这里用的示例数据集只包括一个人(我)的面部。我是个白人(高加索人),而你收集的训练数据中还应该有其他人种或其他肤色的面部。
我们的活体检测器只是针对屏幕上显示的伪造面部训练的——并没有打印出来图像或照片。因此,我的第三个建议是除了屏幕录制得到的伪造面部外,还应该有通过其他方式伪造的面部资源。
我最后要说的是,这里的活体检测并未涉及任何新技术。最好的活体检测器会包含多种活性检测的方法(请参考前文中提到的《What is liveness detection and why do we need it?》)。
花些时间思考并评估你自己的项目、指南和需求——在某些情况下,你可能只需要基本的眨眼检测启发式。
而在另一些情况中,你可能需要将基于深度学习的活体检测和其他启发式结合在一起。
不要急于进行人脸识别和活体检测——花点时间思考你的项目独一无二的需求。这么做可以确保你获得更好、更准确的结果。
总结
你将在本教程中学习如何用 OpenCV 进行活体检测。你现在就可以在自己的面部识别系统中应用这个活体检测器,来发现伪造的面部并进行反面部欺骗。
我们用 OpenCV、深度学习和 Python 创建了自己的活体检测器。
第一步是要收集真实面部和虚假面部的数据集。为了完成这项任务,我们:
在构建数据集之后,我们实现了「LivenessNet」,它集成了 Keras 和深度学习 CNN。
我们有意让这个网络尽可能浅,以确保:
总体来说,我们的活体检测器在验证集上的准确率高达 99%。
为了演示完整的活体检测流程,我们创建了一个 Python+OpenCV 的脚本,它可以加载我们的活体检测器,并且可以将它应用在实时的视频流上。
正如演示所示,我们的活体检测器可以区分真实面部和伪造面部。
原文链接:https://www.pyimagesearch.com/2019/03/11/liveness-detection-with-opencv/