Overview

首先要明确的是人脸检测(Detection)和人脸识别(Recognition)是两个不同的步骤,前者是检测图像中是否存在人脸,后者才是识别两张图像中的人脸是否属于同一人。

而这篇文章主要是用Google ML Kit的人脸检测实现简单的非静默式活体检测,而人脸识别不在讨论范围内,但是可以参考这篇文章: Medium - Real time face recognition with android + TensorFlow Lite

2024-03-16 更新: 使用 AWS Rekognition 进行活体检测

非静默和静默的活体检测

活体检测的主要分为非静默(配合式)和静默式活体检测,前者需要人类配合做一些特定指令,如摇头、点头、张嘴等。

而后者无需人类配合,而是根据面部的一些微表情、光线等数据进行分析,对使用者更加友好。但实现的复杂度远远要比非静默活体检测复杂,需要利用高度训练的深度学习模型。

下文只讨论非静默活体检测的简单实现,如果需要静默活体检测,额外接入成熟的第三方SDK才是首选,例如华为的HSM ML Kit。

Google ML Kit - Face Detection

选择Google ML Kit是因为该SDK非常成熟且接入简单,可以直接使用离线使用,无需在平台上注册应用。需要再次声明的是,Face Detection 只负责检测人脸,不做识别。

关于Google ML Kit 人脸识别更详细的解释可以到其官方文档查看:Google ML Kit - Face Detection,这里只针对活体检测需要使用到的功能进行简单的说明。

  • Face orientation: 识别脸部的旋转角度,用欧拉角表示。可以用来检测点头、摇头、歪头等。

  • Landmark:人脸特征点的坐标,例如眼睛、鼻子、嘴巴等。可以用来检测嘴巴是否张开。

活体检测

  1. 保持脸部正对着摄像机
  2. 微笑
  3. 张嘴
  4. 摇头

使用Google ML Kit 人脸检测还能实现更多的检测方式,但是在这里我们只讨论以上几种。

正脸检测

Google ML Kit 的人脸检测能提供相对于摄像机的脸部三维旋转的欧拉角

  • EularX:脸部上下旋转,正数表示向上(抬头)
  • EularY:脸部左右旋转,正数表示向左(左侧摇头)
  • EularZ:脸部时钟旋转,正数表示逆时针(左侧歪头)

如果人脸是正对着摄像机,这三个值都趋近于0,我们可以检测一定时间内这三个值没有出现过于激烈的变化,就认为人脸是正对摄像机。例如一段时间内,X Y Z 的值(欧拉角)的范围都在15 ~ -15 。

微笑检测

Google ML kit 内置支持微笑检测。

张嘴检测

相对于正脸和摇头检测来说,这个稍微复杂那么一点点。

Google ML Kit 的人脸检测的Landmark提供嘴巴的三个特征点

  • LeftMouth:左嘴角
  • RightMouth:右嘴角
  • BottomMouth:下嘴唇底

我们可以通过这三个点组成的三角形,计算其各个角的欧拉角来判断是否张嘴。例如嘴巴紧闭时底部的角度大约是140~150度,而嘴巴张开时大约是110~120度。

liveness-detection-mouth

而根据三个点计算三角形各个角的欧拉角度的方式可以查看这篇文章: Find all angles of a given triangle

摇头检测

还是根据X Y Z这三个欧拉角,保证一定时间内 X 和 Z 的值没有发生激烈变化的情况下,Y 的值大小超过左右两个阈值(例如20)。为了更好的用户体验,通常我们只需要用户头部转向任意一边即可。

活体检测的连续性问题

以上几个检测,用户可以通过多张照片切换的方式蒙骗过关,虽然难度较高,但确实是可行的。

Google ML Kit 的人脸检测虽然有人脸追踪功能,为每张检测到的人脸分配一个ID,当人脸离开摄像机后再次被检测到时,ID会发生变化。但可惜的是,只要两张不同的人脸切换的足够快,ID不会发生变化。 另一方面,如果用户设备性能低下,甚至可能出现某一帧无法检测到人脸导致ID发生变化。为此,我们不得不放弃人脸追踪功能,并提供一定程度上的容错来保证用户体验。

Android Demo

针对以上的讨论,我写了一个简单的Android项目来进行演示,摄像机使用了Jetpack的CameraX,仅支持Android 5.0 以上版本。

References