| | |
| | | private int mLastFaceId; |
| | | |
| | | private float threholdScore; |
| | | private String groupId; |
| | | |
| | | public static volatile int initStatus = SDK_UNACTIVATION; |
| | | public static volatile boolean initModelSuccess = false; |
| | |
| | | faceAuth.setCoreConfigure(BDFaceSDKCommon.BDFaceCoreRunMode.BDFACE_LITE_POWER_NO_BIND, 2); |
| | | } |
| | | |
| | | public String getGroupId() { |
| | | return groupId; |
| | | } |
| | | |
| | | public void setGroupId(String groupId) { |
| | | this.groupId = groupId; |
| | | } |
| | | |
| | | public void setActiveLog(boolean isLog) { |
| | | if (faceAuth != null) { |
| | | if (isLog) { |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | public void destroy(){ |
| | | /*if(rgbInstance!=null){ |
| | | rgbInstance = null; |
| | | }*/ |
| | | } |
| | | public void setCheckMouthMask(boolean checkMouthMask) { |
| | | this.checkMouthMask = checkMouthMask; |
| | | } |
| | |
| | | startInitModelTime = System.currentTimeMillis(); |
| | | } |
| | | |
| | | public void destroy(){ |
| | | if(rgbInstance!=null){ |
| | | rgbInstance = null; |
| | | } |
| | | } |
| | | |
| | | public FaceCrop getFaceCrop() { |
| | | return faceModel.getFaceCrop(); |
| | | } |
| | |
| | | |
| | | public void initDataBases(Context context) { |
| | | if (FaceApi.getInstance().getmUserNum() != 0) { |
| | | //ToastUtils.toast(context, "人脸库加载中"); |
| | | ToastUtils.toast(context, "人脸库加载中"); |
| | | } |
| | | emptyFrame(); |
| | | // 初始化数据库 |
| | |
| | | faceModel.getFaceSearch().pushPersonById(user.getId(), user.getFeature()); |
| | | } |
| | | if (FaceApi.getInstance().getmUserNum() != 0) { |
| | | //ToastUtils.toast(context, "人脸库加载成功"); |
| | | ToastUtils.toast(context, "人脸库加载成功"); |
| | | } |
| | | } |
| | | } |
| | |
| | | // 判断暗光恢复 |
| | | if (darkEnhance) { |
| | | rgbInstanceOne = faceModel.getDark().faceDarkEnhance(rgbInstance); |
| | | |
| | | rgbInstance.destory(); |
| | | } else { |
| | | rgbInstanceOne = rgbInstance; |
| | | } |
| | |
| | | return cropInstance; |
| | | } |
| | | |
| | | private static BDFaceImageInstance rgbInstance =null; |
| | | private LivenessModel livenessModel; |
| | | private String groupId; |
| | | |
| | | /** |
| | | * 0:管理员,1:用户 |
| | | * @param groupId |
| | | */ |
| | | public void setGroupId(String groupId){ |
| | | this.groupId = groupId; |
| | | } |
| | | /** |
| | | * 检测-活体-特征-人脸检索流程 |
| | | * |
| | |
| | | } |
| | | long startTime = System.currentTimeMillis(); |
| | | // 创建检测结果存储数据 |
| | | livenessModel = new LivenessModel(); |
| | | LivenessModel livenessModel = new LivenessModel(); |
| | | // 创建检测对象,如果原始数据YUV,转为算法检测的图片BGR |
| | | // TODO: 用户调整旋转角度和是否镜像,手机和开发版需要动态适配 |
| | | //System.out.println("==rgbInstance==>初始化"); |
| | | if(rgbInstance!=null){ |
| | | rgbInstance.destory(); |
| | | } |
| | | rgbInstance = getBdImage(bdFaceImageConfig, bdFaceCheckConfig.darkEnhance); |
| | | BDFaceImageInstance rgbInstance = getBdImage(bdFaceImageConfig, bdFaceCheckConfig.darkEnhance); |
| | | livenessModel.setTestBDFaceImageInstanceDuration(System.currentTimeMillis() - startTime); |
| | | onTrack( |
| | | rgbInstance, |
| | |
| | | if (!frameSelect(faceInfos[0])) { |
| | | livenessModel.setBdFaceImageInstance(rgbInstance.getImage()); |
| | | if (faceDetectCallBack != null && faceAdoptModel != null) { |
| | | //System.out.println("==isOk==>多帧判断"); |
| | | faceDetectCallBack.onFaceDetectDarwCallback(livenessModel); |
| | | faceDetectCallBack.onFaceDetectCallback(faceAdoptModel); |
| | | } |
| | | rgbInstance.destory(); |
| | | |
| | | return; |
| | | } |
| | |
| | | if (faceDetectCallBack != null) { |
| | | faceDetectCallBack.onFaceDetectCallback(null); |
| | | livenessModel.setBdFaceImageInstance(rgbInstance.getImage()); |
| | | //System.out.println("==isOk==>流程结束"); |
| | | |
| | | // SaveImageManager.getInstance().saveImage(livenessModel, bdFaceCheckConfig.bdLiveConfig); |
| | | faceDetectCallBack.onFaceDetectDarwCallback(livenessModel); |
| | | faceDetectCallBack.onTip(0, "未检测到人脸"); |
| | | } |
| | | rgbInstance.destory(); |
| | | } |
| | | }); |
| | | } |
| | |
| | | livenessModel.setAccurateTime(System.currentTimeMillis() - accurateTime); |
| | | |
| | | if (faceInfos == null || faceInfos.length <= 0) { |
| | | |
| | | rgbInstance.destory(); |
| | | detectListener.onDetectFail(); |
| | | return; |
| | | } |
| | |
| | | final long startTime, |
| | | final FaceDetectCallBack faceDetectCallBack, |
| | | final FaceInfo[] fastFaceInfos) { |
| | | |
| | | if (future2 != null && !future2.isDone()) { |
| | | // 流程结束销毁图片,开始下一帧图片检测,否着内存泄露 |
| | | //future2.cancel(true); |
| | | |
| | | //System.out.println("==isOk==>之前没结束"); |
| | | rgbInstance.destory(); |
| | | return; |
| | | } |
| | | |
| | |
| | | |
| | | @Override |
| | | public void run() { |
| | | try { |
| | | |
| | | // 获取BDFaceCheckConfig配置信息 |
| | | if (bdFaceCheckConfig == null) { |
| | | rgbInstance.destory(); |
| | | |
| | | return; |
| | | } |
| | |
| | | @Override |
| | | public void onDetectSuccess(FaceInfo[] faceInfos, BDFaceImageInstance rgbInstance) { |
| | | |
| | | try { |
| | | |
| | | // 人脸id赋值 |
| | | if (mLastFaceId != fastFaceInfos[0].faceID) { |
| | | mLastFaceId = fastFaceInfos[0].faceID; |
| | |
| | | } |
| | | |
| | | if (bdFaceCheckConfig == null) { |
| | | |
| | | rgbInstance.destory(); |
| | | livenessModel.clearIdentifyResults(); |
| | | if (faceDetectCallBack != null) { |
| | | faceDetectCallBack.onFaceDetectCallback(livenessModel); |
| | |
| | | if (!onBestImageCheck(livenessModel, bdFaceCheckConfig, faceDetectCallBack)) { |
| | | livenessModel.setQualityCheck(true); |
| | | livenessModel.clearIdentifyResults(); |
| | | |
| | | rgbInstance.destory(); |
| | | if (faceDetectCallBack != null) { |
| | | faceDetectCallBack.onFaceDetectCallback(livenessModel); |
| | | } |
| | |
| | | faceInfos, bdFaceCheckConfig.bdQualityConfig, faceDetectCallBack)) { |
| | | livenessModel.setQualityCheck(true); |
| | | livenessModel.clearIdentifyResults(); |
| | | |
| | | rgbInstance.destory(); |
| | | if (faceDetectCallBack != null) { |
| | | faceDetectCallBack.onFaceDetectCallback(livenessModel); |
| | | } |
| | | |
| | | return; |
| | | } |
| | | |
| | |
| | | bdFaceCheckConfig.activeModel, |
| | | rgbScores, |
| | | bdLiveConfig.rgbLiveScore); |
| | | } else { |
| | | } |
| | | else{ |
| | | onFeatureChecks( |
| | | i, |
| | | rgbInstance, |
| | |
| | | livenessModel.setAllDetectDuration(System.currentTimeMillis() - startTime); |
| | | // LogUtils.e(TIME_TAG, "all process time = " + livenessModel.getAllDetectDuration()); |
| | | // 流程结束销毁图片,开始下一帧图片检测,否着内存泄露 |
| | | |
| | | rgbInstance.destory(); |
| | | if (nirInstance != null) { |
| | | nirInstance.destory(); |
| | | } |
| | | // 显示最终结果提示 |
| | | if (faceDetectCallBack != null) { |
| | | faceDetectCallBack.onFaceDetectCallback(livenessModel); |
| | | } |
| | | }catch (RuntimeException e){ |
| | | faceDetectCallBack.onTip(1,e.getMessage()); |
| | | }catch (Exception e){ |
| | | faceDetectCallBack.onTip(1,e.getMessage()); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | }); |
| | | }catch (RuntimeException e){ |
| | | faceDetectCallBack.onTip(1,e.getMessage()); |
| | | }catch (Exception e){ |
| | | faceDetectCallBack.onTip(1,e.getMessage()); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | |
| | | * 特征提取-人脸识别比对 |
| | | * |
| | | * @param rgbInstance 可见光底层送检对象 |
| | | * @param landmark 检测眼睛,嘴巴,鼻子,72个关键点 |
| | | * @param faceInfos nir人脸数据 |
| | | * @param nirInstance nir 图像句柄 |
| | | * @param livenessModel 检测结果数据集合 |
| | | * @param featureCheckMode 特征抽取模式【不提取特征:1】;【提取特征:2】;【提取特征+1:N检索:3】; |
| | | * @param featureType 特征抽取模态执行 【生活照:1】;【证件照:2】;【混合模态:3】; |
| | | */ |
| | | private void onFeatureCheck( |
| | | BDFaceImageInstance rgbInstance, |
| | | BDFaceCheckConfig bdFaceCheckConfig, |
| | | float[] landmark, |
| | | FaceInfo[] faceInfos, |
| | | BDFaceImageInstance nirInstance, |
| | | LivenessModel livenessModel, |
| | | byte[] secondFeature, |
| | | final int featureCheckMode, |
| | | final int featureType) { |
| | | // 如果不抽取特征,直接返回 |
| | | if (featureCheckMode == 1) { |
| | | return; |
| | | } |
| | | byte[] feature = new byte[512]; |
| | | if (featureType == 3) { |
| | | // todo: 混合模态使用方式是根据图片的曝光来选择需要使用的type,光照的取值范围为:0~1之间 |
| | | AtomicInteger atomicInteger = new AtomicInteger(); |
| | | FaceSDKManager.getInstance().getImageIllum().imageIllum(rgbInstance, atomicInteger); |
| | | int illumScore = atomicInteger.get(); |
| | | BDQualityConfig bdQualityConfig = bdFaceCheckConfig.bdQualityConfig; |
| | | boolean isIllum = bdQualityConfig != null ? illumScore < bdQualityConfig.illum : false; |
| | | BDFaceSDKCommon.FeatureType type = |
| | | isIllum |
| | | ? BDFaceSDKCommon.FeatureType.BDFACE_FEATURE_TYPE_NIR |
| | | : BDFaceSDKCommon.FeatureType.BDFACE_FEATURE_TYPE_LIVE_PHOTO; |
| | | BDFaceImageInstance bdFaceImageInstance = isIllum ? nirInstance : rgbInstance; |
| | | float[] landmarks = isIllum ? faceInfos[0].landmarks : landmark; |
| | | |
| | | long startFeatureTime = System.currentTimeMillis(); |
| | | float featureSize = faceModel.getFaceFeature().feature(type, bdFaceImageInstance, landmarks, feature); |
| | | livenessModel.setFeatureDuration(System.currentTimeMillis() - startFeatureTime); |
| | | livenessModel.setFeature(feature); |
| | | // 人脸检索 |
| | | featureSearch( |
| | | featureCheckMode, |
| | | livenessModel, |
| | | bdFaceCheckConfig, |
| | | feature, |
| | | secondFeature, |
| | | featureSize, |
| | | BDFaceSDKCommon.FeatureType.BDFACE_FEATURE_TYPE_LIVE_PHOTO); |
| | | } else { |
| | | // 生活照检索 |
| | | long startFeatureTime = System.currentTimeMillis(); |
| | | float featureSize = |
| | | faceModel |
| | | .getFaceFeature() |
| | | .feature( |
| | | BDFaceSDKCommon.FeatureType.BDFACE_FEATURE_TYPE_LIVE_PHOTO, rgbInstance, landmark, feature); |
| | | livenessModel.setFeatureDuration(System.currentTimeMillis() - startFeatureTime); |
| | | livenessModel.setFeature(feature); |
| | | livenessModel.setFeatureDuration(System.currentTimeMillis() - startFeatureTime); |
| | | // 人脸检索 |
| | | featureSearch( |
| | | featureCheckMode, |
| | | livenessModel, |
| | | bdFaceCheckConfig, |
| | | feature, |
| | | secondFeature, |
| | | featureSize, |
| | | BDFaceSDKCommon.FeatureType.BDFACE_FEATURE_TYPE_LIVE_PHOTO); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 特征提取-人脸识别比对 |
| | | * |
| | | * @param rgbInstance 可见光底层送检对象 |
| | | * @param rgbFaceInfos rgb人脸数据 |
| | | * @param faceInfos nir人脸数据 |
| | | * @param nirInstance nir 图像句柄 |
| | |
| | | // 如果不抽取特征,直接返回 |
| | | |
| | | if (featureCheckMode == 1) { |
| | | |
| | | return; |
| | | } |
| | | byte[] feature = new byte[512]; |
| | |
| | | // 生活照检索 |
| | | long startFeatureTime = System.currentTimeMillis(); |
| | | if (rgbFaceInfos == null) { |
| | | |
| | | return; |
| | | } |
| | | |
| | |
| | | livenessModel.setFeature(feature); |
| | | livenessModel.setFeatureDuration(System.currentTimeMillis() - startFeatureTime); |
| | | // 人脸检索 |
| | | |
| | | featureSearchs( |
| | | index, |
| | | featureCheckMode, |
| | |
| | | livenessModel.setFeatureCode(featureSize); |
| | | return; |
| | | } |
| | | |
| | | // 如果提取特征+检索,调用search 方法 |
| | | if (featureSize == FEATURE_SIZE / 4) { |
| | | long startFeature = System.currentTimeMillis(); |
| | | // 特征提取成功 |
| | | |
| | | // TODO 阈值可以根据不同模型调整 |
| | | if (featureCheckMode == 3) { |
| | | //System.out.println("==isOk==>44"); |
| | | |
| | | List<? extends Feature> featureResult = |
| | | faceModel.getFaceSearch().search(type, bdFaceCheckConfig.scoreThreshold, 5, feature, false); |
| | | //System.out.println("==isOk==>45"); |
| | | faceModel.getFaceSearch().search(type, bdFaceCheckConfig.scoreThreshold, 2, feature, false); |
| | | |
| | | // TODO 返回top num = 1 个数据集合,此处可以任意设置,会返回比对从大到小排序的num 个数据集合 |
| | | if (featureResult != null && featureResult.size() > 0) { |
| | | //System.out.println("==isOk==>匹配到数量"+featureResult.size()); |
| | | User user = null; |
| | | Feature topFeature = null; |
| | | if(TextUtils.isEmpty(groupId)){ |
| | | //为空,需要排序,优先取会员 |
| | | for(Feature feat:featureResult) { |
| | | // 获取第一个数据 |
| | | Feature topFeature = featureResult.get(0); |
| | | // 判断第一个阈值是否大于设定阈值,如果大于,检索成功 |
| | | threholdScore = bdFaceCheckConfig.scoreThreshold; |
| | | if (feat != null && feat.getScore() > threholdScore) { |
| | | User userOld = FaceApi.getInstance().getUserListById(feat.getId()); |
| | | //System.out.println("==isOk==>匹配到类型:"+userOld.getUserName()); |
| | | if("1".equals(userOld.getGroupId())){ |
| | | user = userOld; |
| | | topFeature = feat; |
| | | break; |
| | | }else if(user==null){ |
| | | user = userOld; |
| | | topFeature = feat; |
| | | if (topFeature != null && topFeature.getScore() > threholdScore) { |
| | | // 当前featureEntity 只有id+feature 索引,在数据库中查到完整信息 |
| | | User user = FaceApi.getInstance().getUserListById(topFeature.getId()); |
| | | if (user != null) { |
| | | IdentifyResult idResult = new IdentifyResult(user, index, topFeature.getScore()); |
| | | // Log.d("Attend", "add user:" + user.getUserInfo() + " index:" + index); |
| | | livenessModel.addIdentifyResult(idResult); |
| | | livenessModel.setUser(user); |
| | | livenessModel.setFeatureScore(topFeature.getScore()); |
| | | |
| | | setFail(livenessModel); |
| | | } else { |
| | | setFail(livenessModel); |
| | | } |
| | | } |
| | | } else { |
| | | setFail(livenessModel); |
| | | } |
| | | }else { |
| | | //只取该类型用户 |
| | | User user = null; |
| | | Feature topFeature = null; |
| | | for(Feature feat:featureResult) { |
| | | // 获取数据 |
| | | // 判断阈值是否大于设定阈值,如果大于,检索成功 |
| | |
| | | } |
| | | } |
| | | } |
| | | } |
| | | if (user != null) { |
| | | if (user != null&&topFeature!=null) { |
| | | //System.out.println("==isOk==>匹配到"); |
| | | IdentifyResult idResult = new IdentifyResult(user, index, topFeature.getScore()); |
| | | livenessModel.addIdentifyResult(idResult); |
| | |
| | | livenessModel.setFeatureScore(topFeature.getScore()); |
| | | setFail(livenessModel); |
| | | } else { |
| | | //IdentifyResult idResult = new IdentifyResult(user, index, topFeature.getScore()); |
| | | setFail(livenessModel); |
| | | } |
| | | } |
| | | } else { |
| | | setFail(livenessModel); |
| | |
| | | faceDetectCallBack.onFaceDetectDarwCallback(livenessModel); |
| | | faceDetectCallBack.onTip(0, "未检测到人脸"); |
| | | } |
| | | |
| | | rgbInstance.destory(); |
| | | } |
| | | }); |
| | | } |
| | |
| | | |
| | | if (future2 != null && !future2.isDone()) { |
| | | // 流程结束销毁图片,开始下一帧图片检测,否着内存泄露 |
| | | |
| | | rgbInstance.destory(); |
| | | return; |
| | | } |
| | | |
| | |
| | | |
| | | @Override |
| | | public void run() { |
| | | try { |
| | | onDetect( |
| | | bdFaceCheckConfig, |
| | | rgbInstance, |
| | |
| | | new DetectListener() { |
| | | @Override |
| | | public void onDetectSuccess(FaceInfo[] faceInfos, BDFaceImageInstance rgbInstance) { |
| | | try { |
| | | // 人脸id赋值 |
| | | if (mLastFaceId != fastFaceInfos[0].faceID) { |
| | | mLastFaceId = fastFaceInfos[0].faceID; |
| | |
| | | mNirLiveList.clear(); |
| | | } |
| | | if (bdFaceCheckConfig == null) { |
| | | |
| | | rgbInstance.destory(); |
| | | if (faceDetectCallBack != null) { |
| | | faceDetectCallBack.onFaceDetectCallback(livenessModel); |
| | | } |
| | |
| | | // 最优人脸控制 |
| | | if (!onBestImageCheck(livenessModel, bdFaceCheckConfig, faceDetectCallBack)) { |
| | | livenessModel.setQualityCheck(true); |
| | | |
| | | rgbInstance.destory(); |
| | | if (faceDetectCallBack != null) { |
| | | faceDetectCallBack.onFaceDetectCallback(livenessModel); |
| | | } |
| | |
| | | System.currentTimeMillis() - startTime); |
| | | // LogUtils.e(TIME_TAG, "all process time = " + livenessModel.getAllDetectDuration()); |
| | | // 流程结束销毁图片,开始下一帧图片检测,否着内存泄露 |
| | | |
| | | rgbInstance.destory(); |
| | | // 显示最终结果提示 |
| | | if (faceDetectCallBack != null) { |
| | | faceDetectCallBack.onFaceDetectCallback(livenessModel); |
| | |
| | | livenessModel.setQualityOcclusion(occlusionFail); |
| | | livenessModel.setQualityDetect(detectFail); |
| | | livenessModel.setQualityCheck(true); |
| | | |
| | | rgbInstance.destory(); |
| | | if (faceDetectCallBack != null) { |
| | | faceDetectCallBack.onFaceDetectCallback(livenessModel); |
| | | } |
| | | } |
| | | }); |
| | | }catch (RuntimeException e){ |
| | | faceDetectCallBack.onTip(1,e.getMessage()); |
| | | }catch (Exception e){ |
| | | faceDetectCallBack.onTip(1,e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | } |
| | | } |
| | | }); |
| | | }catch (RuntimeException e){ |
| | | faceDetectCallBack.onTip(1,e.getMessage()); |
| | | }catch (Exception e){ |
| | | faceDetectCallBack.onTip(1,e.getMessage()); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | |
| | | // 人证核验特征提取 |
| | | public float personDetect( |
| | | final Bitmap bitmap, final byte[] feature, final BDFaceCheckConfig bdFaceCheckConfig, Context context) { |
| | | if(bitmap==null||bitmap.isRecycled()){ |
| | | return -1; |
| | | } |
| | | BDFaceImageInstance rgbInstance = new BDFaceImageInstance(bitmap); |
| | | float ret = -1; |
| | | FaceInfo[] faceInfos; |
| | |
| | | feature); |
| | | } |
| | | } else { |
| | | |
| | | rgbInstance.destory(); |
| | | return -1; |
| | | } |
| | | |
| | | rgbInstance.destory(); |
| | | return ret; |
| | | } |
| | | } |