Android 百度离线人脸识别小案例
步骤:
第一步:有账号直接登入百度云,没有接自己注册,地址https://login.bce.baidu.com/
第二步:登入上去以后,点击离线采集sdk管理,如果没有认证,先进行企业认证,只有企业认证了,才能进行下面的操作。
第三步:认证之后,下载sdk压缩包
第四步:先将sdk导入到Android Studio ,运行sdk,得到设备指纹。然后选择联网或者这里离线激活方式,我这里选的是离线激活,按照离线激活方式的文档提供的步骤,完成离线激活,然后下载授权文件。
第五步:将授权文件的压缩包,放到sdk提示的路径下,再输入序列号,点击离线激活。
第六步:集成源码
1.把facelibrary库添加到自己的工程中:
(1)`settings.gradle` 添加`‘:facelibrary’`;
(2)app->build.gradle->dependencies->compile project(":facelibrary")。
2.自己选择需要的代码,添加到自己的项目里
第七步: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();} 自动识别
}
}
第九步:小案例的显示和效果
还没有评论,来说两句吧...