Android 百度离线人脸识别小案例

百度人脸识别方式有两种:

    第一种:在设备上采集,就是视频里检测到人脸,保存图片,我们根据路径,将图片上传到服务器,在服务器端进行人脸识别。

    第二种:就是在设备上采集,同时也在设备上进行识别,不用与服务器端进行交互,这也称为离线人脸识别,我们接下来要说的就是离线人脸识别。

步骤:

第一步:有账号直接登入百度云,没有接自己注册,地址https://login.bce.baidu.com/

第二步:登入上去以后,点击离线采集sdk管理,如果没有认证,先进行企业认证,只有企业认证了,才能进行下面的操作。

Android 百度离线人脸识别小案例_第1张图片

Android 百度离线人脸识别小案例_第2张图片 第三步:认证之后,下载sdk压缩包

Android 百度离线人脸识别小案例_第3张图片

第四步:先将sdk导入到Android Studio ,运行sdk,得到设备指纹。然后选择联网或者这里离线激活方式,我这里选的是离线激活,按照离线激活方式的文档提供的步骤,完成离线激活,然后下载授权文件。

Android 百度离线人脸识别小案例_第4张图片

第五步:将授权文件的压缩包,放到sdk提示的路径下,再输入序列号,点击离线激活。

Android 百度离线人脸识别小案例_第5张图片

 第六步:集成源码

    1.把facelibrary库添加到自己的工程中:

        (1)settings.gradle 添加‘:facelibrary’

         (2)app->build.gradle->dependencies->compile project(":facelibrary")。

  2.自己选择需要的代码,添加到自己的项目里

Android 百度离线人脸识别小案例_第6张图片

第七步:SDK的参数设置

   1.SDK初始化,采用默认的参数进行初始化(在源码的的MainActivity的initSDK方法里,这里必须初始化好,如果没有初始化好,在后面抽取图片的特征的时候,会抽取不到,那就不能进行对比,所以处理这个,我们可以用个阻塞队列处理,让它们同步)

private void initSDK() {
    FaceSDKManager.getInstance().init(this, new FaceSDKManager.SdkInitListener() {
        @Override
        public void initStart() {
            toast("sdk init start");
        }

        @Override
        public void initSuccess() {
            toast("sdk init success");
            if (FaceSDKManager.getInstance().initStatus() == FaceSDKManager.SDK_UNACTIVATION) {
                toast("SDK还未激活初始化,请先激活初始化");
                return;
            } else if (FaceSDKManager.getInstance().initStatus() == FaceSDKManager.SDK_INIT_FAIL) {
                toast("SDK初始化失败,请重新激活初始化");
                return;
            } else if (FaceSDKManager.getInstance().initStatus() == FaceSDKManager.SDK_INIT_SUCCESS) {
                toast("SDK正在加载模型,请稍后再试");
                return;
            } else if (FaceSDKManager.getInstance().initStatus() == FaceSDKManager.SDK_MODEL_LOAD_SUCCESS) {
              /*  startActivity(new Intent(MainActivity.this, FaceIdCompareActivity.class));
                finish();*/
            }
        }

        @Override
        public void initFail(int errorCode, String msg) {
            toast("sdk init fail:" + msg);
        }
    });
}

  2.在FaceEnvironment里查看或者设置SDK全局配置信息

public class FaceEnvironment {

    // SDK版本号
    public static final String VERSION = "2.0.0";

    public static final float LIVENESS_RGB_THRESHOLD = 0.8f;
    public static final float LIVENESS_IR_THRESHOLD = 0.8f;
    public static final float LIVENESS_DEPTH_THRESHOLD = 0.8f;

    public static boolean isFeatureDetect = false;

    private BDFaceSDKConfig config;

    /**
     * 最小人脸检测大小 建议50
     */
    public int minFaceSize;
    /**
     * 最大人脸检测大小 建议-1(不做限制)
     */
    public int maxFaceSize;

