SeetaFace6包含人脸识别的基本能力:人脸检测、关键点定位、人脸识别,同时增加了活体检测、质量评估、年龄性别估计,并且顺应实际应用需求,开放口罩检测以及口罩佩戴场景下的人脸识别模型。
官网地址:https://github.com/SeetaFace6Open/index
1. 概述
活体检测是判断人脸图像是来自真人还是来自攻击假体(照片、视频等)的方法。
人脸识别系统存在被伪造攻击的风险。因此需要在人脸识别系统中加入活体检测,验证用户是否为真实活体本人操作,以防止照片、视频、以及三维模型的入侵,从而帮助用户甄别欺诈行为,保障用户的利益。
活体检测分为静默活体检测和配合式活体检测。配合式活体检测即“张张嘴”、“眨眨眼”、“摇摇头”之类;多应用于APP刷脸登录、注册等。静默活体检测是不需要任何动作配合,通过算法和摄像头的配合,进行活体判定;使用起来非常方便,用户在无感的情况下就可以通过检测比对,效率非常高。
《GB∕T 41772-2022 信息技术 生物特征识别 人脸识别系统技术要求》给出了假体攻击类型包括不限于二维假体攻击和三维假体攻击,如下表所示。
|   二维假体攻击  |   二维静态纸张图像攻击  |   样本材质  |   打印纸、亚光相纸、高光相纸、绒面相纸、哑粉纸、铜版纸等  | 
|   样本质量  |   分辨率、清晰度、大小、角度、光照条件、完整度等  | ||
|   呈现方式  |   距离、角度、移动、弯曲、折叠等  | ||
|   裁剪方式  |   图像是否扣除眼部、鼻子、嘴巴等  | ||
|   二维静态电子图像攻击  |   设备类型  |   移动终端、微型计算机等  | |
|   设备显示性能  |   分辨率、亮度、对比度等  | ||
|   样本质量  |   分辨率、清晰度、大小、角度、光照条件、完整度等  | ||
|   呈现方式  |   距离、角度、移动等  | ||
|   二维动态图像攻击  |   图像类型  |   录制视频、合成视频等  | |
|   设备类型  |   移动终端、微型计算机等  | ||
|   设备显示性能  |   分辨率、亮度、对比度等  | ||
|   图像质量  |   分辨率、清晰度、帧率等  | ||
|   呈现方式  |   距离、角度、移动等  | ||
|   三维假体攻击  |   三维面具攻击  |   面具材质  |   塑料面具、三维纸张面具、硅胶面具等  | 
|   呈现方式  |   距离、角度、移动等  | ||
|   光线条件  |   正常光、强光、弱光、逆光等  | ||
|   裁剪方式  |   面具是否扣除眼部、鼻子、嘴巴等  | ||
|   三维头模攻击  |   头模材质  |   泡沫、树脂、全彩砂岩、石英砂等  | |
|   呈现方式  |   距离、角度、移动等  | ||
|   光线条件  |   正常光、强光、弱光、逆光等  | 
2. SeetaFace6活体检测
SeetaFace6的活体检测方案,提供了全局活体检测和局部活体检测 两个方法。
- 全局活体检测就是对图片整体做检测,主要是判断是否出现了活体检测潜在的攻击介质,如手机、平板、照片等等。
 - 局部活体检测是对具体人脸的成像细节通过算法分析,区别是一次成像和二次成像,如果是二次成像则认为是出现了攻击。
 
