人脸识别

    APP端集成开发

    一、 准备工作

    在正式集成前,需要做一些准备工作,完成一些账号、应用及配置,具体如下:

    1.1 注册成为开发者

    1. STEP1:点击百度AI 开放平台导航右侧的控制台,页面跳转到百度云登录界面,登录完毕后,将会进入到百度云后台,点击「控制台」进入百度云控制台页面;您也可以在官网直接点击免费试用,登录完毕后将自动进入到百度云控制台。
    2. STEP2:使用百度账号完成登录,如您还未持有百度账户,可以点击此处注册百度账户。
    3. STEP3:进入百度云欢迎页面,填写企业和个人基本信息,注册完毕,至此成为开发者。(如您之前已经是百度云用户或百度开发者中心用户,STEP3 可略过。)
    4. STEP4:进入百度云控制台,找到人工智能相关服务面板。
    5. STEP5:点击进入「人脸识别」模块。

    1.2 创建应用

    创建好账号后,在正式调用AI 能力之前,需要您创建一下应用,这个是调用服务的基础能力单元。 选择「人脸识别」服务,首先见到此服务的控制台概览页,点击「创建应用」,即可进入应用创建界面,如下图所示:

    创建应用

    如上图所示,点击「创建应用」,即可进入应用创建界面,如下图所示:

    img

    注意:您需要创建一个应用,分别做以下作用:

    • 应用一:勾选身份证识别能力,绑定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 示例代码下载

    人脸实名认证控制台创建完APP实名认证方案后,下载相应的IOS/安卓的示例工程。

    APP实名认证方案创建请参考这里

    img

    二、 集成逻辑

    2.1 IOS集成

    2.1.1 OCR身份证识别集成

    把下载下来的License文件(文件名:aip.license),添加到项目里面,无需更改文件名称,然后在AppDelegate添加以下代码引用进去。

    img

    FaceParameterConfig.h里面设置下载下来的License文件的名字和后缀。

    img

    通过API调用ViewController进行身份证扫描

    img

    详细调用文档,请参考 OCR-iOS-SDK文档

    2.1.2 人脸SDK集成

    1、打开或者新建一个项目。

    2、右键点击项目,会出现一个添加菜单,在菜单中选择『Add Files to“此处是你的项目名字”…… 』,如下图所示:

    img

    3、在添加文件弹出框里面选择申请到的license和SDK添加进来。如下图:

    注意:license为百度官方提供,刚才在后台下载的文件(文件名称:idl-license.face-ios)

    SDK包含下面三个文件:

    • IDLFaceSDK.framework
    • com.baidu.idl.face.faceSDK.bundle
    • com.baidu.idl.face.model.bundle

    img

    4、确认下 Bundle Identifier 是否是申请license时填报的那一个.

    5、注意:license 和 Bundle Identifier 为一一对应关系,填错了会导致SDK不可用.

    img

    6、 FACE_LICENSE_ID这个参数填写百度官方给的LicenseID

    FaceParameterConfig.h 文件中填写下面三项。

    img

    7、选择链接C++标准库。

    img

    8、如果没有使用pod管理第三方库的话,请在Build Setting Linking Other Linker Flags 上面加入 –ObjC选项。如果用了pod请忽略,因为pod会自动添加上。

    img

    以下为示例工程调用身份验证的代码片段:

    [[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所示。

    2.2 安卓集成

    2.2.1 OCR身份证识别集成

    • 把申请的license(aip.license)放到到项目中assets目录中
    • 修改app的build.gradle和AndroidMainest.xml包名为申请时填入的包名
    • 拷贝ocr-ui到您的工程中

    接下来调用具体请看Demo中的IdCardActivity

    1、初始化OCR SDK

    img

    2、调用api进行身份证扫描

    img

    3、调用api进行身份证识别

    img

    4、获得身份证号码和姓名后进入人脸活体验证步骤

    详细调用文档,请参考 OCR-Android-SDK文档

    2.2.2 人脸SDK集成

    1、授权参数

    a、把申请的license(idl-license.face-android")放到到项目中assets目录中

    b、修改 Config 类中的参数

    人脸实名认证控制台创建完APP方案后,会自动生成LicenseID和LicenseFileName信息,这里您只需要填写apiKey和secretkey信息即可。

    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_controlliveness_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);
    
                        }
                    }
            );
        }
    上一篇
    项目及方案创建
    下一篇
    H5端实名认证方案