这可能是全网惟一一篇介绍 Android Camera2 接口集成人脸算法的文章了~
写在后面:
说起人脸识别,置信大家都不会感到生疏,在咱们平时的工作生存中,人脸打卡、刷脸领取等等曾经是利用的十分宽泛了,人脸识别也给咱们的生存带来了极大的便当。
这篇文章的目标是让大家理解相熟 Android 平台上人脸算法集成的根本流程(针对应用层的集成)。置信读完这篇文章后,大家会觉的,原来集成人脸识别算法也是 so easy。
这篇文章将针对上面几点开展介绍:
一、Android 平台人脸识别程图
二、ArcSoft 人脸识别算法 sdk 下载
三、Camera2 API 集成 ArcSoft 人脸识别算法
一、Android 平台人脸识别流程图
人脸识别流程图根本如下图所示,用一句话来说就是获取 camera 数据,送到算法中进行辨认,最初显示辨认后果。
二、ArcSoft 人脸识别算法 sdk 下载
人脸识别算法很多,如果是高通平台,高通也是有一套人脸识别算法的。我这里抉择的是 arcsoft 的辨认算法,这个目前是收费的,而且相对来说算法成果也还不错。
接下来咱们看下如何去获取 arcsoft 的人脸识别 sdk。
1)登录 arcsoft 官网 https://ai.arcsoft.com.cn/,…
2)注册并登录开发者核心后,在开发者核心界面,咱们抉择“新建利用”,而后勾选人脸识别性能。
如下图所示,我创立的利用是“CameraDemo”。这个界面的 APP_ID 和 SDK_KEY 咱们前面代码外面须要用到。这个界面还有个“下载 SDK”的按钮,点击就能够下载咱们须要的 sdk demo。
3)Demo 下载下来后,咱们先跑下 arcsoft 官网 Demo 看下成果。
咱们抉择人脸检测属性 (视频)。
如下图所示,成果还不错,咱们能够看到辨认进去的信息外面蕴含了性别、年龄、是否是真人这些根本信息。
三、Camera2 API 集成
通过下面的 2 步,大家有没觉的集成人脸识别还是蛮简略的。介绍完了官网的 demo,那接下来咱们看下采纳 Android Camera2 的 api,如何去集成 arcsoft 的人脸识别算法呢。
1、如上面代码块所示,arcsoft 官网 demo 采纳的是 Camera1 的 api 接口,设置的预览数据的回调,回调的间接就是 nv21 的 byte[]数据,而后再把 byte[]数据送进去算法解决。
`private void initCamera() {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
CameraListener cameraListener = new CameraListener() {
@Override
public void onCameraOpened(Camera camera, int cameraId, int displayOrientation, boolean isMirror) {previewSize = camera.getParameters().getPreviewSize();
drawHelper = new DrawHelper(previewSize.width, previewSize.height, previewView.getWidth(), previewView.getHeight(), displayOrientation
, cameraId, isMirror, false, false);
}
@Override
public void onPreview(byte[] nv21, Camera camera) {if (faceRectView != null) {faceRectView.clearFaceInfo();
}
List<FaceInfo> faceInfoList = new ArrayList<>();
int code = faceEngine.detectFaces(nv21, previewSize.width, previewSize.height, FaceEngine.CP_PAF_NV21, faceInfoList);
if (code == ErrorInfo.MOK && faceInfoList.size() > 0) {code = faceEngine.process(nv21, previewSize.width, previewSize.height, FaceEngine.CP_PAF_NV21, faceInfoList, processMask);
if (code != ErrorInfo.MOK) {return;}
} else {return;}
List<AgeInfo> ageInfoList = new ArrayList<>();
List<GenderInfo> genderInfoList = new ArrayList<>();
List<Face3DAngle> face3DAngleList = new ArrayList<>();
List<LivenessInfo> faceLivenessInfoList = new ArrayList<>();
int ageCode = faceEngine.getAge(ageInfoList);
int genderCode = faceEngine.getGender(genderInfoList);
int face3DAngleCode = faceEngine.getFace3DAngle(face3DAngleList);
int livenessCode = faceEngine.getLiveness(faceLivenessInfoList);
// 有其中一个的错误码不为 ErrorInfo.MOK,return
if ((ageCode | genderCode | face3DAngleCode | livenessCode) != ErrorInfo.MOK) {return;}
if (faceRectView != null && drawHelper != null) {List<DrawInfo> drawInfoList = new ArrayList<>();
for (int i = 0; i < faceInfoList.size(); i++) {Log.v(TAG,"---faceInfoList.get(i).getRect():"+faceInfoList.get(i).getRect());
drawInfoList.add(new DrawInfo(drawHelper.adjustRect(faceInfoList.get(i).getRect()), genderInfoList.get(i).getGender(), ageInfoList.get(i).getAge(), faceLivenessInfoList.get(i).getLiveness(), RecognizeColor.COLOR_UNKNOWN, null));
}
drawHelper.draw(faceRectView, drawInfoList);
}
}
}`
2、接下来咱们要介绍的是应用 Camera2 接口,如何集成 arcsoft 的人脸识别算法。
我本人创立了个利用工程,demo 源码地址也在文末会给出。
咱们先来看下我本人写的 demo 效果图:
上面来解说下代码实现的次要步骤:
(不相熟 Camera2 接口的同学,倡议先找一篇对于 Camera2 API 的文章先理解下,对于 Camera2, 我本人后面也写过算是比拟具体的文章介绍,也欢送大家浏览)
i、初始化 imageReader
mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(),
mPreviewSize.getHeight(),ImageFormat.YUV_420_888, 2);
mImageReader.setOnImageAvailableListener(
mOnImageAvailableListener, mBackgroundHandler);
ii、创立 session 的时候,把 imagerReader 的 surface 也 add 进去。
这样咱们就能拿到实时的视频流。
mPreviewRequestBuilder.addTarget(mImageReader.getSurface());
mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
new CameraCaptureSession.StateCallback() {
}
**iii、在 imageReader 的实时流回调外面,咱们须要把接管到的 YUV_420_888 的数据先转换成 nv21 格局,而后再送进 arcsoft 的人脸检测算法中进行解决。
Camera1 接口上,设置预览数据回调后,回调的间接就是 nv21 格局的数据,相对来说会比 Camera2 上的解决会简略很多。**
不过 Android 目前曾经不再对 Camera 旧的架构进行保护,而且目前支流的手机采纳的基本上也都是 Camera2 的接口。所以咱们还是十分有必要相熟把握 Camera2 的各种应用。
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
= new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {Image image = reader.acquireLatestImage();
if(image == null){return;}
synchronized (mImageReaderLock) {if(!mImageReaderLock.equals(1)){Log.v(TAG, "--- image not available,just return!!!");
image.close();
return;
}
if (ImageFormat.YUV_420_888 == image.getFormat()) {Image.Plane[] planes = image.getPlanes();
lock.lock();
if (y == null) {y = new byte[planes[0].getBuffer().limit() - planes[0].getBuffer().position()];
u = new byte[planes[1].getBuffer().limit() - planes[1].getBuffer().position()];
v = new byte[planes[2].getBuffer().limit() - planes[2].getBuffer().position()];
}
if (image.getPlanes()[0].getBuffer().remaining() == y.length) {planes[0].getBuffer().get(y);
planes[1].getBuffer().get(u);
planes[2].getBuffer().get(v);
if (nv21 == null) {nv21 = new byte[planes[0].getRowStride() * mPreviewSize.getHeight() * 3 / 2];
}
if(nv21 != null && (nv21.length != planes[0].getRowStride() * mPreviewSize.getHeight() *3/2)){return;}
// 回传数据是 YUV422
if (y.length / u.length == 2) {ImageUtil.yuv422ToYuv420sp(y, u, v, nv21, planes[0].getRowStride(), mPreviewSize.getHeight());
}
// 回传数据是 YUV420
else if (y.length / u.length == 4) {ImageUtil.yuv420ToYuv420sp(y, u, v, nv21, planes[0].getRowStride(), mPreviewSize.getHeight());
}
// 调用 Arcsoft 算法, 绘制人脸信息
drawFaceInfo(nv21);
}
lock.unlock();}
}
image.close();}
};
Demo 代码地址:
https://pan.baidu.com/s/1z44m…
这篇文件介绍的,是针对应用层上的人脸算法集成。当初很多手机厂商,人脸算法有一部分是在 hal 层实现的。比方美颜算法这些,间接就是在 hal 层实现的了,这样解决效率会更高。针对 hal 层的算法集成,感兴趣同学的欢送留言,前面的文章我会进行更新介绍。
* 自己从事 Android Camera 相干开发已有 5 年,
* 目前在深圳下班,
* 欢送关注我的微信公众号: 小驰笔记
* 心愿和更多的小伙伴一起交流学习~
——– 2021.04.17 深圳 16:21