首先到虹软人脸AI开放平台https://ai.arcsoft.com.cn/product/arcface.html?utm_source=baidu1f&utm_medium=cpc&audience=313092完成注册登陆,并且添加一个Arcface应用,获得应用的激活码,然后下载sdk‘到本地,里面有个simpleDemo/ArcfaceDemo的android demo,还有sdk的doc文档,下面是对二者的分析和如何使用sdk
调用流程:
1.先重写activity的startActivityForResult()方法,访问手机的所有图片,并获取到图片文件
2.再通过重写activity的onActivityResult()方法,处理startActivityForResult返回的文件数据(人脸图片),处理方式:
2.1拿到文件的路径后,通过调用processImage()方法:关键代码如下:
public void processImage(Bitmap bitmap, int type) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
//bitmap转NV21
final byte[] nv21 = ImageUtil.bitmapToNv21(bitmap, width, height);
}
将图片文件转成bitMap形式,便于计算机处理图片信息(图片的人脸信息)
2.2将bitmap转为nv21,得到图片的nv21格式,宽,高后,就调用FaceEngine对象的detectFaces()方法
List faceInfoList = new ArrayList<>();
//人脸检测
int detectCode = faceEngine.detectFaces(nv21, width, height, FaceEngine.CP_PAF_NV21, faceInfoList);
detectFaces()方法的关键代码如下:
faceInfoList.clear();
int count = this.detectFaces(this.handle, data, width, height, format, this.mFaceInfoArray, this.error);
if (count > 0) {
for(int i = 0; i < count; ++i) {
faceInfoList.add(new FaceInfo(this.mFaceInfoArray[i]));
}
}
return this.error.code;
3.拿到预处理的图像数据faceInfo后就调用extractFaceFeature()方法
FaceFeature faceFeature = new FaceFeature();
int frCode = faceEngine.extractFaceFeature(nv21Data, width, height, format, faceInfo, faceFeature);
//该方法的返回值是int,frCode代表的是错误码的意思,返回的错误码为ErrorInfo.MOK表示特征提取成功
//MOK调用成功 MERR_INVALID_PARAM无效的参数 MERR_EXPIRED操作时间过期............
extractFaceFeature()方法的关键代码如下:
this.extractFaceFeature(this.handle, data, width, height, format, faceInfo.getRect(), faceInfo.getOrient(), feature.getFeatureData(), this.error);
return this.error.code;
进一步追踪this.后面的extractFaceFeature():
private native void extractFaceFeature(long var1, byte[] var3, int var4, int var5, int var6, Rect var7, int var8, byte[] var9, ErrorInfo var10);
这是一个原生方法,它是通过sdk中的 so库里的c或c++的函数实现的(人脸识别的一系列算法),先new一个FaceFeature(人脸特征对象,用于输出人脸特征数据)以参数形式传入到extractFaceFeature中,通过人脸识别算法为FaceFeature对象的字段FEATURE_SIZE
人脸特征数据的长度赋值,再调用FaceFeature对象的setFeatureData(byte[] data)设置人脸特征数据,从而提取出人脸特征,调用FaceFeature的getFeatureData()就能获取到人脸特征数据
4.拿到FaceFuture后,就调用compareFaceFeature()比对人脸:
FaceFeature mainFeature = new FaceFeature();
int res = faceEngine.extractFaceFeature(nv21, width, height, FaceEngine.CP_PAF_NV21, faceInfoList.get(0), mainFeature);
FaceSimilar faceSimilar = new FaceSimilar();
/**
*compareFaceFeature方法
*/
int compareResult = faceEngine.compareFaceFeature(mainFeature, faceFeature, faceSimilar);
ItemShowInfo showInfo = new ItemShowInfo(bitmap, ageInfoList.get(0).getAge(), genderInfoList.get(0).getGender(), faceSimilar.getScore());
//List showInfoList;
showInfoList.add(showInfo);
5.调用 FaceEngine 的 process 方法,传入不同的 combineMask 组合可对 Age、 Gender、Face3Dangle、Liveness 进行检测,传入的 combineMask 的任一属性都需要在 init 时进行初始化,process ()关键代码 :
int faceProcessCode = faceEngine.process(nv21, width, height, FaceEngine.CP_PAF_NV21, faceInfoList, FaceEngine.ASF_AGE | FaceEngine.ASF_GENDER | FaceEngine.ASF_FACE3DANGLE);
//年龄信息结果
List ageInfoList = new ArrayList<>();
//性别信息结果
List genderInfoList = new ArrayList<>();
//三维角度结果
List face3DAngleList = new ArrayList<>();
//获取年龄、性别、三维角度
int ageCode = faceEngine.getAge(ageInfoList);
int genderCode = faceEngine.getGender(genderInfoList);
int face3DAngleCode = faceEngine.getFace3DAngle(face3DAngleList);
获取相似度的评分代码如下:
float similarScore=faceSimilar.getScore();
也可以通过如下获得:
List showInfoList;
ItemShowInfo showInfo = new ItemShowInfo(bitmap, ageInfoList.get(0).getAge(), genderInfoList.get(0).getGender(), faceSimilar.getScore());
showInfoList.add(showInfo);
int age=showInfoList.getAge();
int gender=showInfoList.getGender();
float similar=showInfoList.getSimilar();
人脸注册 :
给出人脸文件夹
File dir = new File(REGISTER_DIR);
final File[] jpgFiles = dir.listFiles()
final int totalCount = jpgFiles.length;
for (int i = 0; i < totalCount; i++) {
final File jpgFile = jpgFiles[i];
Bitmap bitmap = BitmapFactory.decodeFile(jpgFile.getAbsolutePath());
//处理过的Bitmap对象
bitmap = ImageUtil.alignBitmapForNv21(bitmap);
byte[] nv21 = ImageUtil.bitmapToNv21(bitmap, bitmap.getWidth(), bitmap.getHeight());
boolean success = FaceServer.getInstance().register(FaceManageActivity.this, nv21, bitmap.getWidth(), bitmap.getHeight(),
jpgFile.getName().substring(0, jpgFile.getName().lastIndexOf(".")));
}
nv21注册:
public boolean register(Context context, byte[] nv21, int width, int height, String name) {
/**
* 人脸注册关键代码
* ****************************重点关注**************************************************
*/
//特征存储的文件夹
File featureDir = new File(ROOT_PATH + File.separator + SAVE_FEATURE_DIR);
//图片存储的文件夹
File imgDir = new File(ROOT_PATH + File.separator + SAVE_IMG_DIR);
//1.人脸检测
List faceInfoList = new ArrayList<>();
int code = faceEngine.detectFaces(nv21, width, height, FaceEngine.CP_PAF_NV21, faceInfoList);
if (code == ErrorInfo.MOK && faceInfoList.size() > 0) {
FaceFeature faceFeature = new FaceFeature();
//2.特征提取
code = faceEngine.extractFaceFeature(nv21, width, height, FaceEngine.CP_PAF_NV21, faceInfoList.get(0), faceFeature);
String userName = name == null ? String.valueOf(System.currentTimeMillis()) : name;
try {
//3.保存注册结果(注册图、特征数据)
if (code == ErrorInfo.MOK) {
YuvImage yuvImage = new YuvImage(nv21, ImageFormat.NV21, width, height, null);
//为了美观,扩大rect截取注册图
Rect cropRect = getBestRect(width, height, faceInfoList.get(0).getRect());
if (cropRect == null) {
return false;
}
File file = new File(imgDir + File.separator + userName + IMG_SUFFIX);
FileOutputStream fosImage = new FileOutputStream(file);
yuvImage.compressToJpeg(cropRect, 100, fosImage);
fosImage.close();
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
//判断人脸旋转角度,若不为0度则旋转注册图
boolean needAdjust = false;
if (bitmap != null) {
switch (faceInfoList.get(0).getOrient()) {
case FaceEngine.ASF_OC_0:
break;
case FaceEngine.ASF_OC_90:
bitmap = ImageUtil.getRotateBitmap(bitmap, 90);
needAdjust = true;
break;
case FaceEngine.ASF_OC_180:
bitmap = ImageUtil.getRotateBitmap(bitmap, 180);
needAdjust = true;
break;
case FaceEngine.ASF_OC_270:
bitmap = ImageUtil.getRotateBitmap(bitmap, 270);
needAdjust = true;
break;
default:
break;
}
}
if (needAdjust) {
fosImage = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fosImage);
fosImage.close();
}
FileOutputStream fosFeature = new FileOutputStream(featureDir + File.separator + userName);
fosFeature.write(faceFeature.getFeatureData());
fosFeature.close();
//内存中的数据同步
if (faceRegisterInfoList == null) {
faceRegisterInfoList = new ArrayList<>();
}
faceRegisterInfoList.add(new FaceRegisterInfo(faceFeature.getFeatureData(), userName));
return true;
}
}