    /**
     * 人脸跟踪,检测的时间间隔 默认 500ms
     */
    public int trackInterval;

    /**
     * 人脸跟踪,跟踪时间间隔 默认 1000ms
     */
    public int detectInterval;

    /**
     * 人脸置信度阈值,建议值0.5
     */
    public float noFaceSize;

    /**
     * 人脸姿态角 pitch,yaw,roll
     */
    public int pitch;
    public int yaw;
    public int roll;

    /**
     * 质量检测模糊,遮挡,光照,默认不做质量检测
     */
    public boolean isCheckBlur;
    public boolean isOcclusion;
    public boolean isIllumination;

    /**
     * 检测图片类型,可见光或者红外
     */
    public FaceDetect.DetectType detectMethodType;

    public BDFaceSDKConfig getConfig() {
        if (config == null) {
            config = new BDFaceSDKConfig();
            setFaceConfig();
        } else {
            setFaceConfig();
        }
        return config;
    }

    private void setFaceConfig() {
        config.minFaceSize = getMinFaceSize();
        config.maxFaceSize = getMaxFaceSize();
        config.trackInterval = getTrackInterval();
        config.detectInterval = getDetectInterval();
        config.noFaceSize = getNoFaceSize();
        config.pitch = getPitch();
        config.yaw = getYaw();
        config.roll = getRoll();
        config.isCheckBlur = isCheckBlur;
        config.isOcclusion = isOcclusion;
        config.isIllumination = isIllumination;
        config.detectMethodType = getDetectMethodType();
    }

    3.在RgbVideoTrackActivity里设置质量参数(开启质量检测,性能会下降,可以选择不开启质量检测)

/**
 * 质量筛选
 *
 * @param faceInfos
 * @param imageFrame
 */
private void qualitySelect(FaceInfo[] faceInfos, ImageFrame imageFrame) {
    if (faceInfos == null || faceInfos.length == 0) {
        clearTip();
        return;
    }
    int qualityType = PreferencesUtil.getInt(TYPE_QUALITY, GlobalSet.TYPE_QUALITY_CLOSE);
    if (qualityType == GlobalSet.TYPE_QUALITY_CLOSE) {
        if (from == GlobalSet.TYPE_LIVING_SHOW) {
            featureIdenty(imageFrame, faceInfos);
        } else if (from == GlobalSet.TYPE_COLLECT_IMAGE) {
            faceCollect(imageFrame, faceInfos);
        }
    } else if (qualityType == GlobalSet.TYPE_QUALITY_OPEN) {
        float blurrValue = Float.parseFloat(PreferencesUtil.getString(TYPE_BLURR_THRESHOLD,
                String.valueOf(0.70)));
        float occlusionValue = Float.parseFloat(PreferencesUtil.getString(TYPE_OCCLUSION_THRESHOLD,
                String.valueOf(0.70)));
        float illuminateValue = Float.parseFloat(PreferencesUtil.getString(TYPE_ILLUMINATION_THRESHOLD,
                String.valueOf(40)));
        FaceInfo faceInfo = faceInfos[0];
        float[] occlu = faceInfo.occlu;
        if (occlu != null && occlu.length > 0) {
            float leftEye = occlu[0];
            float rightEye = occlu[1];
            float nose = occlu[2];
            float mouth = occlu[3];
            float lContour = occlu[4];
            float rContour = occlu[5];
            float chinContour = occlu[6];
            if ((faceInfo.blur < blurrValue) && (leftEye < occlusionValue) && (rightEye < occlusionValue)
                    && (nose < occlusionValue) && (mouth < occlusionValue) && (lContour < occlusionValue)
                    && (rContour < occlusionValue) && (chinContour < occlusionValue)
                    && (faceInfo.illum > illuminateValue)) {
                if (from == GlobalSet.TYPE_LIVING_SHOW) {
                    featureIdenty(imageFrame, faceInfos);
                } else if (from == GlobalSet.TYPE_COLLECT_IMAGE) {
                    faceCollect(imageFrame, faceInfos);
                }
            } else {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        tvTopShowState.setText("人脸质量差");
                    }
                });
            }
        } else {
            if (from == GlobalSet.TYPE_LIVING_SHOW) {
                featureIdenty(imageFrame, faceInfos);
            } else if (from == GlobalSet.TYPE_COLLECT_IMAGE) {
                faceCollect(imageFrame, faceInfos);
            }
        }
    }
}

