代码 演示效果:
一,创建账号,并集成百度人脸离线采集
1、注册百度账号并认证
百度智能云地址:百度智能云控制台-管理中心 (baidu.com)
登录百度智能云后选择人脸采集
2. 创建你的应用
3.创建完成后,选择本地化部署,选择 离线人脸采集sdk ![](https://i-blog.csdnimg.cn/blog_migrate/ae7138be590e710073ad97e22532da8b.png)
4. 需要注册,按照流程走就行,一般一天就能申请下来
5. 注册完成后 创建新的授权
授权标识: 就是License ID 可以随意填写
场景类型:根据需要填写
开发平台:选择Android即可
Android包名 : 一定要和你的项目包名一样 比如我的项目包名是 com.bd.face,
那么我填写的也是com.bd.face
android MD5 签名:
1.首先 你要在Android中创建一个签名:
密钥 Alias:为您的密钥输入一个标识名。
Password:为您的密钥创建并确认一个安全的密码。此密码应当与您为密钥库选择 的密码不同
Validity (years):以年为单位设置密钥的有效时长。密钥的有效期应至少为 25 年, 以便您可以在应用的整个生命期内使用相同的密钥签署应用更新。
Certificate:为证书输入一些关于您自己的信息。此信息不会显示在应用中,但会作 为 APK 的一部分包含在您的证书中。 填写完表单后,请点击 OK
这样你的签名就已经生成好了 请牢记你的密码
2. (此步骤不可省略)生成完成之后 下面我们对 项目进行加签
输入上面Alias密钥标识 选择文件位置,输入你刚注册的密码 这里release 和debug 都需要
3. 下面开始生成签名的MD5
找到 studio中的Terminal
4.输入命令“ keytool -v -list -keystore gradledemo.jks ” 回车,(这里的xxxx.jks要输入你自己的),然后输入密码,就获取到你想要的信息了。如图
5.把得到的MD5 值 输入到 这里
点击确定后 生成
下面开始集成:
二、集成
2.1 创建 assets 资源文件夹 放入下载的 License
![](https://i-blog.csdnimg.cn/blog_migrate/7ece1b448c4343db7a18f7704edcd875.png)
2.2 引入faceplatform-release库
将开发包中的faceplatform-release库 Import Module 到工程。
2.3 引入faceplatform-ui库
将开发包中的faceplatform-ui库 Import Module 到工程。
2.4 在 app 下的build.gradle 中添加
implementation project(path: ':faceplatform-ui')
以上集成就已经完全集成成功!
下面奉上代码过程:
二.代码实现:
2.1首先添加权限:
清单文件中需要添加一下文件
<uses-permission android:name="android.permission.WRITE_CALENDAR"/> <uses-permission android:name="android.permission.READ_CALENDAR"/> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.hardware.camera.autofocus"/> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_SETTINGS" tools:ignore="ProtectedPermissions" /> <uses-permission android:name="android.permission.WAKE_LOCK"/>
需要添加动态权限有:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissions( new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE ,Manifest.permission.CAMERA },1001); }
2.2初始化FaceSDKManager
2.2.1 首先配置 人脸参数数据 上代码:
代码有点多但是基本上都是复制
private void setFaceConfig() { // 获取配置人脸 的接口 FaceConfig config = FaceSDKManager.getInstance().getFaceConfig(); // 设置模糊度阈值 config.setBlurnessValue((float)0.8); // 设置最小光照阈值(范围0-255) config.setBrightnessValue(30); // 设置最大光照阈值(范围0-255) config.setBrightnessMaxValue(240); // 设置左眼遮挡阈值 config.setOcclusionLeftEyeValue(v); // 设置右眼遮挡阈值 config.setOcclusionRightEyeValue(v); // 设置鼻子遮挡阈值 config.setOcclusionNoseValue(v); // 设置嘴巴遮挡阈值 config.setOcclusionMouthValue(v); // 设置左脸颊遮挡阈值 config.setOcclusionLeftContourValue(v); // 设置右脸颊遮挡阈值 config.setOcclusionRightContourValue(v); // 设置下巴遮挡阈值 config.setOcclusionChinValue(v); // 设置人脸姿态角阈值 config.setHeadPitchValue(30); config.setHeadYawValue(18); config.setHeadRollValue(30); // 设置可检测的最小人脸阈值 config.setMinFaceSize(FaceEnvironment.VALUE_MIN_FACE_SIZE); // 设置可检测到人脸的阈值 config.setNotFaceValue(FaceEnvironment.VALUE_NOT_FACE_THRESHOLD); // 设置闭眼阈值 config.setEyeClosedValue(FaceEnvironment.VALUE_CLOSE_EYES); // 设置图片缓存数量 config.setCacheImageNum(FaceEnvironment.VALUE_CACHE_IMAGE_NUM); // 设置活体动作,通过设置list,LivenessTypeEunm.Eye, LivenessTypeEunm.Mouth, // LivenessTypeEunm.HeadUp, LivenessTypeEunm.HeadDown, LivenessTypeEunm.HeadLeft, // LivenessTypeEunm.HeadRight config.setLivenessTypeList(livenessList); // 设置动作活体是否随机 config.setLivenessRandom(true); // 设置开启提示音 config.setSound(true); // 原图缩放系数 config.setScale(FaceEnvironment.VALUE_SCALE); // 抠图宽高的设定,为了保证好的抠图效果,建议高宽比是4:3 config.setCropHeight(FaceEnvironment.VALUE_CROP_HEIGHT); config.setCropWidth(FaceEnvironment.VALUE_CROP_WIDTH); // 抠图人脸框与背景比例 config.setEnlargeRatio(FaceEnvironment.VALUE_CROP_ENLARGERATIO); // 加密类型,0:Base64加密,上传时image_sec传false;1:百度加密文件加密,上传时image_sec传true config.setSecType(FaceEnvironment.VALUE_SEC_TYPE); // 检测超时设置 config.setTimeDetectModule(FaceEnvironment.TIME_DETECT_MODULE); // 检测框远近比率 config.setFaceFarRatio(FaceEnvironment.VALUE_FAR_RATIO); config.setFaceClosedRatio(FaceEnvironment.VALUE_CLOSED_RATIO); // 保存 设置 FaceSDKManager.getInstance().setFaceConfig(config); }
2.2.2初始化FaceSDKManager
// 初始化 人脸 功能
private void initLicense() {
// 调用 配置信息方法
setFaceConfig();
// 为了android和ios 区分授权,appId=appname_face_android ,其中appname为申请sdk时的应用名
// 应用上下文
// 申请License取得的APPID
// assets目录下License文件名
FaceSDKManager.getInstance().initialize(this, "******-face-android",
"idl-license.face-android", new IInitCallback() {
@Override
public void initSuccess() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "初始化成功", Toast.LENGTH_SHORT).show();
isfacle=true;
}
});
}
@Override
public void initFailure(final int errCode, final String errMsg) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "初始化失败", Toast.LENGTH_SHORT).show();
isfacle=false;
}
});
}
});
}
这样咱们 的初始化就完成了 下面就是初始化的全部代码
布局代码:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:onClick="onclick"
android:text="人脸采集"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
Java代码
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.baidu.idl.face.platform.FaceConfig;
import com.baidu.idl.face.platform.FaceEnvironment;
import com.baidu.idl.face.platform.FaceSDKManager;
import com.baidu.idl.face.platform.LivenessTypeEnum;
import com.baidu.idl.face.platform.listener.IInitCallback;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private List<LivenessTypeEnum> livenessList;
private float v = (float)0.95;
private boolean isfacle=false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.CAMERA},1001);
}
// 动作活体条目集合
livenessList = new ArrayList<>();
// 眨眼
livenessList.add(LivenessTypeEnum.Eye);
// 张嘴
livenessList.add(LivenessTypeEnum.Mouth);
// 右转
livenessList.add(LivenessTypeEnum.HeadRight);
// 初始化FaceSDK
initLicense();
}
public void onclick(View view) {
if (isfacle){
// 跳转到采集页面
startActivity(new Intent(this,FaceLivenessExpActivity.class));
}else {
Toast.makeText(this, "初始化失败", Toast.LENGTH_SHORT).show();
}
}
/**
* 参数配置方法
*/
private void setFaceConfig() {
// 获取配置人脸 的接口
FaceConfig config = FaceSDKManager.getInstance().getFaceConfig();
// 设置模糊度阈值
config.setBlurnessValue((float)0.8);
// 设置最小光照阈值(范围0-255)
config.setBrightnessValue(30);
// 设置最大光照阈值(范围0-255)
config.setBrightnessMaxValue(240);
// 设置左眼遮挡阈值
config.setOcclusionLeftEyeValue(v);
// 设置右眼遮挡阈值
config.setOcclusionRightEyeValue(v);
// 设置鼻子遮挡阈值
config.setOcclusionNoseValue(v);
// 设置嘴巴遮挡阈值
config.setOcclusionMouthValue(v);
// 设置左脸颊遮挡阈值
config.setOcclusionLeftContourValue(v);
// 设置右脸颊遮挡阈值
config.setOcclusionRightContourValue(v);
// 设置下巴遮挡阈值
config.setOcclusionChinValue(v);
// 设置人脸姿态角阈值
config.setHeadPitchValue(30);
config.setHeadYawValue(18);
config.setHeadRollValue(30);
// 设置可检测的最小人脸阈值
config.setMinFaceSize(FaceEnvironment.VALUE_MIN_FACE_SIZE);
// 设置可检测到人脸的阈值
config.setNotFaceValue(FaceEnvironment.VALUE_NOT_FACE_THRESHOLD);
// 设置闭眼阈值
config.setEyeClosedValue(FaceEnvironment.VALUE_CLOSE_EYES);
// 设置图片缓存数量
config.setCacheImageNum(FaceEnvironment.VALUE_CACHE_IMAGE_NUM);
// 设置活体动作,通过设置list,LivenessTypeEunm.Eye, LivenessTypeEunm.Mouth,
// LivenessTypeEunm.HeadUp, LivenessTypeEunm.HeadDown, LivenessTypeEunm.HeadLeft,
// LivenessTypeEunm.HeadRight
config.setLivenessTypeList(livenessList);
// 设置动作活体是否随机
config.setLivenessRandom(true);
// 设置开启提示音
config.setSound(true);
// 原图缩放系数
config.setScale(FaceEnvironment.VALUE_SCALE);
// 抠图宽高的设定,为了保证好的抠图效果,建议高宽比是4:3
config.setCropHeight(FaceEnvironment.VALUE_CROP_HEIGHT);
config.setCropWidth(FaceEnvironment.VALUE_CROP_WIDTH);
// 抠图人脸框与背景比例
config.setEnlargeRatio(FaceEnvironment.VALUE_CROP_ENLARGERATIO);
// 加密类型,0:Base64加密,上传时image_sec传false;1:百度加密文件加密,上传时image_sec传true
config.setSecType(FaceEnvironment.VALUE_SEC_TYPE);
// 检测超时设置
config.setTimeDetectModule(FaceEnvironment.TIME_DETECT_MODULE);
// 检测框远近比率
config.setFaceFarRatio(FaceEnvironment.VALUE_FAR_RATIO);
config.setFaceClosedRatio(FaceEnvironment.VALUE_CLOSED_RATIO);
// 保存 设置
FaceSDKManager.getInstance().setFaceConfig(config);
}
// 初始化 人脸 功能
private void initLicense() {
// 调用 配置信息方法
setFaceConfig();
// 为了android和ios 区分授权,appId=appname_face_android ,其中appname为申请sdk时的应用名
// 应用上下文
// 申请License取得的APPID
// assets目录下License文件名
FaceSDKManager.getInstance().initialize(this, "********android",
"idl-license.face-android", new IInitCallback() {
@Override
public void initSuccess() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "初始化成功", Toast.LENGTH_SHORT).show();
isfacle=true;
}
});
}
@Override
public void initFailure(final int errCode, final String errMsg) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "初始化失败", Toast.LENGTH_SHORT).show();
isfacle=false;
}
});
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
// 释放资源
FaceSDKManager.getInstance().release();
}
}
2.2 采集人脸页面的代码
2.2.1 创建一个java类 集成自 FaceLivenessActivity 这个 FaceLivenessActivity 是引用的Module里面的 在清单文件中记得注册
<activity
android:name=".FaceLivenessExpActivity"
android:hardwareAccelerated="true"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
Java代码: 重写里面的 onLivenessCompletion 方法
// todo 人脸 识别 活体检测
public class FaceLivenessExpActivity extends FaceLivenessActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
// 开始采集
@Override
public void onLivenessCompletion(FaceStatusNewEnum status, String message,
HashMap<String, ImageInfo> base64ImageCropMap,
HashMap<String, ImageInfo> base64ImageSrcMap, int currentLivenessCount) {
super.onLivenessCompletion(status, message, base64ImageCropMap, base64ImageSrcMap, currentLivenessCount);
}
@Override
public void finish() {
super.finish();
}
}
获取最优图片 人脸采集时像素最清晰的一张
// 开始采集
@Override
public void onLivenessCompletion(FaceStatusNewEnum status, String message,
HashMap<String, ImageInfo> base64ImageCropMap,
HashMap<String, ImageInfo> base64ImageSrcMap, int currentLivenessCount) {
super.onLivenessCompletion(status, message, base64ImageCropMap, base64ImageSrcMap, currentLivenessCount);
if (status == FaceStatusNewEnum.OK && mIsCompletion) {
// 获取最优图片
/***
* base64ImageCropMap 裁剪 图片 集合
* base64ImageSrcMap 原图集合
* */
getBestImage(base64ImageCropMap, base64ImageSrcMap);
// 在规定时间内没有完成
} else if (status == FaceStatusNewEnum.DetectRemindCodeTimeout) {
// 提示 动画
if (mViewBg != null) {
mViewBg.setVisibility(View.VISIBLE);
}
Toast.makeText(this, "您在规定时间内尚未完成", Toast.LENGTH_SHORT).show();
}
}
/**
* 获取最优图片
* @param imageCropMap 抠图集合
* @param imageSrcMap 原图集合
*/
private void getBestImage(HashMap<String, ImageInfo> imageCropMap,
HashMap<String, ImageInfo> imageSrcMap) {
String bmpStr = null;
// 将抠图集合中的图片按照质量降序排序,最终选取质量最优的一张抠图图片
if (imageCropMap != null && imageCropMap.size() > 0) {
List<Map.Entry<String, ImageInfo>> list1 = new ArrayList<>(imageCropMap.entrySet());
// 返回来的 值 在list1 中
Collections.sort(list1, new Comparator<Map.Entry<String, ImageInfo>>() {
@Override
public int compare(Map.Entry<String, ImageInfo> o1,
Map.Entry<String, ImageInfo> o2) {
String[] key1 = o1.getKey().split("_");
String score1 = key1[2];
String[] key2 = o2.getKey().split("_");
String score2 = key2[2];
// return 用于 结束循环 并返回 排完的集合
// 降序排序
return Float.valueOf(score2).compareTo(Float.valueOf(score1));
}
});
// 获取抠图中的加密或非加密的base64
// int secType = mFaceConfig.getSecType();
// String base64;
// if (secType == 0) {
// base64 = list1.get(0).getValue().getBase64();
// } else {
// base64 = list1.get(0).getValue().getSecBase64();
// }
}
// 将原图集合中的图片按照质量降序排序,最终选取质量最优的一张原图图片
if (imageSrcMap != null && imageSrcMap.size() > 0) {
List<Map.Entry<String, ImageInfo>> list2 = new ArrayList<>(imageSrcMap.entrySet());
// 排序方法 返回的值在list2中
Collections.sort(list2, new Comparator<Map.Entry<String, ImageInfo>>() {
@Override
public int compare(Map.Entry<String, ImageInfo> o1,
Map.Entry<String, ImageInfo> o2) {
String[] key1 = o1.getKey().split("_");
String score1 = key1[2];
String[] key2 = o2.getKey().split("_");
String score2 = key2[2];
// 降序排序
return Float.valueOf(score2).compareTo(Float.valueOf(score1));
}
});
// 获取 原图 集合中最优的一张图片
// 给他转化为 Base64 码
// 这个码 就是我们人脸的信息
bmpStr = list2.get(0).getValue().getBase64();
// 获取原图中的加密或非加密的base64
// int secType = mFaceConfig.getSecType();
// String base64;
// if (secType == 0) {
// base64 = bmpStr;
// } else {
// base64 = list2.get(0).getValue().getBase64();
// }
// Log.i("base64", base64);
}
// 获取完 人脸信息后 页面跳转
// IntentUtils 导入的包 封装好的
IntentUtils.getInstance().setBitmap(bmpStr);
Intent intent = new Intent(FaceLivenessExpActivity.this,
CompleteActivity.class);
startActivity(intent);
}
还有一个 采集完成跳转的Activity 在下面给大家贴上代码
public class CompleteActivity extends AppCompatActivity {
private ImageView image;
private String bmpStr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_complete);
image = findViewById(R.id.image);
Intent intent = getIntent();
if (intent != null) {
// 把 传过来的 Bitmp 流转化为 bitmmap 图片
bmpStr = IntentUtils.getInstance().getBitmap();
if (TextUtils.isEmpty(bmpStr)) {
return;
}
Bitmap bmp = base64ToBitmap(bmpStr);
// 进行裁剪
bmp = FaceSDKManager.getInstance().scaleImage(bmp,
DensityUtils.dip2px(getApplicationContext(), 97),
DensityUtils.dip2px(getApplicationContext(), 97));
image.setImageBitmap(bmp);
Log.i("base64", "initData: "+ bmpStr);
}
}
private Bitmap base64ToBitmap(String base64Data) {
byte[] bytes = Base64Utils.decode(base64Data, Base64Utils.NO_WRAP);
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 释放资源
IntentUtils.getInstance().release();
}
以上又是人脸识别的全部过程 第一次写博客 多谢大家支持! 在集成过程中如果有疑问