SeetaFace6人脸活体检测C++代码实现Demo

        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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/11077.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【补充】图神经网络前传——DeepWalk

论文阅读 论文&#xff1a;https://arxiv.org/pdf/1403.6652 参考&#xff1a;【论文逐句精读】DeepWalk&#xff0c;随机游走实现图向量嵌入&#xff0c;自然语言处理与图的首次融合_随机游走图嵌入-CSDN博客 abstract DeepWalk是干什么的&#xff1a;在一个网络中学习顶点…

【Mac】Ghost Buster Pro(苹果电脑内存清理专家) v3.2.5安装教程

软件介绍 Ghost Buster pro是一款针对Mac系统的电脑清理和优化工具&#xff0c;可以帮助用户清理系统垃圾、修复注册表错误、卸载不需要的软件、管理启动项等&#xff0c;从而提高系统性能和稳定性。 安装教程 1.打开镜像包&#xff0c;拖动「Ghost Buster Pro」到应用程序中…

GIT SSL certificate problem

简单来说&#xff0c;SSL 协议可以为你的 Web 浏览器或其他进程提供一种安全的通道&#xff0c;使服务器和客户端之间的数据传输过程不被第三方窃取或篡改。这非常重要&#xff0c;特别是在处理敏感数据&#xff0c;比如信用卡信息、用户名和密码等情况下。 现在&#xff0c;S…

Flutter 中的 Row 小部件:全面指南

Flutter 中的 Row 小部件&#xff1a;全面指南 在 Flutter 中&#xff0c;Row 是一个水平布局的小部件&#xff0c;用于将子控件沿着水平轴排列。Row 类似于 HTML 中的 div 标签&#xff0c;但仅限于水平布局。它非常适合用来创建行式布局&#xff0c;如表单输入、按钮组、标签…

【linux软件基础知识】完全公平调度

完全公平调度&#xff08;CFS&#xff09; CFS根据每个进程相对于所有可运行线程总权重的权重为每个进程分配一个“时间片”。 CFS 的目标是近似“无限小”的调度持续时间&#xff0c;称为目标延迟。 较小的目标延迟可以提高交互性并接近完美的多任务处理&#xff0c;但其代价…

【Linux网络】Https【下】{CA认证/证书的签发与认证/安全性/总结}

文章目录 1.引入证书【为方案五铺垫】1.1再谈https1.2SSL/TLS1.3CA机构1.4理解数字签名1.4继续铺垫1.5方案五服务端申请证书回顾一二三回顾方案四方案五过程寻找方案五的漏洞客⼾端对证书进⾏认证 2.查看证书2.1查看浏览器的受信任证书发布机构2.2中间⼈有没有可能篡改该证书2.…

差分约束 C++ 算法例题

差分约束 差分约束 是一种特殊的 n 元一次不等式组&#xff0c;m 个约束条件&#xff0c;可以组成形如下的格式&#xff1a; { x 1 − x 1 ′ ≤ y 1 x 2 − x 2 ′ ≤ y 2 ⋯ x m − x m ′ ≤ y m \begin{cases} x_1-x_1^{} \le y_1 \\ x_2-x_2^{} \le y_2 \\ \cdots \\ x_…

数据库的要求

本来我是不准备写数据库的。而且是准备从零开始&#xff0c;学习python&#xff0c;学完语言学&#xff0c;会c和写作技法&#xff0c;再来学习数据库 那样做的复杂度是天量的&#xff0c;按部就班什么的具备&#xff0c;因为你完全不清楚什么时候就有这个基础和条件&#xff0…

【53】Camunda8-Zeebe核心引擎-Partitions分区与Internal processing内部处理

Partitions分区 在Zeebe中,所有数据都是基于分区的。(一个)分区本质上是一个关于流程事件的持久化流。在broker集群中,分区分布在节点之间,因此可以将其视为分片。启动/初始化Zeebe 集群时,用户可以配置所需的分区数。如果使用过Kafka,这部分内容是比较相似的。 每当部…

SpringBoot集成jxls2实现复杂(多表格)excel导出

核心依赖 需求 导出多个表格&#xff0c;包含图片&#xff0c;类似商品标签 1.配置模板 创建一个xlsx的模板文件&#xff0c;配置如下 该模板进行遍历了两次&#xff0c;因为我想要导出的数据分为两列展示&#xff0c;左右布局&#xff0c;一个循环实现不了&#xff0c;所以采…

