Android Camera2 集成人脸识别算法

这可能是全网唯一一篇介绍Android Camera2接口集成人脸算法的文章了~

写在前面:

说起人脸识别,相信大家都不会感到陌生,在我们平时的工作生活中,人脸打卡刷脸支付等等已经是应用的非常广泛了,人脸识别也给我们的生活带来了极大的便利。

这篇文章的目的是让大家了解熟悉Android平台上人脸算法集成的基本流程(针对应用层的集成)。相信读完这篇文章后,大家会觉的,原来集成人脸识别算法也是so easy。

0cb899e61152b3fd0b7106a18111e57f.png

这篇文章将针对下面几点展开介绍:

一、Android平台人脸识别流程图

二、ArcSoft人脸识别算法sdk下载

三、Camera2 API 集成 ArcSoft人脸识别算法

一、Android平台人脸识别流程图

人脸识别流程图基本如下图所示。

用一句话来说就是获取camera数据,送到算法中进行识别,最后显示识别结果。

cca3eb6b1900636a626d6e1b39a79d1b.png

二、ArcSoft人脸识别算法sdk下载

人脸识别算法很多,如果是高通平台,高通也是有一套人脸识别算法的。我这里选择的是arcsoft的识别算法,这个目前是免费的,而且相对来说算法效果也还不错。

接下来我们看下如何去获取arcsoft的人脸识别sdk。

1)登录arcsoft官网,然后选择进入开发者中心。

(https://ai.arcsoft.com.cn/)

8eb393d7b442db04c4a305f4a5e36feb.png

2)注册并登录开发者中心后,在开发者中心界面,我们选择“新建应用”,然后勾选人脸识别功能。

如下图所示,我创建的应用是“CameraDemo”。这个界面的APP_ID 和SDK_KEY我们后面代码里面需要用到。这个界面还有个“下载SDK”的按钮,点击就可以下载我们需要的sdk demo。

d458f77814de242bba8f026e01d907dc.png

3)Demo下载下来后,我们先跑下arcsoft官方Demo看下效果。

3ce0158a05b0686803d704290c60514e.png

我们选择人脸检测属性(视频)。如下图所示,效果还不错,我们可以看到识别出来的信息里面包含了性别、年龄、是否是真人这些基本信息。

97e8e482c495ce42ff4a5f988eb9ef3f.png

三、Camera2 API 集成 ArcSoft人脸识别算法

通过上面的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效果图:

d112107884144d9c5521811db629fc3b.png

下面来讲解下代码实现的主要步骤:

(不熟悉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();
        }
    };

这篇文件介绍的,是针对应用层上的人脸算法集成。

现在很多手机厂商,人脸算法有一部分是在hal层完成的。比如美颜算法这些,直接就是在hal层完成的了,这样处理效率会更高。

3fa447f5b0902155ff73579af6f543f4.png

《Android Camera开发入门》、《Camx初认识》已经上架,可以点击了解 -> 小驰成长圈 |期待见证彼此的成长 30dda9e8be4be8debd9500cb42580ab2.png

d7a906c77d38dcaffaebd345e92b9833.png

觉得不错,点个赞呗 5463dd4fc619f5a5dc06fbe0b8f4d915.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/777772.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于若依的文件上传、下载

基于若依实现文件上传、下载 文章目录 基于若依实现文件上传、下载1、前端实现-文件上传1.1 通用上传分析1.2 修改实现上传接口 2、后端实现-文件上传3、后端实现-文件下载4、前端实现-文件下载 官网其实也写了&#xff0c;但是我是自己改造封装了一下&#xff0c;再次迈向全栈…

kafka系列之消费后不提交offset情况的分析总结

概述 每当我们调用Kafka的poll()方法或者使用KafkaListener(其实底层也是poll()方法)时&#xff0c;它都会返回之前被写入Kafka的记录&#xff0c;即我们组中的消费者还没有读过的记录。 这意味着我们有一种方法可以跟踪该组消费者读取过的记录。 如前所述&#xff0c;Kafka的一…

一种一维时间序列信号变化/事件/异常检测方法(MATLAB)

随着工业物联网、大数据和人工智能的发展&#xff0c;传统工业正在向数字化和智能化升级&#xff0c;从而创造了大量的时间序列数据。通过分析这些数据&#xff0c;可以提供准确可靠的信息服务和决策依据&#xff0c;促进制造业的转型升级。工业物联网在传统工业向“工业 4.0”…

CASS如何输入距离和坐标绘制图形

1、软件版本 这里使用CASS7.0软件进行操作。如下&#xff1a; 2、 操作 输入&#xff1a;500,45【表示距离500米&#xff0c;方向45度】。 点击回车&#xff0c;完成绘制。

V3.76 ViVaCut高级版本!已经开启永久订阅!一款专业视频剪辑软件

在短视频和社交媒体盛行的今天&#xff0c;视频内容的创作和分享已经成为人们日常生活的一部分。为了满足广大视频创作者的需求&#xff0c;一款专业视频剪辑软件应运而生&#xff0c;以其强大的功能和用户友好的界面&#xff0c;为用户提供了全新的视频编辑体验。他提供了众多…

JWT(Json Web Token)在.NET Core中的使用

登录成功时生成JWT字符串目录 JWT是什么&#xff1f; JWT的优点&#xff1a; JWT在.NET Core 中的使用 JWT是什么&#xff1f; JWT把登录信息&#xff08;也称作令牌&#xff09;保存在客户端为了防止客户端的数据造假&#xff0c;保存在客户端的令牌经过了签名处理&#xf…

