活体检测
如果您对文档内容有任何疑问,可以通过以下几种方式联系我们:
一、视频活体检测
能力介绍
业务能力
视频活体检测产品,是由两个接口组合而成,主要用于在H5场景下,通过用户新录制并上传一个视频,来进行活体检测的判断。相对于APP有动作校验+静默图片活体、静默图片活体这两种方式,视频活体检测方案比APP方案更加灵活,同时比单张图片活体方式更加安全。其主要功能如下所示:
- 视频多帧活体检测:录制并上传的视频,会在云端进行随机抽帧分析,并得出最终的活体检测分数。
- 
随机校验码:(用于在语音/动作活体检测中生成随机数字/动作) - 为防止用户提交非当前操作的视频,选择随机验证码后,即可在录制视频时,随机生成数字/动作,用户需要读出数字/做出相应动作,在后续识别时校验,以判断视频是否为现场录制。
- 随机校验码作为辅助性质的验证条件,是一个可选项,可根据业务具体应用场景来选择是否使用,以及根据业务场景决定选择语音/动作活体检测方式。如业务场景比较嘈杂或方言口音比较重,可不使用语音活体检测方式,选择动作活体检测方式进行校验。
 
- 
唇语识别Beta版: - 对用户上传的视频进行唇语识别,返回唇语识别是否通过,返回结果为单独字段,与视频活体与语音/动作校验不冲突。
- 若需要使用唇语识别,需要先使用随机校验码和视频活体检测接口,且活体检测方式应配置为语音活体检测。
- 唇语识别能力当前为Beta版本,识别准确率较低,仅用于辅助 语音活体检测方式 进行验证,您可以通过接口的入参来设置是否使用该能力
 
- 
合成图识别Beta版: - 对用户上传的视频抽帧进行合成图像识别,能识别出AI变脸、AI换脸等合成图,让业务更加安全。
- 合成图识别能力当前为Beta版本,仅用于辅助验证,您可以通过接口的入参来设置是否使用该能力
 
