文档简介:
本文档为您介绍了纯服务端的接入流程。
一、 准备工作
在正式集成前,需要做一些准备工作,完成一些账号、应用及配置,具体如下:
1.1 注册成为开发者
- STEP1:点击百度AI 开放平台导航右侧的控制台,页面跳转到百度云登录界面,登录完毕后,将会进入到百度云后台,点击「控制台」进入百度云控制台页面;您也可以在官网直接点击免费试用,登录完毕后将自动进入到百度云控制台。
- STEP2:使用百度账号完成登录,如您还未持有百度账户,可以点击此处注册百度账户。
- STEP3:进入百度云欢迎页面,填写企业和个人基本信息,注册完毕,至此成为开发者。(如您之前已经是百度云用户或百度开发者中心用户,STEP3 可略过。)
- STEP4:进入百度云控制台,找到人工智能相关服务面板。
- STEP5:点击进入「人脸识别」模块。
1.2 创建应用
创建好账号后,在正式调用AI 能力之前,需要您创建一下应用,这个是调用服务的基础能力单元。 选择「人脸识别」服务,首先见到此服务的控制台概览页,点击「创建应用」,即可进入应用创建界面,如下图所示:
如上图所示,点击「创建应用」,即可进入应用创建界面,如下图所示:
注意:您需要创建一个应用,分别做以下作用:
- 应用一:勾选身份证识别能力,绑定iOS OCR、Android OCR包名,用于使用OCR能力。
- 应用二:此应用默认会沟通人脸实名认证能力,用于使用身份验证判断;
1.3 获取秘钥
在您创建完毕应用后,平台将会分配给您此应用的相关凭证,主要为AppID、API Key、Secret Key,以上三个信息是您应用实际开发的主要凭证,每个应用之间各不相同,请您妥善保管。如上图所示。该AK/SK用于调用在线API 如:身份验证。注:开发中请注意区分多份AK/SK(API Key、Secret Key)
1.4 生成token
刚才所创建的应用在调用开放平台API 之前,首先需要获取Access Token(用户身份验证和授权的凭证)您需要使用创建应用所分配到的AppID、API Key 及Secret Key,进行Access Token 的生成,方法详见 Access Token 获取,我们为您准备了几种常见语言的请求示例代码。
注:Access Token 的有效期为30天(以秒为单位),请您集成时注意在程序中定期请求新的token,或每次请求都获取一次token。
1.5 SDK License 配置
- OCR身份证识别SDK License:此License封装了aksk,用于更方便地调用接口。请在刚才创建的两个身份证应用中,点击「应用名称」,进入应用详情页面,找到如下图所示内容:
点击button,下载此license文件,名称都为aip.license(分别用于iOS和安卓),稍后集成需要使用。
- 人脸SDK License :此license用于SDK离线功能使用,在您的申请人脸SDK的后台页面,下载两个端的license,如下图所示:
用于接下来集成使用,不过我们为您提供了自动化配置脚本,如下图所示:
强烈推荐您在下载核身示例工程的同时,直接下载已经配置好授权信息的版本。
二、集成逻辑
2.1 集成流程
下面我们将以更为复杂的有源身份验证作为范例讲解:
如上图所示,集成逻辑可以概括为三个核心步骤:
- OCR SDK获取身份证信息,本地输出。
- 人脸SDK获取活体检测图片,本地输出。
- 将姓名、身份证号、人脸图像推送到您的server端,从server端先调用在线身份验证接口,得到结果。
如何判断业务是否终止,主要分为五个节点:
- 身份证不合规:在身份证识别的返回参数中,有如下字段:如判断身份证信息为非正常身份证,可提示用户,并中断验证流程;
- 人脸SDK本地有动作活体检测,如果用户无法完成指定动作,也无法继续进行;
- 人脸图像质量较低(如选择了此项),流程中止;
- 人脸图像经在线活体检测判断分数过低,流程中止;
- 前三步都完成,但是人脸实名认证分数过低,也可提示核身验证失败。
2.2 服务中转
SDK获取人脸过程中的处理,完全无需联网,但人脸对比、人脸查找、人脸属性分析能力需要调用API使用。产品策略方面,因API使用需要使用在线鉴权token,为token的安全起见,建议将人脸推送到server端再调用API接口。
对安全有进一步需求的话,为防止人脸传输过程中被篡改,可对SDK本地输出的人脸图像做加密处理,在server端进行相应解密操作,进一步增强安全性。
2.3 阈值选择
v3版本的身份验证接口中,对于质量控制、活体控制的阈值设定,都简化为LOW、NORMAL、HIGH三个级别,您只需指定等级作为阈值即可,无需设定具体的数值阈值。
脸部遮挡指标(质量校验)
每一项详细判断项,取值范围[0~1],0为无遮挡,1是完全遮挡
控制度 | left_eye | right_eye | nose | mouth | left_cheek | right_cheek | chin_contour |
---|---|---|---|---|---|---|---|
LOW | 0.8 | 0.8 | 0.8 | 0.8 | 0.8 | 0.8 | 0.8 |
NORMAL | 0.6 | 0.6 | 0.6 | 0.6 | 0.6 | 0.6 | 0.6 |
HIGH | 0.2 | 0.2 | 0.2 | 0.2 | 0.2 | 0.2 | 0.2 |
光照、模糊度、完整度指标(质量校验)
- illumination:取值范围[0~255],脸部光照的灰度值,0表示光照不好。以及对应客户端SDK中,YUV的Y分量。
- blurdegree:取值范围[0~1],0是最清晰,1是最模糊。
- completeness:0或1,0为人脸溢出图像边界,1为人脸都在图像边界内。
控制度 | illumination | blurdegree | completeness |
---|---|---|---|
LOW | 20 | 0.8 | 0 |
NORMAL | 40 | 0.6 | 0 |
HIGH | 100 | 0.2 | 1 |
活体检测阈值指标
- 误拒率(FRR):如0.5%,指1000次真人请求,会有5次因为活体分数低于阈值被错误拒绝。
控制度 | 对应阈值 | 说明 |
---|---|---|
LOW | 0.05 | 万分之一活体误拒率 |
NORMAL | 0.3 | 千分之一活体误拒率 |
HIGH | 0.9 | 百分之一活体误拒率 |
身份验证对比分值的阈值选择
阈值分数 | 误识率 | 识别率 |
---|---|---|
60 | 0.781615% | 99.550128% |
70 | 0.096534% | 98.307626% |
78 | 0.015570%(万分之一) | 95.672664% |
80 | 0.009342%(低于万分之一) | 94.323051% |
注:识别率与误识率成正比:识别率越高,误识率越高;识别率降低,误识率也降低;
三、 IOS集成
3.1 OCR身份证识别集成
把下载下来的License文件(文件名:aip.license),添加到项目里面,无需更改文件名称,然后在AppDelegate添加以下代码引用进去。
在FaceParameterConfig.h里面设置下载下来的License文件的名字和后缀。
通过API调用ViewController进行身份证扫描
详细调用文档,请参考 OCR-iOS-SDK文档
3.2 人脸SDK集成
1、打开或者新建一个项目。
2、右键点击项目,会出现一个添加菜单,在菜单中选择『Add Files to“此处是你的项目名字”…… 』,如下图所示:
3、在添加文件弹出框里面选择申请到的license和SDK添加进来。如下图:
注意:license为百度官方提供,刚才在后台下载的文件(文件名称:idl-license.face-ios)
SDK包含下面三个文件:
- IDLFaceSDK.framework
- com.baidu.idl.face.faceSDK.bundle
- com.baidu.idl.face.model.bundle
4、确认下 Bundle Identifier 是否是申请license时填报的那一个.
5、注意:license 和 Bundle Identifier 为一一对应关系,填错了会导致SDK不可用.
6、 FACE_LICENSE_ID这个参数填写百度官方给的LicenseID
在 FaceParameterConfig.h 文件中填写下面三项。
7、选择链接C++标准库。
8、如果没有使用pod管理第三方库的话,请在Build Setting Linking Other Linker Flags 上面加入 –ObjC选项。如果用了pod请忽略,因为pod会自动添加上。
以下为示例工程调用身份验证的代码片段:
[[NetAccessModel sharedInstance] verifyFaceAndIDCard:self.nameTextField.text idNumber:self.identityCardTextField.
text imageStr:imageStr completion:^(NSError *error, id resultObject) { if (error == nil) { NSDictionary* dict
= [NSJSONSerialization JSONObjectWithData:resultObject options:NSJSONReadingAllowFragments error:nil];
NSLog(@"dict = %@",dict); dispatch_async(dispatch_get_main_queue(), ^{ FaceResultType type = FaceResultTypeFail;
NSString* tip = @"验证分数"; NSString* scoreStr = @""; NSString* showStr = nil; if ([dict[@"error_code"] intValue]
== 0) { CGFloat score = [dict[@"result"][@"score"] floatValue]; scoreStr = [NSString stringWithFormat:@"%.4f",score];
if (score > 80) { type = FaceResultTypeSuccess; } } else { tip = [NSString stringWithFormat:@"错误码:%@\n错误信息:
%@",dict[@"error_code"],dict[@"error_msg"]]; } NSMutableDictionary* resultDict = [@{} mutableCopy]; resultDict[@"type"]
= @(type); resultDict[@"tip"] = tip; resultDict[@"score"] = scoreStr; resultDict[@"showStr"] = showStr;
[weakSelf performSegueWithIdentifier:@"Affirm2Result" sender:resultDict]; }); } else { NSLog(@"网络请求失败"); } }];
接下来基于接口返回的分数进行业务判断即可,详细业务流程详见2.2.1所示。
四、安卓集成
4.1 OCR身份证识别集成
- 把申请的license(aip.license)放到到项目中assets目录中
- 修改app的build.gradle和AndroidMainest.xml包名为申请时填入的包名
- 拷贝ocr-ui到您的工程中
接下来调用具体请看Demo中的IdCardActivity
1、初始化OCR SDK
2、调用api进行身份证扫描
3、调用api进行身份证识别
4、获得身份证号码和姓名后进入人脸活体验证步骤
详细调用文档,请参考 OCR-Android-SDK文档
4.2 人脸SDK集成
1、授权参数
a、把申请的license(idl-license.face-android")放到到项目中assets目录中
b、修改 Config 类中的参数
public class Config { // 为了apiKey,secretKey为您调用百度人脸在线接口的,如注册,比对等。 // 为了的安全,建议放在您的服务端
,端把人脸传给服务器,在服务端端 // license为调用sdk的人脸检测功能使用,人脸识别 = 人脸检测(SDK功能)
+ 人脸比对(服务端API) public static String apiKey = "替换为你的apiKey(ak)"; public static String secretKey
= "替换为你的secretKey(sk)"; public static String licenseID = "替换为你的licenseID,后台SDK管理界面中,
已经生成的licenseID,如:test-face-android"; public static String licenseFileName = "替换为你的license文件";
/* * 人脸识别 接口 https://aip.baidubce.com/rest/2.0/face/v3/search *
人脸注册 接口 https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add */
public static String groupID = "替换为你的人脸组groupID"; }
c、配置签名(申请license时的md5为打包签名的文件,所以必须用申请license的签名文件)
app->build.gradle->android->signingConfigs
signingConfigs {
def password = "替换为签名密码"
def alias = "替换为签名别名"
def filePath = "替换为签名文件路径" //如 ../facesharp.jks//签名文件路径
debug {
keyAlias alias
keyPassword password
storeFile file(filePath)
storePassword(password)
}
release {
keyAlias alias
keyPassword password
storeFile file(filePath)
storePassword(password)
}
}
d、修改包名 app->build.gradle->android->defaultConfig ->您申请license时填的包名
2、继承 FaceLivenessActivity,初始人脸SDK
/** * 初始化SDK */ private void initLib() { // 为了android和ios 区分授权,appId=appname_face_android ,
其中appname为申请sdk时的应用名 // 应用上下文 // 申请License取得的APPID // assets目录下License
文件名 FaceSDKManager.getInstance().init(this, Config.licenseID, Config.licenseFileName); setFaceConfig(); }
3、设置参数,如不设置,将使用默认值
private void setFaceConfig() { FaceTracker tracker = FaceSDKManager.getInstance().getFaceTracker(this);
// SDK初始化已经设置完默认参数(推荐参数),您也根据实际需求进行数值调整 // 模糊度范围 (0-1) 推荐小于0.7
tracker.set_blur_thr(FaceEnvironment.VALUE_BLURNESS); // 光照范围 (0-1) 推荐大于40
tracker.set_illum_thr(FaceEnvironment.VALUE_BRIGHTNESS); // 裁剪人脸大小
tracker.set_cropFaceSize(FaceEnvironment.VALUE_CROP_FACE_SIZE); // 人脸yaw,pitch,row 角度,
范围(-45,45),推荐-15-15 tracker.set_eulur_angle_thr(FaceEnvironment.VALUE_HEAD_PITCH,
FaceEnvironment.VALUE_HEAD_ROLL, FaceEnvironment.VALUE_HEAD_YAW); // 最小检测人脸
(在图片人脸能够被检测到最小值)80-200, 越小越耗性能,推荐120-200 tracker.set_min_face_size(FaceEnvironment.VALUE_MIN_FACE_SIZE)
; // tracker.set_notFace_thr(FaceEnvironment.VALUE_NOT_FACE_THRESHOLD); // 人脸遮挡范围 (0-1)
推荐小于0.5 tracker.set_occlu_thr(FaceEnvironment.VALUE_OCCLUSION); // 是否进行质量检测 tracker.set_isCheckQuality(true);
// 是否进行活体校验 tracker.set_isVerifyLive(false); }
4、开始进行活体检测
5、获取活体检测结果
@Override public void onLivenessCompletion(FaceStatusEnum status, String message, HashMap<String, String>
base64ImageMap) { super.onLivenessCompletion(status, message, base64ImageMap); if (status == FaceStatusEnum.OK
&& mIsCompletion) { // Toast.makeText(this, "活体检测成功", Toast.LENGTH_SHORT).show(); saveImage(base64ImageMap);
alertText("检测结果", "活体检测成功"); } else if (status == FaceStatusEnum.Error_DetectTimeout || status
== FaceStatusEnum.Error_LivenessTimeout || status == FaceStatusEnum.Error_Timeout) { // Toast.makeText(this,
"活体检测采集超时", Toast.LENGTH_SHORT).show(); alertText("检测结果", "活体检测采集超时"); } }
6、保持活体检测得到图片,以便进行身份核验接口调用
private void saveImage(HashMap<String, String> imageMap) { // imageMap 里保存了最佳人脸和各个动作的图片,若对安全要求比较高,
可以传多张图片进行在线活体,目前只用最佳人脸进行了在线活体检测 String bestimageBase64 = imageMap.get("bestImage0");
Bitmap bmp = base64ToBitmap(bestimageBase64); // Bitmap newBmp = detect(bmp); // if (newBmp == null) { // newBmp
= bmp; // } // 如果觉的在线校验慢,可以压缩图片的分辨率,目前没有压缩分辨率,压缩质量置80,在neuxs5上大概30k,
后面版本我们将截出人脸部分,大小应该小于10k try { File file = File.createTempFile("face", ".jpg");
FileOutputStream outputStream = new FileOutputStream(file); bmp.compress(Bitmap.CompressFormat.JPEG, 80, outputStream)
; outputStream.close(); bestImagePath = file.getAbsolutePath(); } catch (IOException e) { e.printStackTrace(); } }
7、获取token,用于调用接口
注意:通过ak,sk获取,为了防止ak,sk泄露,建议把ak/sk放在服务端,移动端通过服务端去拉取token
private void initAccessToken() { APIService.getInstance().init(this); // 用ak,sk获取token, 调用在线api,
如:注册、识别等。为了ak、sk安全,建议放您的服务器, APIService.getInstance().initAccessTokenWithAkSk
new OnResultListener<AccessToken>() { @Override public void onResult(AccessToken result) { Log.i("wtf", "AccessToken->"
+ result.getAccessToken()); } @Override public void onError(FaceException error) { Log.e("xx", "AccessTokenError:" + error)
; error.printStackTrace(); } }, Config.apiKey, Config.secretKey); }
8、根据离线活体得到的人脸,进行在线活体检测和人脸实名认证(参见FaceOnlineVerifyActivity)
如果参选择 quality_control 和 liveness_control 这两个参数,则检测顺序将会变为: 图片质量检测-> 活体检测 -> 权威数据源人脸实名认证,其中前两个环节有任意一个条件不通过,则检测流程流程终止,返回信息中会说明不符合的详细内容;如果前两个检测条件全部验证通过,则会执行人脸实名认证接口请求,返回内容包含对比分数。
提示:为了安全及维护成本考虑,我们建议您将SDK获取的人脸图像,推送到服务器端,由服务器端进行API调用,并将结果返回给客户端APP
private void policeVerify(String filePath) { if (TextUtils.isEmpty(filePath) || waitAccesstoken)
{ return; } File file = new File(filePath); if (!file.exists()) { return; } displayTip(resultTipTV,
"权威数据源身份核实中..."); APIService.getInstance().policeVerify(username, idnumber, filePath, new OnResultListener
<LivenessVsIdcardResult>() { @Override public void onResult(LivenessVsIdcardResult result) { if (result != null && result.getScore()
>= 80) { delete(); displayTip(resultTipTV, "核身成功"); displayTip(scoreTV, "人脸实名认证分数:" + result.getScore());
} else { displayTip(resultTipTV, "核身失败"); displayTip(scoreTV, "人脸实名认证分数过低:" + result.getScore())
; retBtn.setVisibility(View.VISIBLE); } } @Override public void onError(FaceException error) { delete(); // TODO 错误处理
// 如返回错误码为:216600,则核身失败,提示信息为:身份证号码错误 // 如返回错误码为:216601,则核身失败,
提示信息为:身份证号码与姓名不匹配 Toast.makeText(FaceOnlineVerifyActivity.this,
"权威数据源人脸实名核实失败:" + error.getMessage(), Toast.LENGTH_SHORT) .show(); retBtn.setVisibility(View.VISIBLE); } } ); }