人脸识别

    视频活体检测

    如果您对文档内容有任何疑问,可以通过以下几种方式联系我们:

    • 在百度云控制台内 提交工单,咨询问题类型请选择人工智能服务
    • 如有需要讨论的疑问,欢迎进入 AI社区 与其他开发者们一同交流。

    能力介绍

    业务能力

    H5视频活体检测产品,是由两个接口组合而成,主要用于在H5场景下,通过用户新录制并上传一个视频,来进行活体检测的判断。相对于APP有动作校验+静默图片活体静默图片活体这两种方式,H5视频活体方案比APP方案更加灵活,同时比单张图片活体方式更加安全。其主要功能如下所示:

    • 视频多帧活体检测:录制并上传的视频,会在云端进行随机抽帧分析,并得出最终的活体检测分数。
    • 语音校验码

      • 为防止用户提交非当前操作的视频,在录制视频时,随机分配一个数字,用户需要读出这个数字,在后续识别时校验,以判断视频是否为现场录制。
      • 语音校验码作为辅助性质的验证条件,是一个可选项,如果应用场景比较嘈杂或方言口音比较重,可以不使用语音验证。
    • 唇语识别Beta版

      • 对用户上传的视频进行唇语识别,返回唇语识别是否通过,返回结果为单独字段,与视频活体与语音校验不冲突。
      • 若需要使用唇语识别,需要先使用语音校验码和视频活体检测接口
      • 唇语识别能力当前为Beta版本,识别准确率较低,仅用于辅助验证,您可以通过接口的入参来设置是否使用该能力
    • 合成图识别Beta版

      • 对用户上传的视频抽帧进行合成图像识别,能识别出AI变脸、AI换脸等合成图,让业务更加安全。
      • 合成图识别能力当前为Beta版本,仅用于辅助验证,您可以通过接口的入参来设置是否使用该能力

    以上四项能力,分为两个接口,使用顺序为语音校验码接口->视频活体检测接口,具体调用逻辑可以参考我们的。Demo体验地址(手机端用IOS手机;电脑端用谷歌、火狐浏览器):
    Mobile:https://ai.baidu.com/face-verify/mobile.html
    PC:https://ai.baidu.com/face-verify/pc.html

    主要适用场景

    • 微信服务号:用于对操作用户真实性要求严格的场景,用于依托于微信服务号的金融开户、实名认证、账户信息变更二次验证等服务。
    • APP内Webview:对于如Cordova架构开发的APP,或者APP内变更频繁的身份信息页等情况,可以采用此方案完成活体检测。
    • 浏览器:如果仅是一个H5宣传页,或者Wap版本网页等,可以通过此方法快速集成更加安全的活体检测功能。

    此方案的优劣势

    • 优势:相对于APP有动作校验、单张图片静默判断,此方法在没有APP情况下,可以更快速、轻量级地实现活体检测,同时保障一定安全性。
    • 劣势:由于视频较大,上传时间可能较长,另由于不同手机的浏览器内核差异较大,容易出现兼容性问题。

    调用方式

    请求URL数据格式

    向API服务地址使用POST发送请求,必须在URL中带上参数access_token,可通过后台的API Key和Secret Key生成,具体方式请参考“Access Token获取”。

    示例代码

    #!/bin/bash
    curl -i -k 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=【百度云应用的AK】&client_secret=【百度云应用的SK】'
    <?php
    function request_post($url = '', $param = '') {
            if (empty($url) || empty($param)) {
                return false;
            }
            
            $postUrl = $url;
            $curlPost = $param;
            $curl = curl_init();//初始化curl
            curl_setopt($curl, CURLOPT_URL,$postUrl);//抓取指定网页
            curl_setopt($curl, CURLOPT_HEADER, 0);//设置header
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);//要求结果为字符串且输出到屏幕上
            curl_setopt($curl, CURLOPT_POST, 1);//post提交方式
            curl_setopt($curl, CURLOPT_POSTFIELDS, $curlPost);
            $data = curl_exec($curl);//运行curl
            curl_close($curl);
            
            return $data;
        }
    
        $url = 'https://aip.baidubce.com/oauth/2.0/token';
        $post_data['grant_type']       = 'client_credentials';
        $post_data['client_id']      = '你的 Api Key';
        $post_data['client_secret'] = '你的 Secret Key';
        $o = "";
        foreach ( $post_data as $k => $v ) 
        {
            $o.= "$k=" . urlencode( $v ). "&" ;
        }
        $post_data = substr($o,0,-1);
        
        $res = request_post($url, $post_data);
    
        var_dump($res);
    
    ?>
    package com.baidu.ai.aip.auth;
    
    import org.json.JSONObject;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 获取token类
     */
    public class AuthService {
    
        /**
         * 获取权限token
         * @return 返回示例:
         * {
         * "access_token": "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567",
         * "expires_in": 2592000
         * }
         */
        public static String getAuth() {
            // 官网获取的 API Key 更新为你注册的
            String clientId = "百度云应用的AK";
            // 官网获取的 Secret Key 更新为你注册的
            String clientSecret = "百度云应用的SK";
            return getAuth(clientId, clientSecret);
        }
    
        /**
         * 获取API访问token
         * 该token有一定的有效期,需要自行管理,当失效时需重新获取.
         * @param ak - 百度云官网获取的 API Key
         * @param sk - 百度云官网获取的 Securet Key
         * @return assess_token 示例:
         * "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567"
         */
        public static String getAuth(String ak, String sk) {
            // 获取token地址
            String authHost = "https://aip.baidubce.com/oauth/2.0/token?";
            String getAccessTokenUrl = authHost
                    // 1. grant_type为固定参数
                    + "grant_type=client_credentials"
                    // 2. 官网获取的 API Key
                    + "&client_id=" + ak
                    // 3. 官网获取的 Secret Key
                    + "&client_secret=" + sk;
            try {
                URL realUrl = new URL(getAccessTokenUrl);
                // 打开和URL之间的连接
                HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
                connection.setRequestMethod("GET");
                connection.connect();
                // 获取所有响应头字段
                Map<String, List<String>> map = connection.getHeaderFields();
                // 遍历所有的响应头字段
                for (String key : map.keySet()) {
                    System.err.println(key + "--->" + map.get(key));
                }
                // 定义 BufferedReader输入流来读取URL的响应
                BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String result = "";
                String line;
                while ((line = in.readLine()) != null) {
                    result += line;
                }
                /**
                 * 返回结果示例
                 */
                System.err.println("result:" + result);
                JSONObject jsonObject = new JSONObject(result);
                String access_token = jsonObject.getString("access_token");
                return access_token;
            } catch (Exception e) {
                System.err.printf("获取token失败!");
                e.printStackTrace(System.err);
            }
            return null;
        }
    
    }
     # encoding:utf-8
    import requests 
    
    # client_id 为官网获取的AK, client_secret 为官网获取的SK
    host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=【官网获取的AK】&client_secret=【官网获取的SK】'
    response = requests.get(host)
    if response:
        print(response.json())
    #include <iostream>
    #include <curl/curl.h>
    #include <json/json.h>
    #include "access_token.h"
    // libcurl库下载链接:https://curl.haxx.se/download.html
    // jsoncpp库下载链接:https://github.com/open-source-parsers/jsoncpp/
    // 获取access_token所需要的url
    const std::string access_token_url = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials";
    // 回调函数获取到的access_token存放变量
    // static std::string access_token_result;
    /**
     * curl发送http请求调用的回调函数,回调函数中对返回的json格式的body进行了解析,解析结果储存在result中
     * @param 参数定义见libcurl库文档
     * @return 返回值定义见libcurl库文档
     */
    static size_t callback(void *ptr, size_t size, size_t nmemb, void *stream) {
        // 获取到的body存放在ptr中,先将其转换为string格式
        std::string s((char *) ptr, size * nmemb);
        // 开始获取json中的access token项目
        Json::Reader reader;
        Json::Value root;
        // 使用boost库解析json
        reader.parse(s,root);
        std::string* access_token_result = static_cast<std::string*>(stream);
        *access_token_result = root["access_token"].asString();
        return size * nmemb;
    }
    
    /**
     * 用以获取access_token的函数,使用时需要先在百度云控制台申请相应功能的应用,获得对应的API Key和Secret Key
     * @param access_token 获取得到的access token,调用函数时需传入该参数
     * @param AK 应用的API key
     * @param SK 应用的Secret key
     * @return 返回0代表获取access token成功,其他返回值代表获取失败
     */
    int get_access_token(std::string &access_token, const std::string &AK, const std::string &SK) {
        CURL *curl;
        CURLcode result_code;
        int error_code = 0;
        curl = curl_easy_init();
        if (curl) {
            std::string url = access_token_url + "&client_id=" + AK + "&client_secret=" + SK;
            curl_easy_setopt(curl, CURLOPT_URL, url.data());
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
            std::string access_token_result;
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &access_token_result);
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
            result_code = curl_easy_perform(curl);
            if (result_code != CURLE_OK) {
                fprintf(stderr, "curl_easy_perform() failed: %s\n",
                        curl_easy_strerror(result_code));
                return 1;
            }
            access_token = access_token_result;
            curl_easy_cleanup(curl);
            error_code = 0;
        } else {
            fprintf(stderr, "curl_easy_init() failed.");
            error_code = 1;
        }
        return error_code;
    }
    using System;
    using System.Collections.Generic;
    using System.Net.Http;
    
    namespace com.baidu.ai
    {
        public static class AccessToken
    
        {
            // 调用getAccessToken()获取的 access_token建议根据expires_in 时间 设置缓存
            // 返回token示例
            public static String TOKEN = "24.adda70c11b9786206253ddb70affdc46.2592000.1493524354.282335-1234567";
    
            // 百度云中开通对应服务应用的 API Key 建议开通应用的时候多选服务
            private static String clientId = "百度云应用的AK";
            // 百度云中开通对应服务应用的 Secret Key
            private static String clientSecret = "百度云应用的SK";
    
            public static String getAccessToken() {
                String authHost = "https://aip.baidubce.com/oauth/2.0/token";
                HttpClient client = new HttpClient();
                List<KeyValuePair<String, String>> paraList = new List<KeyValuePair<string, string>>();
                paraList.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
                paraList.Add(new KeyValuePair<string, string>("client_id", clientId));
                paraList.Add(new KeyValuePair<string, string>("client_secret", clientSecret));
    
                HttpResponseMessage response = client.PostAsync(authHost, new FormUrlEncodedContent(paraList)).Result;
                String result = response.Content.ReadAsStringAsync().Result;
                Console.WriteLine(result);
                return result;
            }
        }
    }
    var https = require('https');
    var qs = require('querystring');
    
    const param = qs.stringify({
        'grant_type': 'client_credentials',
        'client_id': '您的 Api Key',
        'client_secret': '您的 Secret Key'
    });
    
    https.get(
        {
            hostname: 'aip.baidubce.com',
            path: '/oauth/2.0/token?' + param,
            agent: false
        },
        function (res) {
            // 在标准输出中查看运行结果
            res.pipe(process.stdout);
        }
    );

    注意access_token的有效期为30天,切记需要每30天进行定期更换,或者每次请求都拉取新token

    例如此接口,使用HTTPS POST发送:

    https://aip.baidubce.com/rest/2.0/face/v1/merge?access_token=24.f9ba9c5341b67688ab4added8bc91dec.2592000.1485570332.282335-8574074

    POST中Body的参数,按照下方请求参数说明选择即可。

    提示:如果您为百度云老用户,正在使用其他非AI的服务,可以参考百度云AKSK鉴权方式发送请求,虽然请求方式鉴权方法和本文所介绍的不同,但请求参数和返回结果一致。

    语音校验码接口

    接口描述

    此接口主要用于生成随机码,用于视频的语音识别校验使用,以判断视频的即时性,而非事先录制的,提升作弊的难度。

    请求说明

    请求示例

    HTTP方法:POST

    请求URL: https://aip.baidubce.com/rest/2.0/face/v1/faceliveness/sessioncode

    URL参数:

    参数
    access_token 通过API Key和Secret Key获取的access_token,参考“Access Token获取

    Header:

    参数
    Content-Type application/x-www-form-urlencoded

    Body中放置请求参数,参数详情如下:

    • 请求参数
    参数名 必选 类型 说明
    min_code_length int 生成的验证码最小长度 最大6 最小3 默认3
    max_code_length int 生成的验证码最大长度 最大6 最小3 默认6

    返回说明

    返回参数

    字段 必选 类型 说明
    session_id string 语音校验码会话id,有效期5分钟,请提示用户在五分钟内完成全部操作
    code string 语音验证码,数字形式,3~6位数字

    返回示例

    {
    	"err_no": 0,
    	"err_msg": "SUCCESS",
    	"result": {
    		"session_id": "S59faeeebb9111890355690", //会话ID      
          "code": "9940"  
          },  
    		"timestamp": 1509617387,
    		"cached": 0,
    		"serverlogid": "0587756642",
    		"error_code": 0,
    		"error_message": "SUCCESS"
    }

    error_code为0即代表成功, 其他情况则为失败

    视频活体检测接口

    接口描述

    此接口一方面通过语音识别得到校验码,通过session code来判断视频是否作弊。另一方面进行视频抽帧,判断是否为活体。

    请求说明

    请求示例

    HTTP方法:POST

    请求URL: https://aip.baidubce.com/rest/2.0/face/v1/faceliveness/verify

    URL参数:

    参数
    access_token 通过API Key和Secret Key获取的access_token,参考“Access Token获取

    Header:

    参数
    Content-Type application/x-www-form-urlencoded

    Body中放置请求参数,参数详情如下:

    请求参数

    参数名 必选 类型 说明
    video_base64 string base64 编码的视频数据;
    建议视频大小控制在10M/1min以内
    session_id string 会话ID (当此字段为空时,则跳过语音验证和唇语验证步骤)
    lip_identify string 取值COMMON/STRICT/OFF, COMMON代表使用唇语识别,STRICT代表使用唇语识别并使用更加严格的策略判断是否通过 OFF代表关闭唇语识别,默认OFF
    face_field string 需要使用合成图功能时, 此项传入spoofing

    唇语识别中,使用STRICT策略会比使用COMMON策略通过率降低,但攻击拒绝率会提升 建议视频大小控制在10M/1min以内

    返回说明

    返回参数

    参数名 类型 说明
    score float 活体检测的总体打分 范围[0,1],分数越高则活体的概率越大
    maxspoofing float 判断是否是合成图功能 范围[0,1],分数越高则概率越大
    thresholds array 阈值 按活体检测分数>阈值来判定活体检测是否通过(阈值视产品需求选择其中一个)
    code array 验证码信息
    +create string 生成的验证码
    +identify string 验证码的语音识别结果
    +similarity float 验证码相似度 取值0~1 1代表完全一致 0代表完全不一致 推荐阈值0.75
    lip_language string 唇语识别结果 pass代表唇语验证通过,fail代表唇语验证未通过
    pic_list array 抽取出来的图片信息(共8张)
    +face_token string 人脸图片的唯一标识
    +pic string base64编码后的图片信息
    +liveness_score float 此图片的活体分数,范围[0,1]
    +spoofing float 判断此图片是合成图的分数,范围[0,1]

    返回示例

    {
        "err_no": 0,
        "err_msg": "SUCCESS",
        "result": {
            "pic_list": [     //默认返回8张图片 
                {
                    "pic": "/9j//gAQTGF2YzU4LjU3LjEwMAD/2wBD...",
                    "face_token": "20f59d5d1396cf38b5afd46e7ce147ec",
                    "face_id": "20f59d5d1396cf38b5afd46e7ce147ec",
                    "liveness_score": 0.99,
                    "spoofing": 0.001312574488
                },
                {
                    "pic": "/9j//gAQTGF2YzU4LjU3LjEjEwMAD/2wBD...",
                    "face_token": "57b2a27738602b701b359d43c242341c",
                    "face_id": "57b2a27738602b701b359d43c242341c",
                    "liveness_score": 1,
                    "spoofing": 0.0007703750744
                }
            ],
            "score": 1,
            "maxspoofing": 0.001557751792,
            "thresholds": {
                "frr_1e-4": 0.05,
                "frr_1e-3": 0.3,
                "frr_1e-2": 0.9
            }
        },
        "timestamp": 1591679143,
        "cached": 0,
        "serverlogid": 7579451500184,
        "error_code": 0,
        "error_msg": "SUCCESS"
    }

    活体阈值参考

    请务必在产品侧做好以下条件限制

    • 检测的图片为二次采集,即通过相机当场拍摄,确保时间及操作条件的约束;
    • SDK输出的多帧情况,只要这些帧中,任何一张通过了阈值,即可判断为活体,建议可用三帧情况
    • 推荐分值采用99.5%

    关于活体检测faceliveness的判断阈值选择,可参考以下数值信息

    阈值(Threshold) 误拒率(FRR) 通过率(TAR) 攻击拒绝率(TRR))
    0.05 0.01% 99.99% 97.75%
    0.1 0.05% 99.95% 98.33%
    0.3 (推荐 0.1% 99.9% 98.82%
    0.5 0.5% 99.5% 99.67%
    0.9 1% 99% 99.77%

    关于以上数值的概念介绍

    • 拒绝率(TRR):如99%,代表100次作弊假体攻击,会有99次被拒绝。
    • 误拒率(FRR):如0.5%,指1000次真人请求,会有5次因为活体分数低于阈值被错误拒绝。
    • 通过率(TAR):如99%,指100次真人请求,会有99次因为活体分数高于阈值而通过。
    • 阈值(Threshold):高于此数值,则可判断为活体。

    合成图阈值参考

    新推出合成图检测能力,在入参字段中增加spoofing参数,进行判断,若spoofing分值高于合成图推荐阈值,则可判断为合成图攻击

    关于合成图检测spoofing的判断阈值选择,可参考以下数值信息

    阈值 误拒率(FRR) 通过率(TAR) 攻击拒绝率(TRR))
    0.00023 5% 95% 94.93%
    0.00048(推荐 1% 99% 89.71%
    0.00066 0.5% 99.5% 88.02%
    0.00109 0.1% 99.9% 84.57%
    0.00171 0.05% 99.95% 81.52%
    0.00547 0.01% 99.99% 65.52%
    • 阈值(Threshold):高于此数值,则可判断为是合成图攻击。

    错误码列表

    错误码 error_msg 错误信息 描述
    216430 rtse/face service error rtse/face 服务异常 请重新尝试
    216431 voice service error 语音识别服务异常 请重新尝试
    216432 video service call fail 视频解析服务调用失败 请重新尝试
    216433 video service error 视频解析服务发生错误 请重新尝试
    216434 liveness check fail 活体检测失败 请重新尝试
    216500 code digit error 验证码位数错误 验证码错误,
    请增加一层验证环节
    216501 not found face 没有找到人脸 请查看上传视频是否包含人脸
    216502 session lapse 当前会话已失效 请重新获取语音验证码
    216505 redis connect error redis连接失败 请重新尝试
    216506 redis operation error redis操作失败 请重新尝试
    216507 found many faces 视频中有多张人脸 请重新录制视频
    216508 not found video info 没有找到视频信息 请参考文档修改视频格式
    216509 voice can not identify 视频中的声音无法识别
    (声音过低或者有杂
    音导致无法识别)
    请重新录制视频
    216908 视频中人脸质量较差
    (返回信息中包含具体原因)
    视频中人脸质量过低
    (返回的错误信息会包含
    具体的错误信息包含
    illumiantion(光照不足) angle(角度不好)
    blur (人脸模糊) occlusion(有遮挡)
    too large(人脸过大, 占屏幕2/3以上) 等原因
    请重新录制视频
    222027 code length param error 验证码长度错误
    (最小值大于最大值)
    参考API说明文档,修改参数
    222028 param[min_code_length] format error 参数格式错误 参考API说明文档,修改参数
    222029 param[max_code_length] format error 参数格式错误 参考API说明文档,修改参数
    222030 param[match_threshold] format error 参数格式错误 参考API说明文档,修改参数
    上一篇
    在线活体检测
    下一篇
    人像特效API文档