第八步:在FaceIdCompareActivity里选择图片和在RgbVideoTrackActivity视频里检测到图片对比

       1.设置图片显示和完成图片的特征抽取       

try {
       final Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream( getImageContentUri(FaceIdCompareActivity.this, new File("/sdcard/faces/face.jpg"))));
    if (bitmap != null) {
        imgFirst.setImageBitmap(bitmap);
        if ((bitmap.getWidth() * bitmap.getHeight()) > pictureSize) {
            // 超过限制 缩放图片
            pictureResize(bitmap, 1);
        } else {
            syncFeature(bitmap, firstFeature, 1);
        }
    }
} catch (Exception e) {
    e.printStackTrace();
}

   1.1 因为在源码的操作步骤和处理是,点击按钮,进入到系统相册选取界面,选择图片,返回图片的uri,因为我们这是文件路径,所以我们转换成uri   getImageContentUri(FaceIdCompareActivity.this, new File("/sdcard/faces/face.jpg")))

 1.2接下来是特征抽取,只有图片和视频检测到的图片的特征都抽取成功,才能进行接下来的识别。

private void syncFeature(final Bitmap bitmap, final byte[] feature, final int index) {
    float ret = -1;
    ret = FaceApi.getInstance().extractIdPhotoFeature(bitmap, feature, 50);
    Log.i("wtf", "ret:" + ret);
    Log.d("firstFeatureFinished",index+".ret="+ret);
    if (ret == 128 && index == 1) {
        firstFeatureFinished = true;
    } else if (ret == 128 && index == 2) {
        secondFeatureFinished = true;
    }
    if (ret == 128) {
        toast("图片" + index + "特征抽取成功");
    } else if (ret == -100) {
        toast("未完成人脸比对,可能原因,图片1为空");
    } else if (ret == -101) {
        toast("未完成人脸比对,可能原因,图片2为空");
    } else if (ret == -102) {
        toast("未完成人脸比对,可能原因,图片1未检测到人脸");
    } else if (ret == -103) {
        toast("未完成人脸比对,可能原因,图片2未检测到人脸");
    } else {
        toast("未完成人脸比对,可能原因,"
                + "人脸太小(小于sdk初始化设置的最小检测人脸)"
                + "人脸不是朝上,sdk不能检测出人脸");
    }
    if(index==2 && ret == 128){  //这里是图片和视频检测的图片特征斗殴抽取成功后,直接调用match()方法,进行识别
        match();
    }
}

2.把从RgbVideoTrackActivity视频里获取到的图片显示到控件上,并完成特征抽取。

2.1 在界面可见时,就开启摄像头预览

@Override
protected void onResume() {
    super.onResume();
       //摄像头预览
        startCameraPreview();
}
/**
 * 摄像头图像预览
 */
private void startCameraPreview() {
    // 设置前置摄像头
    // Camera1PreviewManager.getInstance().setCameraFacing(Camera1PreviewManager.CAMERA_FACING_FRONT);
    // 设置后置摄像头
    // Camera1PreviewManager.getInstance().setCameraFacing(Camera1PreviewManager.CAMERA_FACING_BACK);
    // 设置USB摄像头
    Camera1PreviewManager.getInstance().setCameraFacing(Camera1PreviewManager.CAMERA_USB);

    Camera1PreviewManager.getInstance().startPreview(this, mPreviewView, mWidth, mHeight, new CameraDataCallback() {
        @Override
        public void onGetCameraData(int[] data, Camera camera, int width, int height) {
            dealCameraData(data, width, height);
        }
    });
}
/**
 * 摄像头数据处理
 *
 * @param data
 * @param width
 * @param height
 */