2.1 基本使用
活体检测识别器可以加载一个局部检测模型或者局部检测模型+全局检测模型。
只加载一个局部检测模型:
#include <seeta/FaceAntiSpoofing.h>
seeta::FaceAntiSpoofing *new_fas() {
    seeta::ModelSetting setting;
    setting.append("fas_first.csta");
    return new seeta::FaceAntiSpoofing(setting);
} 
或者局部检测模型+全局检测模型,启用全局检测能力:
#include <seeta/FaceAntiSpoofing.h>
seeta::FaceAntiSpoofing *new_fas_v2() {
    seeta::ModelSetting setting;
    setting.append("fas_first.csta");
    setting.append("fas_second.csta");
    return new seeta::FaceAntiSpoofing(setting);
} 
调用有两种模式,一个是单帧识别,另外就是视频识别。 其接口声明分别为:
seeta::FaceAntiSpoofing::Status seeta::FaceAntiSpoofing::Predict( const SeetaImageData &image, const SeetaRect &face, const SeetaPointF *points ) const;
seeta::FaceAntiSpoofing::Status seeta::FaceAntiSpoofing::PredictVideo( const SeetaImageData &image, const SeetaRect &face, const SeetaPointF *points ) const; 
从接口上两者的入参和出参的形式是一样的。出参这里列一下它的声明:
class FaceAntiSpoofing {
public:/*     * 活体识别状态     */enum Status
    {
        REAL = 0,       ///< 真实人脸
        SPOOF = 1,      ///< 攻击人脸(假人脸)
        FUZZY = 2,      ///< 无法判断(人脸成像质量不好)
        DETECTING = 3,  ///< 正在检测
    };
} 
单帧识别返回值会是REAL、SPOOF或FUZZY。 视频识别返回值会是REAL、SPOOF、FUZZY或DETECTING。
两种工作模式的区别在于前者属于一帧就是可以返回识别结果,而后者要输入多个视频帧然后返回识别结果。在视频识别输入帧数不满足需求的时候,返回状态就是DETECTING。
这里给出单帧识别调用的示例:
void predict(seeta::FaceAntiSpoofing *fas, const SeetaImageData &image, const SeetaRect &face, const SeetaPointF *points) {
    auto status = fas->Predict(image, face, points);
    switch(status) {
    case seeta::FaceAntiSpoofing::REAL:
        std::cout << "真实人脸" << std::endl; break;
    case seeta::FaceAntiSpoofing::SPOOF:
        std::cout << "攻击人脸" << std::endl; break;
    case seeta::FaceAntiSpoofing::FUZZY:
        std::cout << "无法判断" << std::endl; break;
    case seeta::FaceAntiSpoofing::DETECTING:
        std::cout << "正在检测" << std::endl; break;
    }
} 
这里需要注意face和points必须对应,也就是points必须是face表示的人脸进行关键点定位的结果。points是5个关键点。当然image也是需要识别的原图。
如果是视频识别模式的话,只需要将predict中的fas->Predict(image, face, points)修改为fas->PredictVideo(image, face, points)。
在视频识别模式中,如果该识别结果已经完成,需要开始新的视频的话,需要调用ResetVideo重置识别状态,然后重新输入视频:
void reset_video(seeta::FaceAntiSpoofing *fas) {
    fas->ResetVideo();
} 
当了解基本调用接口之后,就可以直接看出来,识别接口直接输入的就是单个人脸位置和关键点。因此,当视频或者图片中存在多张人脸的时候,需要业务决定具体识别哪一个人脸。一般有这几种选择,1. 只做单人识别,当出现两个人的时候识别中止。2. 识别最大的人脸。3. 识别在指定区域中出现的人脸。这几种选择对精度本身影响不大,主要是业务选型和使用体验的区别。
2.2 参数设置
设置视频帧数:
void SetVideoFrameCount( int32_t number ); 
默认为10,当在PredictVideo模式下,输出帧数超过这个number之后,就可以输出识别结果。这个数量相当于多帧识别结果融合的融合的帧数。当输入的帧数超过设定帧数的时候,会采用滑动窗口的方式,返回融合的最近输入的帧融合的识别结果。一般来说,在10以内,帧数越多,结果越稳定,相对性能越好,但是得到结果的延时越高。
设置识别阈值:
void SetThreshold( float clarity, float reality ); 
默认为(0.3, 0.8)。活体识别时,如果清晰度(clarity)低的话,就会直接返回FUZZY。清晰度满足阈值,则判断真实度(reality),超过阈值则认为是真人,低于阈值是攻击。在视频识别模式下,会计算视频帧数内的平均值再跟帧数比较。两个阈值都符合,越高的话,越是严格。
设置全局检测阈值:
void SetBoxThresh(float box_thresh); 
默认为0.8,这个是攻击介质存在的分数阈值,该阈值越高,表示对攻击介质的要求越严格,一般的疑似就不会认为是攻击介质。这个一般不进行调整。
以上参数设置都存在对应的Getter方法,将方法名称中的Set改为Get就可以访问对应的参数获取了。
2.3 参数调试
在应用过程中往往不可避免对阈值产生疑问,如果要调试对应的识别的阈值,这里我们给出了每一帧分数的获取函数。
下面给出识别之后获取识别具体分数的方法:
void predict_log(seeta::FaceAntiSpoofing *fas, const SeetaImageData &image, const SeetaRect &face, const SeetaPointF *points) {
    auto status = fas->Predict(image, face, points);
    float clarity, reality;
    fas->GetPreFrameScore(&clarity, &reality);
    std::cout << "clarity = " << clarity << ", reality = " << reality << std::endl;
} 
在Predict或者PredictVideo之后,调用GetPreFrameScore方法可以获取刚刚输入帧的识别分数。
3. 演示Demo
3.1 开发环境
- Windows 10 Pro x64
 - Visual Studio 2015
 - Seetaface6
 
3.2 功能介绍
演示程序主界面如下图所示,包括参数显示、实时活体检测、取消等功能。

3.3 效果测试
二维假体攻击,包括二维静态纸张图像攻击、二维静态电子图像攻击、二维动态图像攻击,检测效果还是不错。



三维假体攻击,除了塑料材质检测效果还可以,其他材质基本无法正确检测。






3.4 下载地址
开发环境:
- Windows 10 pro x64
 - Visual Studio 2015
 - Seetaface6
 
VS工程下载:SeetaFace6人脸活体检测C++代码实现Demo



