【ARM64 常见汇编指令学习 20.1 -- ARM 伪指令 .include】

请阅读【嵌入式开发学习必备专栏】 文章目录 ARM 编译指令 .include 使用介绍a.s 文件b.s 文件小结 ARM 编译指令 .include 使用介绍 在UEFI&#xff08;统一可扩展固件接口&#xff09;开发中&#xff0c;通常会用到汇编语言文件&#xff08;.s 或 .S 文件&#xff09;。如果…

百面算法工程师 | 正则优化函数——BN、LN、Dropout

本文给大家带来的百面算法工程师是正则优化函数&#xff0c;文章内总结了常见的提问问题&#xff0c;旨在为广大学子模拟出更贴合实际的面试问答场景。在这篇文章中&#xff0c;我们将总结一些BN、LN、Dropout的相关知识&#xff0c;并提供参考的回答及其理论基础&#xff0c;以…

Linux kbdconfig命令教程:键盘设置与配置(附案例详解和注意事项)

Linux kbdconfig命令介绍 kbdconfig&#xff08;键盘配置&#xff09;是一个用于设置键盘类型的程序&#xff0c;提供图形化的操作界面。kbdconfig实际上是修改/etc/sysconfig/keyboard的键盘配置文件。 Linux kbdconfig命令适用的Linux版本 kbdconfig命令主要在Red Hat Lin…

电商秒杀系统-案例04-redis下的session控制

前言&#xff1a; 在现代的Web应用中&#xff0c;安全和高效的用户身份验证机制是至关重要的。本文将深入探讨基于令牌的用户登录会话机制&#xff0c;特别是在使用Redis进行会话管理的情景。通过这一案例实战&#xff0c;我们将了解令牌如何在用户身份验证过程中发挥核心作用&…

Linux dircolors命令教程:如何设置ls命令的颜色方案(附案例详解和注意事项)

Linux dircolors命令介绍 dircolors命令在Linux中用于设置ls命令显示文件和目录的颜色方案。它可以输出设置LS_COLORS环境变量的命令。 Linux dircolors命令适用的Linux版本 dircolors命令在大多数Linux发行版中都可用&#xff0c;包括Debian、Ubuntu、Alpine、Arch Linux、…

C++ | Leetcode C++题解之第85题最大矩形

题目&#xff1a; 题解&#xff1a; class Solution { public:int maximalRectangle(vector<vector<char>>& matrix) {int m matrix.size();if (m 0) {return 0;}int n matrix[0].size();vector<vector<int>> left(m, vector<int>(n, 0)…

【HCIP学习】BGP对等体组、聚合、路由反射器、联盟、团体属性

一、大规模BGP网络所遇到的问题 BGP对等体众多&#xff0c;配置繁琐&#xff0c;维护管理难度大 BGP路由表庞大&#xff0c;对设备性能提出挑战 IBGP全连接&#xff0c;应用和管理BGP难度增加&#xff0c;邻居数量过多 路由变化频繁&#xff0c;导致路由更新频繁 二、解决大…

使用QT-QSqlQuery::value()遇到的问题

在实现客户端间好友添加功能时&#xff0c;我通过以下函数想实现数据库对好友信息的保存 bool OpeDB::handleAddFriend_repound(const char *pername, const char *name) { // pername 被添加方 name 申请添加方 qDebug() << pername << " " &l…

Nginx(简洁版)

基本配置 worker_processes 1; //默认为1&#xff0c;表示开启一个业务进程 events //事件驱动模块&#xff08;&#xff09;{worker_connections 1024; //单个业务进程可接受连接数 } http{include mime.types; // 引入http mime类型&#xff08;在外部已经定义好&#xff0c…

Java数组——冒泡排序

冒泡排序是最出名的排序算法之一&#xff0c;总共有八大排序。 冒泡排序代码并不复杂&#xff0c;共两层循环&#xff0c;外层冒泡轮数&#xff0c;里层依次比较。 算法步骤&#xff1a; 1. 比较数组中两个相邻元素&#xff0c;如果第一个元素比第二个元素大&#xff0c;交换…