TikTok马来西亚直播网络怎么配置?

TikTok是一款全球流行的社交媒体应用&#xff0c;在东南亚地区拥有大量用户。在马来西亚这个多元化的国家&#xff0c;配置高效稳定的直播网络对TikTok的运营至关重要。 配置马来西亚直播网络的必要性 广泛的地理覆盖&#xff1a;马来西亚包括大片陆地和众多岛屿&#xff0c;网…

加入运动健康数据开放平台,共赢鸿蒙未来

HarmonyOS SDK运动健康服务&#xff08;Health Service Kit&#xff09;是为华为生态应用打造的基于华为帐号和用户授权的运动健康数据开放平台。在获取用户授权后&#xff0c;开发者可以使用运动健康服务提供的开放能力获取运动健康数据&#xff0c;基于多种类型数据构建运动健…

大数据Spark 面经

1: Spark 整体架构 Spark 是新一代的大数据处理引擎&#xff0c;支持批处理和流处理&#xff0c;也还支持各种机器学习和图计算&#xff0c;它就是一个Master-worker 架构&#xff0c;所以整个的架构就如下所示&#xff1a; 2: Spark 任务提交命令 一般我们使用shell 命令提…

理解MySQL核心技术:存储过程与函数的强大功能

在大型应用程序和复杂的数据库操作中&#xff0c;存储过程与函数扮演着至关重要的角色。它们不仅可以提高代码的可维护性&#xff0c;还能加强数据库的安全性和性能。本篇文章将深入探讨MySQL存储过程与函数的基础知识、创建、管理及其在实际应用中的优势。 什么是存储过程和函…

set的应用(C++)

set的使用 【基本用法】 大家可以敲一下这段代码体会一下set的基本初始化和使用 #include <iostream> #include <set> #include <vector> using namespace std;int main() {set<int> st1; // 空的set// 使用迭代器构造string str("abcdef"…

uniapp实现一个键盘功能

前言 因为公司需要&#xff0c;所以我.... 演示 代码 键盘组件代码 <template><view class"keyboard_container"><view class"li" v-for"(item, index) in arr" :key"index" click"changArr(item)" :sty…

【GIt】变基(rebase)

目录 变基(rebase)是什么为什么有变基变基后的时间线变基前的时间线 变基原理怎么变基同一个分支变基不同分支变基 参考文章 变基(rebase)是什么 Git 变基&#xff08;rebase&#xff09;是一种用于整合分支的方法&#xff0c;它的工作原理是将一系列提交&#xff08;或分支合…

Pycharm远程连接GPU(内容:下载安装Pycharm、GPU租借、配置SSH、将代码同步到镜像、命令行操控远程镜像、配置远程GPU解释器)

目录 windows下载安装pycharmGPU租借网站AutoDlfeaturize好易智算 GPU租借GPU选择选择镜像充值 然后创建镜像创建成功 复制SSH登录信息 远程进入镜像 在Pycharm中进行ssh连接新建SFTP配置SSH复制ssh根据复制的信息填写ssh配置测试连接 将代码同步到远程镜像上设置mappings将本地…

XAML 框架横向对比

多年来&#xff0c;基于 XAML 的 UI 框架有了很大的发展。下面的图表很好地证明了这个观点。XAML UI 框架的三大巨头&#xff1a;Avalonia UI、Uno Platform 和 .NET MAUI 都支持跨平台的应用。事实上&#xff0c;除了 Avalonia UI&#xff0c;对跨平台 XAML 的需求是它们发展的…

Mysql部署MHA高可用

部署前准备&#xff1a; mysql-8.0.27下载地址&#xff1a;https://cdn.mysql.com//Downloads/MySQL-8.0/mysql-8.0.27-1.el7.x86_64.rpm-bundle.tar mha-manager下载地址&#xff1a;https://github.com/yoshinorim/mha4mysql-manager/releases/download/v0.58/mha4mysql-mana…

三丰云评测:免费虚拟主机与免费云服务器的全面对比

三丰云是一家知名的互联网服务提供商&#xff0c;专注于虚拟主机和云服务器的服务。在互联网技术日新月异的今天&#xff0c;选择一个优质的云服务提供商至关重要。本次评测将重点对比三丰云的免费虚拟主机和免费云服务器&#xff0c;帮助用户更好地选择适合自己需求的服务。首…

Java基础-接口与实现

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 Java 接口 什么是接口&#xff1f; 声明接口 实现接口 继承接口 接口的多继承 标记接口 Java 接口 …

【海贼王的数据航海】ST表——RMQ问题

目录 1 -> RMQ问题 1.1 -> 定义 1.2 -> 解决策略 2 -> ST表 2.1 -> 定义 2.2 什么是可重复贡献问题 2.3 -> 预处理ST表 2.4 -> 处理查询 2.5 -> 实际问题 1 -> RMQ问题 1.1 -> 定义 RMQ (Range Minimum/Maximum Query)即区间最值查询…

Qwen1.5-1.8b部署

仿照ChatGLM3部署&#xff0c;参考了Qwen模型的文档&#xff0c;模型地址https://modelscope.cn/models/qwen/Qwen1.5-1.8B-Chat/summary http接口 服务端代码api.py from fastapi import FastAPI, Request from transformers import AutoTokenizer, AutoModelForCausalLM, …