以上四项能力,分为两个接口,使用顺序为
随机校验码接口->视频活体检测接口,具体调用逻辑可以参考文档 接口文档
主要适用场景
- 微信服务号:用于对操作用户真实性要求严格的场景,用于依托于微信服务号的金融开户、实名认证、账户信息变更二次验证等服务。
- APP内Webview:对于如Cordova架构开发的APP,或者APP内变更频繁的身份信息页等情况,可以采用此方案完成活体检测。
- 浏览器:如果仅是一个H5宣传页,或者Wap版本网页等,可以通过此方法快速集成更加安全的活体检测功能。
此方案的优劣势
- 优势:相对于APP有动作校验、单张图片静默判断,此方法在没有APP情况下,可以更快速、轻量级地实现活体检测,同时保障一定安全性。
- 劣势:由于视频较大,上传时间可能较长,另由于不同手机的浏览器内核差异较大,容易出现兼容性问题。
调用方式
请求URL数据格式
向API服务地址使用POST发送请求,必须在URL中带上参数access_token,可通过后台的API Key和Secret Key生成,具体方式请参考“Access Token获取”。
示例代码
1#!/bin/bash
2curl -i -k 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=【百度云应用的AK】&client_secret=【百度云应用的SK】'1<?php
2function request_post($url = '', $param = '') {
3        if (empty($url) || empty($param)) {
4            return false;
5        }
6        
7        $postUrl = $url;
8        $curlPost = $param;
9        $curl = curl_init();//初始化curl
10        curl_setopt($curl, CURLOPT_URL,$postUrl);//抓取指定网页
11        curl_setopt($curl, CURLOPT_HEADER, 0);//设置header
12        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);//要求结果为字符串且输出到屏幕上
13        curl_setopt($curl, CURLOPT_POST, 1);//post提交方式
14        curl_setopt($curl, CURLOPT_POSTFIELDS, $curlPost);
15        $data = curl_exec($curl);//运行curl
16        curl_close($curl);
17        
18        return $data;
19    }
20
21    $url = 'https://aip.baidubce.com/oauth/2.0/token';
22    $post_data['grant_type']       = 'client_credentials';
23    $post_data['client_id']      = '你的 Api Key';
24    $post_data['client_secret'] = '你的 Secret Key';
25    $o = "";
26    foreach ( $post_data as $k => $v ) 
27    {
28        $o.= "$k=" . urlencode( $v ). "&" ;
29    }
30    $post_data = substr($o,0,-1);
31    
32    $res = request_post($url, $post_data);
33
34    var_dump($res);
35
36?>1package com.baidu.ai.aip.auth;
2
3import org.json.JSONObject;
4
5import java.io.BufferedReader;
6import java.io.InputStreamReader;
7import java.net.HttpURLConnection;
8import java.net.URL;
9import java.util.List;
10import java.util.Map;
11
12/**
13 * 获取token类
14 */
15public class AuthService {
16
17    /**
18     * 获取权限token
19     * @return 返回示例:
20     * {
21     * "access_token": "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567",
22     * "expires_in": 2592000
23     * }
24     */
25    public static String getAuth() {
26        // 官网获取的 API Key 更新为你注册的
27        String clientId = "百度云应用的AK";
28        // 官网获取的 Secret Key 更新为你注册的
29        String clientSecret = "百度云应用的SK";
30        return getAuth(clientId, clientSecret);
31    }
32
33    /**
34     * 获取API访问token
35     * 该token有一定的有效期,需要自行管理,当失效时需重新获取.
36     * @param ak - 百度云官网获取的 API Key
37     * @param sk - 百度云官网获取的 Securet Key
38     * @return assess_token 示例:
39     * "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567"
40     */
41    public static String getAuth(String ak, String sk) {
42        // 获取token地址
43        String authHost = "https://aip.baidubce.com/oauth/2.0/token?";
44        String getAccessTokenUrl = authHost
45                // 1. grant_type为固定参数
46                + "grant_type=client_credentials"
47                // 2. 官网获取的 API Key
48                + "&client_id=" + ak
49                // 3. 官网获取的 Secret Key
50                + "&client_secret=" + sk;
51        try {
52            URL realUrl = new URL(getAccessTokenUrl);
53            // 打开和URL之间的连接
54            HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
55            connection.setRequestMethod("GET");
56            connection.connect();
57            // 获取所有响应头字段
58            Map<String, List<String>> map = connection.getHeaderFields();
59            // 遍历所有的响应头字段
60            for (String key : map.keySet()) {
61                System.err.println(key + "--->" + map.get(key));
62            }
63            // 定义 BufferedReader输入流来读取URL的响应
64            BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
65            String result = "";
66            String line;
67            while ((line = in.readLine()) != null) {
68                result += line;
69            }
70            /**
71             * 返回结果示例
72             */
73            System.err.println("result:" + result);
74            JSONObject jsonObject = new JSONObject(result);
75            String access_token = jsonObject.getString("access_token");
76            return access_token;
77        } catch (Exception e) {
78            System.err.printf("获取token失败!");
79            e.printStackTrace(System.err);
80        }
81        return null;
82    }
83
84}1# encoding:utf-8
2import requests 
3
4# client_id 为官网获取的AK, client_secret 为官网获取的SK
5host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=【官网获取的AK】&client_secret=【官网获取的SK】'
6response = requests.get(host)
7if response:
8    print(response.json())1#include <iostream>
2#include <curl/curl.h>
3#include <json/json.h>
4#include "access_token.h"
5// libcurl库下载链接:https://curl.haxx.se/download.html
6// jsoncpp库下载链接:https://github.com/open-source-parsers/jsoncpp/
7// 获取access_token所需要的url
8const std::string access_token_url = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials";
9// 回调函数获取到的access_token存放变量
10// static std::string access_token_result;
11/**
12 * curl发送http请求调用的回调函数,回调函数中对返回的json格式的body进行了解析,解析结果储存在result中
13 * @param 参数定义见libcurl库文档
14 * @return 返回值定义见libcurl库文档
15 */
16static size_t callback(void *ptr, size_t size, size_t nmemb, void *stream) {
17    // 获取到的body存放在ptr中,先将其转换为string格式
18    std::string s((char *) ptr, size * nmemb);
19    // 开始获取json中的access token项目
20    Json::Reader reader;
21    Json::Value root;
22    // 使用boost库解析json
23    reader.parse(s,root);
24    std::string* access_token_result = static_cast<std::string*>(stream);
25    *access_token_result = root["access_token"].asString();
26    return size * nmemb;
27}
28
29/**
30 * 用以获取access_token的函数,使用时需要先在百度云控制台申请相应功能的应用,获得对应的API Key和Secret Key
31 * @param access_token 获取得到的access token,调用函数时需传入该参数
32 * @param AK 应用的API key
33 * @param SK 应用的Secret key
34 * @return 返回0代表获取access token成功,其他返回值代表获取失败
35 */
36int get_access_token(std::string &access_token, const std::string &AK, const std::string &SK) {
37    CURL *curl;
38    CURLcode result_code;
39    int error_code = 0;
40    curl = curl_easy_init();
41    if (curl) {
42        std::string url = access_token_url + "&client_id=" + AK + "&client_secret=" + SK;
43        curl_easy_setopt(curl, CURLOPT_URL, url.data());
44        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
45        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
46        std::string access_token_result;
47        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &access_token_result);
48        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
49        result_code = curl_easy_perform(curl);
50        if (result_code != CURLE_OK) {
51            fprintf(stderr, "curl_easy_perform() failed: %s\n",
52                    curl_easy_strerror(result_code));
53            return 1;
54        }
55        access_token = access_token_result;
56        curl_easy_cleanup(curl);
57        error_code = 0;
58    } else {
59        fprintf(stderr, "curl_easy_init() failed.");
60        error_code = 1;
61    }
62    return error_code;
63}1using System;
2using System.Collections.Generic;
3using System.Net.Http;
4
5namespace com.baidu.ai
6{
7    public static class AccessToken
8
9    {
10        // 调用getAccessToken()获取的 access_token建议根据expires_in 时间 设置缓存
11        // 返回token示例
12        public static String TOKEN = "24.adda70c11b9786206253ddb70affdc46.2592000.1493524354.282335-1234567";
13
14        // 百度云中开通对应服务应用的 API Key 建议开通应用的时候多选服务
15        private static String clientId = "百度云应用的AK";
16        // 百度云中开通对应服务应用的 Secret Key
17        private static String clientSecret = "百度云应用的SK";
18
19        public static String getAccessToken() {
20            String authHost = "https://aip.baidubce.com/oauth/2.0/token";
21            HttpClient client = new HttpClient();
22            List<KeyValuePair<String, String>> paraList = new List<KeyValuePair<string, string>>();
23            paraList.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
24            paraList.Add(new KeyValuePair<string, string>("client_id", clientId));
25            paraList.Add(new KeyValuePair<string, string>("client_secret", clientSecret));
26
27            HttpResponseMessage response = client.PostAsync(authHost, new FormUrlEncodedContent(paraList)).Result;
28            String result = response.Content.ReadAsStringAsync().Result;
29            Console.WriteLine(result);
30            return result;
31        }
32    }
33}1var https = require('https');
2var qs = require('querystring');
3
4const param = qs.stringify({
5    'grant_type': 'client_credentials',
6    'client_id': '您的 Api Key',
7    'client_secret': '您的 Secret Key'
8});
9
10https.get(
11    {
12        hostname: 'aip.baidubce.com',
13        path: '/oauth/2.0/token?' + param,
14        agent: false
15    },
16    function (res) {
17        // 在标准输出中查看运行结果
18        res.pipe(process.stdout);
19    }
20);注意:
access_token的有效期为30天,切记需要每30天进行定期更换,或者每次请求都拉取新token;
例如此接口,使用HTTPS POST发送:
1https://aip.baidubce.com/rest/2.0/face/v1/merge?access_token=24.f9ba9c5341b67688ab4added8bc91dec.2592000.1485570332.282335-8574074POST中Body的参数,按照下方请求参数说明选择即可。
提示:如果您为百度云老用户,正在使用其他非AI的服务,可以参考百度云AKSK鉴权方式发送请求,虽然请求方式和鉴权方法和本文所介绍的不同,但请求参数和返回结果一致。
1.1 随机校验码接口(原语音验证码接口)
接口描述
此接口主要用于生成随机码,用于视频的语音/动作识别校验使用,以判断视频的即时性,而非事先录制的,提升作弊的难度。
在线调试
您可以在 API Explorer 中调试该接口,可进行签名验证、查看在线调用的请求内容和返回结果、示例代码的自动生成。
请求说明
请求示例
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中放置请求参数,参数详情如下:
- 请求参数
| 参数名 | 必选 | 类型 | 说明 | 
|---|---|---|---|
| type | 否 | int | 0为语音验证和唇语验证步骤, 1为视频动作活体 默认0 | 
| min_code_length | 否 | int | 当type=0时,语音和唇语生成的验证码最小长度:最大6 最小3 默认3 当type=1时,视频动作活体 的验证码最小长度:最大3 最小1 默认1 | 
| max_code_length | 否 | int | 当type=0时,语音和唇语生成的验证码最大长度:最大6 最小3 默认6 当type=1时,视频动作活体 的验证码最大长度:最大3 最小1 默认3 | 
说明:
- 当传参为1-1-3时,代表随机生成1-3个动作进行核验;
- 当传参为1-1-1时,代表随机生成1个动作进行核验;
- 当传参为1-2-2时,代表随机生成2个动作进行核验;
- 当传参为1-3-3时,代表随机生成3个动作进行核验。
返回说明
返回参数
| 字段 | 必选 | 类型 | 说明 | 
|---|---|---|---|
| session_id | 是 | string | 随机校验码会话id,有效期5分钟,请提示用户在五分钟内完成全部操作 验证码使用过即失效,每次使用视频活体前请重新拉取验证码 | 
| code | 是 | string | 随机验证码,数字形式,1~6位数字; 若为动作活体时,返回数字表示的动作对应关系为:0:眨眼 2:右转 3:左转 4:抬头 5:低头 | 
返回示例
1{
2   "err_no": 0,
3   "err_msg": "SUCCESS",
4   "result": {
5       "session_id": "S59faeeebb9111890355690", //会话ID
6       "code": "034" //当为视频动作活体时,返回值的代表所需动作和动作顺序。 0:眨眼  2:右转 3:左转  4:抬头  5:低头
7   },
8   "timestamp": 1509617387,
9   "cached": 0,
10   "serverlogid": "0587756642",
11   "error_code": 0,
12    "error_message": "SUCCESS"
13}error_code为0即代表成功, 其他情况则为失败
1.2 视频活体检测接口
接口描述
此接口一方面通过随机验证码接口获取语音/动作校验码,通过session code来判断视频是否作弊。另一方面进行视频抽帧,判断是否为活体。
在线调试
您可以在 API Explorer 中调试该接口,可进行签名验证、查看在线调用的请求内容和返回结果、示例代码的自动生成。
请求说明
请求示例
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中放置请求参数,参数详情如下:
请求参数
| 参数名 | 必选 | 类型 | 说明 | 
|---|---|---|---|
| type_identify | 否 | string | voice为语音验证,action为视频动作活体验证,默认为voice (若您需要静默视频活体验证,此参数无需传入) | 
| video_base64 | 是 | string | base64 编码的视频数据(编码前建议先将视频进行转码,h.264编码,mp4封装)需要注意的是,视频的base64编码是不包含视频头的,如 data:video/mp4;base64,; 建议视频长度控制在01s-10s之间,视频大小建议在2M以内(视频大小强制要求在20M以内,推荐使用等分辨率压缩,压缩分辨率建议不小于640*480) 视频大小分辨率建议限制在16~2032之间 | 
| 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 | 返回的1-8张图片中合成图检测得分的最大值 范围[0,1],分数越高则概率越大 | 
| spoofing_score | float | 返回的1-8张图片中合成图检测得分的中位数 范围[0,1],分数越高则概率越大 | 
| thresholds | array | 阈值 按活体检测分数>阈值来判定活体检测是否通过(阈值视产品需求选择其中一个) | 
| code | array | 验证码信息 | 
| +create | string | 生成的验证码 | 
| +identify | string | 验证码的语音识别结果 | 
| +similarity | float | 验证码相似度 取值0~1 1代表完全一致 0代表完全不一致 推荐阈值0.75 | 
| lip_language | string | 唇语识别结果 pass代表唇语验证通过,fail代表唇语验证未通过,当存在请求字段lip_identify字段值为 COMMON 或 STRICT时返回 | 
| action_verify | string | 动作识别结果 pass代表动作验证通过,fail代表动作验证未通过,当存在请求字段type_identify字段值为action时返回 | 
| best_image | array | 质量最佳图片 | 
| +face_token | string | 人脸图片的唯一标识 | 
| +pic | string | base64编码后的图片信息 | 
| +liveness_score | float | 此图片的活体分数,范围[0,1] | 
| pic_list | array | 返回1-8张抽取出来的图片信息 | 
| +face_token | string | 人脸图片的唯一标识 | 
| +spoofing | float | 此图片的合成图分数,范围[0,1] | 
返回示例
1{
2"err_no": 0,
3"err_msg": "SUCCESS",
4"result": {
5    "score": 0.18,
6    "maxspoofing": 0.0002082588035,
7    "spoofing_score": 0.00018671568975,
8    "code": {
9        "create": "853",
10        "identify": "23456789",
11        "similarity": 0.13
12    },
13    "lip_language": "fail",     //lip_identify 为 COMMON 或 STRICT 时返回该字段值,值为pass 或 false
14    "action_verify": "fail",    //type_identify 为 action 时返回该字段值,值为pass 或 false【注意:action_verify与lip_language是互斥的】
15    "thresholds": {
16          "frr_1e-4": 0.05,     //万分之一误拒率的阈值
17          "frr_1e-3": 0.3,      //千分之一误拒率的阈值
18          "frr_1e-2": 0.9,      //百分之一误拒率的阈值
19    },
20    "best_image": {
21        "pic": "图片base64值",
22        "face_token": "0839b921224816fb558b0a74ee6284fb",
23        "face_id": "0839b921224816fb558b0a74ee6284fb",
24        "liveness_score": 0.9634260269,
25        "spoofing": 0.0001962436945
26    },
27    "pic_list": [ //默认返回8张图片
28        {
29            "pic" : "gAQTGF2YzU4LjkyLjEwMAD", //图片base64编码后的值
30            "face_token": "f043b6c7d202cb25e8dfc24fccf37553",
31            "face_id": "f043b6c7d202cb25e8dfc24fccf37553",
32            "liveness_score": 0.18,
33            "spoofing": 0.000179775554
34        },
35        {
36            "pic" : "gAQTGF2YzU4LjkyLjEwMAD", //图片base64编码后的值
37            "face_token": "d12b7e32069d337dc5d57cd3d15e2935",
38            "face_id": "d12b7e32069d337dc5d57cd3d15e2935",
39            "liveness_score": 0.06,
40            "spoofing": 0.0002082588035
41        },
42        {
43            "pic" : "gAQTGF2YzU4LjkyLjEwMAD", //图片base64编码后的值
44            "face_token": "6411f95f491fb665c389de03a33f12a4",
45            "face_id": "6411f95f491fb665c389de03a33f12a4",
46            "liveness_score": 0.06,
47            "spoofing": 0.0001938246714
48        },
49        {
50            "pic" : "gAQTGF2YzU4LjkyLjEwMAD", //图片base64编码后的值
51            "face_token": "d7fb09b7942555bf1e4b8d47a63c2e4b",
52            "face_id": "d7fb09b7942555bf1e4b8d47a63c2e4b",
53            "liveness_score": 0.05,
54            "spoofing": 0.0001579090458
55        },
56        {
57            "pic" : "gAQTGF2YzU4LjkyLjEwMAD", //图片base64编码后的值
58            "face_token": "b14f94951a1d1b0fb8770bb1ef2bf2e7",
59            "face_id": "b14f94951a1d1b0fb8770bb1ef2bf2e7",
60            "liveness_score": 0.05,
61            "spoofing": 0.0001889262057
62        },
63        {
64            "pic" : "gAQTGF2YzU4LjkyLjEwMAD", //图片base64编码后的值
65            "face_token": "f7f363d0e71e91906dbdcfec0573de70",
66            "face_id": "f7f363d0e71e91906dbdcfec0573de70",
67            "liveness_score": 0.05,
68            "spoofing": 0.0001999060332
69        },
70        {
71            "pic" : "gAQTGF2YzU4LjkyLjEwMAD", //图片base64编码后的值
72            "face_token": "388bdccbd70200f62c5f46a84b012691",
73            "face_id": "388bdccbd70200f62c5f46a84b012691",
74            "liveness_score": 0.04,
75            "spoofing": 0.0001798788871
76        },
77        {
78            "pic" : "gAQTGF2YzU4LjkyLjEwMAD", //图片base64编码后的值
79            "face_token": "5fa4e1116f00912f66dba9b42a6a739e",
80            "face_id": "5fa4e1116f00912f66dba9b42a6a739e",
81            "liveness_score": 0.04,
82            "spoofing": 0.0001976373605
83        }
84    ]
85},
86"timestamp": 1597148814,
87"cached": 0,
88"serverlogid": 1614796453,
89"error_code": 0,
90"error_msg": "SUCCESS"
91}活体阈值参考
请务必在产品侧做好以下条件限制
- 检测的图片为二次采集,即通过相机当场拍摄,确保时间及操作条件的约束;
- 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说明文档,修改参数 | 
人脸识别接口分为V2和V3两个版本,本文档为V3版本接口的说明文档,请确认您在百度云后台获得的是V3版本接口权限,再来阅读本文档。
辨别接口版本的方法是:在百度云后台进入【应用列表】,点击【应用名称】,在【API列表】中可以看到【请求地址】,若请求地址中带有【v3】标识,则您具有的是v3权限,可以阅读本文档;若请求地址中带有【v2】标识,则您具有的是v2权限,应该去阅读v2文档。 如果您对文档内容有任何疑问,可以通过以下几种方式联系我们:
二、在线图片活体检测
能力介绍
接口能力
- 人脸基础信息:包括人脸框位置,人脸空间旋转角度,人脸置信度等信息。
- 人脸质量检测:判断人脸的遮挡、光照、模糊度、完整度等质量信息。可用于判断上传的人脸是否符合标准。
- 基于图片的活体检测:基于单张图片,判断图片中的人脸是否为二次翻拍(举例:如用户A用手机拍摄了一张包含人脸的图片一,用户B翻拍了图片一得到了图片二,并用图片二伪造成用户A去进行识别操作,这种情况普遍发生在金融开户、实名认证等环节)以及是否为合成图攻击。此能力可用于H5场景下的一些人脸采集场景中,增加人脸注册的安全性和真实性。
在线调试
您可以在 API Explorer 中调试该接口,可进行签名验证、查看在线调用的请求内容和返回结果、示例代码的自动生成。
调用方式
请求URL数据格式
向API服务地址使用POST发送请求,必须在URL中带上参数access_token,可通过后台的API Key和Secret Key生成,具体方式请参考“Access Token获取”。
示例代码
1#!/bin/bash
2curl -i -k 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=【百度云应用的AK】&client_secret=【百度云应用的SK】'1<?php
2function request_post($url = '', $param = '') {
3        if (empty($url) || empty($param)) {
4            return false;
5        }
6        
7        $postUrl = $url;
8        $curlPost = $param;
9        $curl = curl_init();//初始化curl
10        curl_setopt($curl, CURLOPT_URL,$postUrl);//抓取指定网页
11        curl_setopt($curl, CURLOPT_HEADER, 0);//设置header
12        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);//要求结果为字符串且输出到屏幕上
13        curl_setopt($curl, CURLOPT_POST, 1);//post提交方式
14        curl_setopt($curl, CURLOPT_POSTFIELDS, $curlPost);
15        $data = curl_exec($curl);//运行curl
16        curl_close($curl);
17        
18        return $data;
19    }
20
21    $url = 'https://aip.baidubce.com/oauth/2.0/token';
22    $post_data['grant_type']       = 'client_credentials';
23    $post_data['client_id']      = '你的 Api Key';
24    $post_data['client_secret'] = '你的 Secret Key';
25    $o = "";
26    foreach ( $post_data as $k => $v ) 
27    {
28        $o.= "$k=" . urlencode( $v ). "&" ;
29    }
30    $post_data = substr($o,0,-1);
31    
32    $res = request_post($url, $post_data);
33
34    var_dump($res);
35
36?>1package com.baidu.ai.aip.auth;
2
3import org.json.JSONObject;
4
5import java.io.BufferedReader;
6import java.io.InputStreamReader;
7import java.net.HttpURLConnection;
8import java.net.URL;
9import java.util.List;
10import java.util.Map;
11
12/**
13 * 获取token类
14 */
15public class AuthService {
16
17    /**
18     * 获取权限token
19     * @return 返回示例:
20     * {
21     * "access_token": "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567",
22     * "expires_in": 2592000
23     * }
24     */
25    public static String getAuth() {
26        // 官网获取的 API Key 更新为你注册的
27        String clientId = "百度云应用的AK";
28        // 官网获取的 Secret Key 更新为你注册的
29        String clientSecret = "百度云应用的SK";
30        return getAuth(clientId, clientSecret);
31    }
32
33    /**
34     * 获取API访问token
35     * 该token有一定的有效期,需要自行管理,当失效时需重新获取.
36     * @param ak - 百度云官网获取的 API Key
37     * @param sk - 百度云官网获取的 Securet Key
38     * @return assess_token 示例:
39     * "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567"
40     */
41    public static String getAuth(String ak, String sk) {
42        // 获取token地址
43        String authHost = "https://aip.baidubce.com/oauth/2.0/token?";
44        String getAccessTokenUrl = authHost
45                // 1. grant_type为固定参数
46                + "grant_type=client_credentials"
47                // 2. 官网获取的 API Key
48                + "&client_id=" + ak
49                // 3. 官网获取的 Secret Key
50                + "&client_secret=" + sk;
51        try {
52            URL realUrl = new URL(getAccessTokenUrl);
53            // 打开和URL之间的连接
54            HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
55            connection.setRequestMethod("GET");
56            connection.connect();
57            // 获取所有响应头字段
58            Map<String, List<String>> map = connection.getHeaderFields();
59            // 遍历所有的响应头字段
60            for (String key : map.keySet()) {
61                System.err.println(key + "--->" + map.get(key));
62            }
63            // 定义 BufferedReader输入流来读取URL的响应
64            BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
65            String result = "";
66            String line;
67            while ((line = in.readLine()) != null) {
68                result += line;
69            }
70            /**
71             * 返回结果示例
72             */
73            System.err.println("result:" + result);
74            JSONObject jsonObject = new JSONObject(result);
75            String access_token = jsonObject.getString("access_token");
76            return access_token;
77        } catch (Exception e) {
78            System.err.printf("获取token失败!");
79            e.printStackTrace(System.err);
80        }
81        return null;
82    }
83
84}1# encoding:utf-8
2import requests 
3
4# client_id 为官网获取的AK, client_secret 为官网获取的SK
5host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=【官网获取的AK】&client_secret=【官网获取的SK】'
6response = requests.get(host)
7if response:
8    print(response.json())1#include <iostream>
2#include <curl/curl.h>
3#include <json/json.h>
4#include "access_token.h"
5// libcurl库下载链接:https://curl.haxx.se/download.html
6// jsoncpp库下载链接:https://github.com/open-source-parsers/jsoncpp/
7// 获取access_token所需要的url
8const std::string access_token_url = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials";
9// 回调函数获取到的access_token存放变量
10// static std::string access_token_result;
11/**
12 * curl发送http请求调用的回调函数,回调函数中对返回的json格式的body进行了解析,解析结果储存在result中
13 * @param 参数定义见libcurl库文档
14 * @return 返回值定义见libcurl库文档
15 */
16static size_t callback(void *ptr, size_t size, size_t nmemb, void *stream) {
17    // 获取到的body存放在ptr中,先将其转换为string格式
18    std::string s((char *) ptr, size * nmemb);
19    // 开始获取json中的access token项目
20    Json::Reader reader;
21    Json::Value root;
22    // 使用boost库解析json
23    reader.parse(s,root);
24    std::string* access_token_result = static_cast<std::string*>(stream);
25    *access_token_result = root["access_token"].asString();
26    return size * nmemb;
27}
28
29/**
30 * 用以获取access_token的函数,使用时需要先在百度云控制台申请相应功能的应用,获得对应的API Key和Secret Key
31 * @param access_token 获取得到的access token,调用函数时需传入该参数
32 * @param AK 应用的API key
33 * @param SK 应用的Secret key
34 * @return 返回0代表获取access token成功,其他返回值代表获取失败
35 */
36int get_access_token(std::string &access_token, const std::string &AK, const std::string &SK) {
37    CURL *curl;
38    CURLcode result_code;
39    int error_code = 0;
40    curl = curl_easy_init();
41    if (curl) {
42        std::string url = access_token_url + "&client_id=" + AK + "&client_secret=" + SK;
43        curl_easy_setopt(curl, CURLOPT_URL, url.data());
44        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
45        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
46        std::string access_token_result;
47        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &access_token_result);
48        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
49        result_code = curl_easy_perform(curl);
50        if (result_code != CURLE_OK) {
51            fprintf(stderr, "curl_easy_perform() failed: %s\n",
52                    curl_easy_strerror(result_code));
53            return 1;
54        }
55        access_token = access_token_result;
56        curl_easy_cleanup(curl);
57        error_code = 0;
58    } else {
59        fprintf(stderr, "curl_easy_init() failed.");
60        error_code = 1;
61    }
62    return error_code;
63}1using System;
2using System.Collections.Generic;
3using System.Net.Http;
4
5namespace com.baidu.ai
6{
7    public static class AccessToken
8
9    {
10        // 调用getAccessToken()获取的 access_token建议根据expires_in 时间 设置缓存
11        // 返回token示例
12        public static String TOKEN = "24.adda70c11b9786206253ddb70affdc46.2592000.1493524354.282335-1234567";
13
14        // 百度云中开通对应服务应用的 API Key 建议开通应用的时候多选服务
15        private static String clientId = "百度云应用的AK";
16        // 百度云中开通对应服务应用的 Secret Key
17        private static String clientSecret = "百度云应用的SK";
18
19        public static String getAccessToken() {
20            String authHost = "https://aip.baidubce.com/oauth/2.0/token";
21            HttpClient client = new HttpClient();
22            List<KeyValuePair<String, String>> paraList = new List<KeyValuePair<string, string>>();
23            paraList.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
24            paraList.Add(new KeyValuePair<string, string>("client_id", clientId));
25            paraList.Add(new KeyValuePair<string, string>("client_secret", clientSecret));
26
27            HttpResponseMessage response = client.PostAsync(authHost, new FormUrlEncodedContent(paraList)).Result;
28            String result = response.Content.ReadAsStringAsync().Result;
29            Console.WriteLine(result);
30            return result;
31        }
32    }
33}1var https = require('https');
2var qs = require('querystring');
3
4const param = qs.stringify({
5    'grant_type': 'client_credentials',
6    'client_id': '您的 Api Key',
7    'client_secret': '您的 Secret Key'
8});
9
10https.get(
11    {
12        hostname: 'aip.baidubce.com',
13        path: '/oauth/2.0/token?' + param,
14        agent: false
15    },
16    function (res) {
17        // 在标准输出中查看运行结果
18        res.pipe(process.stdout);
19    }
20);注意:
access_token的有效期为30天,切记需要每30天进行定期更换,或者每次请求都拉取新token;
例如此接口,使用HTTPS POST发送:
1https://aip.baidubce.com/rest/2.0/face/v1/merge?access_token=24.f9ba9c5341b67688ab4added8bc91dec.2592000.1485570332.282335-8574074POST中Body的参数,按照下方请求参数说明选择即可。
提示:如果您为百度云老用户,正在使用其他非AI的服务,可以参考百度云AKSK鉴权方式发送请求,虽然请求方式和鉴权方法和本文所介绍的不同,但请求参数和返回结果一致。
请求说明
注意事项:
- 请求体格式化:Content-Type为application/json,通过json格式化请求体。
- Base64编码:请求的图片需经过Base64编码,图片的base64编码指将图片数据编码成一串字符串,使用该字符串代替图像地址。您可以首先得到图片的二进制,然后用Base64格式编码即可。需要注意的是,图片的base64编码是不包含图片头的,如data:image/jpg;base64,
- 图片格式:现支持PNG、JPG、JPEG、BMP,不支持GIF图片
- 人脸识别接口分为V2和V3两个版本,本文档为V3版本接口的说明文档,请确认您在百度云后台获得的是V3版本接口权限,再来阅读本文档。
辨别接口版本的方法是:在百度云后台进入【应用列表】,点击【应用名称】,在【API列表】中可以看到【请求地址】,若请求地址中带有【v3】标识,则您具有的是v3权限,可以阅读本文档;若请求地址中带有【v2】标识,则您具有的是v2权限,应该去阅读v2文档。
请求示例
HTTP方法:POST	
请求URL: https://aip.baidubce.com/rest/2.0/face/v3/faceverify
URL参数:
| 参数 | 值 | 
|---|---|
| access_token | 通过API Key和Secret Key获取的access_token,参考“Access Token获取” | 
Header:
| 参数 | 值 | 
|---|---|
| Content-Type | application/json | 
Body中放置请求参数,参数详情如下:
请求参数
| 参数 | 是否必选 | 类型 | 说明 | 
|---|---|---|---|
| image | 是 | string | 图片信息(总数据大小应小于10M),图片上传方式根据image_type来判断; 可以上传同一个用户的1张、3张或8张图片来进行活体判断 注: (1)后端会选择每组照片中的最高分数作为整体分数。 图片通过json格式上传,格式参考表格下方示例 (2)支持1、3、8张图片输入进行计算,请求格式为数组格式 | 
| image_type | 是 | string | 图片类型 BASE64:(推荐)图片的base64值,base64编码后的图片数据,需urlencode,编码后的图片大小不超过2M;FACE_TOKEN: 人脸图片的唯一标识,调用人脸检测接口时,会为每个人脸图片赋予一个唯一的FACE_TOKEN,同一张图片多次检测得到的FACE_TOKEN是同一个。 | 
| face_field | 否 | string | 包括age,beauty,expression,face_shape,gender,glasses,landmark,quality,face_type,spoofing信息,逗号分隔,默认只返回face_token、活体数、人脸框、概率和旋转角度 | 
| option | 否 | string | 场景信息,程序会视不同的场景选用相对应的模型。当前支持的场景有COMMON(通用场景),GATE(闸机场景),默认使用COMMON | 
说明:图片的上传使用json格式,发送内容为数组,(即 [{XXXXX},{XXXXX}] 这种格式)具体如下:
JSON1[ 2 { 3 "image": "sfasq35sadvsvqwr5q...", 4 "image_type": "BASE64", 5 "face_field": "age,beauty,spoofing", 6 "option": "COMMON" 7 }, 8 { 9 "image": "http://xxx.baidu.com/image1.png", 10 "image_type": "URL", 11 "face_field": "age,beauty,spoofing", 12 "option": "COMMON" 13 }, 14 { 15 "image": "9f30d19f86f89f2f07ce88b69557061a", 16 "image_type": "FACE_TOKEN", 17 "face_field": "age,beauty,spoofing", 18 "option": "COMMON" 19 } 20]
请求示例
提示一:使用示例代码前,请记得替换其中的示例Token、图片地址或Base64信息。
提示二:部分语言依赖的类或库,请在代码注释中查看下载地址。
1在线活体检测
2curl -i -k 'https://aip.baidubce.com/rest/2.0/face/v3/faceverify?access_token=【调用鉴权接口获取的token】' --data '[{"image":"sfasq35sadvsvqwr5q...","image_type":"BASE64","face_field":"age,beauty,expression"},{"image":"http://xxx.baidu.com/image1.png","image_type":"URL","face_field":"age,beauty"}]' -H 'Content-Type:application/json; charset=UTF-8'1<?php
2/**
3 * 发起http post请求(REST API), 并获取REST请求的结果
4 * @param string $url
5 * @param string $param
6 * @return - http response body if succeeds, else false.
7 */
8function request_post($url = '', $param = '')
9{
10    if (empty($url) || empty($param)) {
11        return false;
12    }
13
14    $postUrl = $url;
15    $curlPost = $param;
16    // 初始化curl
17    $curl = curl_init();
18    curl_setopt($curl, CURLOPT_URL, $postUrl);
19    curl_setopt($curl, CURLOPT_HEADER, 0);
20    // 要求结果为字符串且输出到屏幕上
21    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
22    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
23    // post提交方式
24    curl_setopt($curl, CURLOPT_POST, 1);
25    curl_setopt($curl, CURLOPT_POSTFIELDS, $curlPost);
26    // 运行curl
27    $data = curl_exec($curl);
28    curl_close($curl);
29
30    return $data;
31}
32
33$token = '[调用鉴权接口获取的token]';
34$url = 'https://aip.baidubce.com/rest/2.0/face/v3/faceverify?access_token=' . $token;
35$bodys = "[{\"image\":\"sfasq35sadvsvqwr5q...\",\"image_type\":\"BASE64\",\"face_field\":\"age,beauty,expression\"},{\"image\":\"http://xxx.baidu.com/image1.png\",\"image_type\":\"URL\",\"face_field\":\"age,beauty\"}]"
36$res = request_post($url, $bodys);
37
38var_dump($res);1package com.baidu.ai.aip;
2
3import com.baidu.ai.aip.utils.HttpUtil;
4import com.baidu.ai.aip.utils.GsonUtils;
5
6import java.util.*;
7
8/**
9* 在线活体检测
10*/
11public class FaceVerify {
12
13    /**
14    * 重要提示代码中所需工具类
15    * FileUtil,Base64Util,HttpUtil,GsonUtils请从
16    * https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72
17    * https://ai.baidu.com/file/C8D81F3301E24D2892968F09AE1AD6E2
18    * https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3
19    * https://ai.baidu.com/file/470B3ACCA3FE43788B5A963BF0B625F3
20    * 下载
21    */
22    public static String faceVerify() {
23        // 请求url
24        String url = "https://aip.baidubce.com/rest/2.0/face/v3/faceverify";
25        try {
26
27            String param = GsonUtils.toJson(map);
28
29            // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。
30            String accessToken = "[调用鉴权接口获取的token]";
31
32            String result = HttpUtil.post(url, accessToken, "application/json", param);
33            System.out.println(result);
34            return result;
35        } catch (Exception e) {
36            e.printStackTrace();
37        }
38        return null;
39    }
40
41    public static void main(String[] args) {
42        FaceVerify.faceVerify();
43    }
44}1# encoding:utf-8
2
3import requests
4
5'''
6在线活体检测
7'''
8
9request_url = "https://aip.baidubce.com/rest/2.0/face/v3/faceverify"
10
11params = "[{\"image\":\"sfasq35sadvsvqwr5q...\",\"image_type\":\"BASE64\",\"face_field\":\"age,beauty,expression\"},{\"image\":\"http://xxx.baidu.com/image1.png\",\"image_type\":\"URL\",\"face_field\":\"age,beauty\"}]"
12access_token = '[调用鉴权接口获取的token]'
13request_url = request_url + "?access_token=" + access_token
14headers = {'content-type': 'application/json'}
15response = requests.post(request_url, data=params, headers=headers)
16if response:
17    print (response.json())1#include <iostream>
2#include <curl/curl.h>
3
4// libcurl库下载链接:https://curl.haxx.se/download.html
5// jsoncpp库下载链接:https://github.com/open-source-parsers/jsoncpp/
6const static std::string request_url = "https://aip.baidubce.com/rest/2.0/face/v3/faceverify";
7static std::string faceVerify_result;
8/**
9 * curl发送http请求调用的回调函数,回调函数中对返回的json格式的body进行了解析,解析结果储存在全局的静态变量当中
10 * @param 参数定义见libcurl文档
11 * @return 返回值定义见libcurl文档
12 */
13static size_t callback(void *ptr, size_t size, size_t nmemb, void *stream) {
14    // 获取到的body存放在ptr中,先将其转换为string格式
15    faceVerify_result = std::string((char *) ptr, size * nmemb);
16    return size * nmemb;
17}
18/**
19 * 在线活体检测
20 * @return 调用成功返回0,发生错误返回其他错误码
21 */
22int faceVerify(std::string &json_result, const std::string &access_token) {
23    std::string url = request_url + "?access_token=" + access_token;
24    CURL *curl = NULL;
25    CURLcode result_code;
26    int is_success;
27    curl = curl_easy_init();
28    if (curl) {
29        curl_easy_setopt(curl, CURLOPT_URL, url.data());
30        curl_easy_setopt(curl, CURLOPT_POST, 1);
31        curl_slist *headers = NULL;
32        headers = curl_slist_append(headers, "Content-Type:application/json;charset=UTF-8");
33        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
34        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "[{\"image\":\"sfasq35sadvsvqwr5q...\",\"image_type\":\"BASE64\",\"face_field\":\"age,beauty,expression\"},{\"image\":\"http://xxx.baidu.com/image1.png\",\"image_type\":\"URL\",\"face_field\":\"age,beauty\"}]");
35        result_code = curl_easy_perform(curl);
36        if (result_code != CURLE_OK) {
37            fprintf(stderr, "curl_easy_perform() failed: %s\n",
38                    curl_easy_strerror(result_code));
39            is_success = 1;
40            return is_success;
41        }
42        json_result = faceVerify_result;
43        curl_easy_cleanup(curl);
44        is_success = 0;
45    } else {
46        fprintf(stderr, "curl_easy_init() failed.");
47        is_success = 1;
48    }
49    return is_success;
50}1using System;
2using System.IO;
3using System.Net;
4using System.Text;
5using System.Web;
6
7namespace com.baidu.ai
8{
9    public class FaceVerify
10    {
11        // 在线活体检测
12        public static string faceVerify()
13        {
14            string token = "[调用鉴权接口获取的token]";
15            string host = "https://aip.baidubce.com/rest/2.0/face/v3/faceverify?access_token=" + token;
16            Encoding encoding = Encoding.Default;
17            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(host);
18            request.Method = "post";
19            request.KeepAlive = true;
20            String str = "[{\"image\":\"sfasq35sadvsvqwr5q...\",\"image_type\":\"BASE64\",\"face_field\":\"age,beauty,expression\"},{\"image\":\"http://xxx.baidu.com/image1.png\",\"image_type\":\"URL\",\"face_field\":\"age,beauty\"}]";
21            byte[] buffer = encoding.GetBytes(str);
22            request.ContentLength = buffer.Length;
23            request.GetRequestStream().Write(buffer, 0, buffer.Length);
24            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
25            StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.Default);
26            string result = reader.ReadToEnd();
27            Console.WriteLine("在线活体检测:");
28            Console.WriteLine(result);
29            return result;
30        }
31    }
32}返回说明
返回参数
| 参数 | 是否必须 | 类型 | 说明 | 
|---|---|---|---|
| face_liveness | 是 | float | 活体分数值 | 
| thresholds | 是 | array | 由服务端返回最新的阈值数据(随着模型的优化,阈值可能会变化),将此参数与返回的face_liveness进行比较,可以作为活体判断的依据。 frr_1e-4:万分之一误识率的阈值;frr_1e-3:千分之一误识率的阈值;frr_1e-2:百分之一误识率的阈值。误识率越低,准确率越高,相应的拒绝率也越高 | 
| face_list | 是 | array | 每张图片的详细信息描述,如果只上传一张图片,则只返回一个结果。 | 
| +face_token | 是 | string | 人脸图片的唯一标识 | 
| +location | 是 | array | 人脸在图片中的位置 | 
| ++left | 是 | double | 人脸区域离左边界的距离 | 
| ++top | 是 | double | 人脸区域离上边界的距离 | 
| ++width | 是 | double | 人脸区域的宽度 | 
| ++height | 是 | double | 人脸区域的高度 | 
| ++rotation | 是 | int64 | 人脸框相对于竖直方向的顺时针旋转角,[-180,180] | 
| +face_probability | 是 | double | 人脸置信度,范围【0~1】,代表这是一张人脸的概率,0最小、1最大。 | 
| +angel | 是 | array | 人脸旋转角度参数 | 
| ++yaw | 是 | double | 三维旋转之左右旋转角[-90(左), 90(右)] | 
| ++pitch | 是 | double | 三维旋转之俯仰角度[-90(上), 90(下)] | 
| ++roll | 是 | double | 平面内旋转角[-180(逆时针), 180(顺时针)] | 
| +age | 否 | double | 年龄 ,当face_field包含age时返回 | 
| +beauty | 否 | int64 | 美丑打分,范围0-100,越大表示越美。当face_fields包含beauty时返回 | 
| +expression | 否 | array | 表情,当 face_field包含expression时返回 | 
| ++type | 否 | string | none:不笑;smile:微笑;laugh:大笑 | 
| ++probability | 否 | double | 表情置信度,范围【0~1】,0最小、1最大。 | 
| +face_shape | 否 | array | 脸型,当face_field包含face_shape时返回 | 
| ++type | 否 | double | square: 正方形 triangle:三角形 oval: 椭圆 heart: 心形 round: 圆形 | 
| ++probability | 否 | double | 置信度,范围【0~1】,代表这是人脸形状判断正确的概率,0最小、1最大。 | 
| +gender | 否 | array | 性别,face_field包含gender时返回 | 
| ++type | 否 | string | male:男性 female:女性 | 
| ++probability | 否 | double | 性别置信度,范围【0~1】,0代表概率最小、1代表最大。 | 
| +glasses | 否 | array | 是否带眼镜,face_field包含glasses时返回 | 
| ++type | 否 | string | none:无眼镜,common:普通眼镜,sun:墨镜 | 
| ++probability | 否 | double | 眼镜置信度,范围【0~1】,0代表概率最小、1代表最大。 | 
| +face_type | 否 | array | 真实人脸/卡通人脸 face_field包含face_type时返回 | 
| ++type | 否 | string | human: 真实人脸 cartoon: 卡通人脸 | 
| ++probability | 否 | double | 人脸类型判断正确的置信度,范围【0~1】,0代表概率最小、1代表最大。 | 
| +landmark | 否 | array | 4个关键点位置,左眼中心、右眼中心、鼻尖、嘴中心。face_field包含landmark时返回 | 
| +landmark72 | 否 | array | 72个特征点位置 face_field包含landmark时返回 | 
| +quality | 否 | array | 人脸质量信息。face_field包含quality时返回 | 
| ++occlusion | 否 | array | 人脸各部分遮挡的概率,范围[0~1],0表示完整,1表示不完整 | 
| +++left_eye | 否 | double | 左眼遮挡比例,[0-1] , 1表示完全遮挡 | 
| +++right_eye | 否 | double | 右眼遮挡比例,[0-1] , 1表示完全遮挡 | 
| +++nose | 否 | double | 鼻子遮挡比例,[0-1] , 1表示完全遮挡 | 
| +++mouth | 否 | double | 嘴巴遮挡比例,[0-1] , 1表示完全遮挡 | 
| +++left_cheek | 否 | double | 左脸颊遮挡比例,[0-1] , 1表示完全遮挡 | 
| +++right_cheek | 否 | double | 右脸颊遮挡比例,[0-1] , 1表示完全遮挡 | 
| +++chin | 否 | double | 下巴遮挡比例,,[0-1] , 1表示完全遮挡 | 
| ++blur | 否 | double | 人脸模糊程度,范围[0~1],0表示清晰,1表示模糊 | 
| ++illumination | 否 | double | 取值范围在[0~255], 表示脸部区域的光照程度 越大表示光照越好 | 
| ++completeness | 否 | int64 | 人脸完整度,0或1, 0为人脸溢出图像边界,1为人脸都在图像边界内 | 
| +spoofing | 否 | double | 合成图打分 判断图片是否为合成图 face_field包含时返回spoofing | 
返回示例
1{
2    "error_code": 0,
3    "error_msg": "SUCCESS",
4    "log_id": 9999201750012,
5    "timestamp": 1587021157,
6    "cached": 0,
7    "result": {
8        "thresholds": {
9            "frr_1e-4": 0.05,
10            "frr_1e-3": 0.3,
11            "frr_1e-2": 0.9
12        },
13        "face_liveness": 1,
14        "face_list": [
15            {
16                "face_token": "6e6880584e9ad6d22e309da37ed72b78",
17                "location": {
18                    "left": 60.21,
19                    "top": 134.93,
20                    "width": 162,
21                    "height": 164,
22                    "rotation": -4
23                },
24                "face_probability": 1,
25                "angle": {
26                    "yaw": -0.9,
27                    "pitch": 12.87,
28                    "roll": -5.36
29                },
30                "liveness": {
31                    "livemapscore": 1
32                },
33                "spoofing": 0.0002664364583
34            }
35        ]
36    }
37}活体阈值参考
请务必在产品侧做好以下条件限制
- 检测的图片为二次采集,即通过相机当场拍摄,确保时间及操作条件的约束;
- SDK输出的多帧情况,只要这些帧中,任何一张通过了阈值,即可判断为活体,建议可用三帧情况;
- 推荐分值采用99.5%
关于活体检测faceliveness的判断阈值选择,可参考以下数值信息(金融保险等对安全性要求较高的业务可适当调高活体阈值,如:0.5):
| 阈值(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):高于此数值,则可判断为活体。 
合成图阈值参考
新推出合成图检测能力,在face_field字段中增加spoofing参数,进行判断,若spoofing分值高于合成图推荐阈值,则可判断为合成图攻击;此参数在face_liveness基础上进行合成图判断
。
关于合成图检测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):高于此数值,则可判断为是合成图攻击。
质量检测参考
| 指标 | 字段与解释 | 推荐数值界限 | 
|---|---|---|
| 遮挡范围 | occlusion,取值范围[0~1],0为无遮挡,1是完全遮挡 含有多个具体子字段,表示脸部多个部位 通常用作判断头发、墨镜、口罩等遮挡 | left_eye : 0.6, #左眼被遮挡的阈值 right_eye : 0.6, #右眼被遮挡的阈值 nose : 0.7, #鼻子被遮挡的阈值 mouth : 0.7, #嘴巴被遮挡的阈值 left_check : 0.8, #左脸颊被遮挡的阈值 right_check : 0.8, #右脸颊被遮挡的阈值 chin_contour : 0.6, #下巴被遮挡阈值 | 
| 模糊度范围 | blur,取值范围[0~1],0是最清晰,1是最模糊 | 小于0.7 | 
| 光照范围 | illumination,取值范围[0~255] 脸部光照的灰度值,0表示光照不好 以及对应客户端SDK中,YUV的Y分量 | 大于40 | 
| 姿态角度 | Pitch:三维旋转之俯仰角度[-90(上), 90(下)] Roll:平面内旋转角[-180(逆时针), 180(顺时针)] Yaw:三维旋转之左右旋转角[-90(左), 90(右)] | 分别小于20度 | 
| 人脸完整度 | completeness(0或1),0为人脸溢出图像边界,1为人脸都在图像边界内 | 视业务逻辑判断 | 
| 人脸大小 | 人脸部分的大小 建议长宽像素值范围:80*80~200*200 | 人脸部分不小于100*100像素 | 
人脸空间姿态角参考
姿态角分为Pitch、Roll、Yaw,用于表示人脸在空间三维坐标系内的角度,常用于判断识别角度的界限值。
各角度阈值如下:
1Pitch:三维旋转之俯仰角度,范围:[-90(上), 90(下)],推荐俯仰角绝对值不大于20度;
2Roll:平面内旋转角,范围:[-180(逆时针), 180(顺时针)],推荐旋转角绝对值不大于20度;
3Yaw:三维旋转之左右旋转角,范围:[-90(左), 90(右)],推荐旋转角绝对值不大于20度;各角度范围示意图如下:
从姿态角度来看,这三个值的绝对值越小越好,这样代表人脸足够正视前方,最利于实际注册/识别使用。
错误码
请参考人脸识别错误码
