这可能是全网惟一一篇介绍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