private void dealCameraData(int[] data, int width, int height) {
    if (selectType == TYPE_PREVIEWIMAGE_OPEN) {
        setTrackAngle(data, width, height); // 显示检测的图片。用于调试,如果人脸sdk检测的人脸需要朝上,可以通过该图片判断。实际应用中可注释掉
    }
           // 摄像头预览数据进行人脸检测
           faceDetect(data, width, height);


}
/**
 * 人脸检测
 *
 * @param argb
 * @param width
 * @param height
 */
private void faceDetect(int[] argb, int width, int height) {
    if (liveType == LivenessSettingActivity.TYPE_NO_LIVENSS) {
        FaceTrackManager.getInstance().setAliving(false); // 无活体检测
    } else if (liveType == LivenessSettingActivity.TYPE_RGB_LIVENSS) {
        FaceTrackManager.getInstance().setAliving(true); // 活体检测
    }
    FaceTrackManager.getInstance().faceTrack(argb, width, height, new FaceDetectCallBack() {
        @Override
        public void onFaceDetectCallback(LivenessModel livenessModel) {
            showFrame(livenessModel); //在这个方法里,如果符合检测要求,就会绘制绿框
            checkResult(livenessModel);//这个方法里,先是关于质量检测的,然后是关于脸的角度的,如果合格,就保存图片到本地,并且intent传数据到其它界面显示。
        }

        @Override
        public void onTip(int code, final String msg) {
            displayTip(msg);
        }
    });
}
/**
 * 图片收集
 *
 * @param faceInfo
 * @param imageFrame
 */
private void faceCollect(ImageFrame imageFrame, FaceInfo[] faceInfos) {
    FaceInfo faceInfo = faceInfos[0];
    float[] headPose = faceInfo.headPose;
    if (Math.abs(headPose[0]) > 30 || Math.abs(headPose[1]) > 30 || Math.abs(headPose[2]) > 30) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                tvTopShowState.setText("人脸置角度太大,请正对屏幕");
            }
        });
    } else {
        saveFace(faceInfo, imageFrame);
    }
}
/**
 * 图片截取
 *
 * @param faceInfo
 * @param imageFrame
 */
private void saveFace(FaceInfo faceInfo, ImageFrame imageFrame) {
    final Bitmap bitmap = FaceCropper.getFace(imageFrame.getArgb(), faceInfo, imageFrame.getWidth());
    try {
        // 其他来源保存到临时目录
        final File file = File.createTempFile(UUID.randomUUID().toString() + "", ".jpg");
        // 人脸识别不需要整张图片。可以对人脸区别进行裁剪。减少流量消耗和,网络传输占用的时间消耗。
        ImageUtils.resize(bitmap, file, 300, 300);
        Intent intent = new Intent();
        intent.putExtra("file_path", file.getAbsolutePath());
        setResult(Activity.RESULT_OK, intent);
        finish();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

然后显示从视频里获取到的人脸图片,显示在界面上,和从照片进行识别

Bitmap bitmap = BitmapFactory.decodeFile(faceImagePath);
if (bitmap != null) {
    imgSecond.setImageBitmap(bitmap);
    if ((bitmap.getWidth() * bitmap.getHeight()) > pictureSize) {
        // 超过限制 缩放图片
        pictureResize(bitmap, 1);
    } else {
        syncFeature(bitmap, secondFeature, 2);//将识别的方法match()放到方法里if(index==2 && ret == 128){ match();} 自动识别
      }
}

第九步:小案例的显示和效果

Android 百度离线人脸识别小案例_第7张图片

你可能感兴趣的:(Android 百度离线人脸识别小案例)