Android Camera2 集成人脸识别算法

news2025/2/23 17:02:03

这可能是全网唯一一篇介绍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.coloradmin.cn/o/1899337.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何给gitlab其他访问者创建账号并增加权限

嗨&#xff0c;今天创建了项目之后&#xff0c;我想把项目链接发送给其他人&#xff0c;让他下载这个项目&#xff0c;结果发现对方打开显示登录的界面&#xff0c;没错&#xff0c;他要想使用这个git下载项目&#xff0c;首先他的有一个git账号 接下来我找有权限的相关人员给他…

Pseudo-Label : The Simple and Efficient Semi-Supervised Learning Method--论文笔记

论文笔记 资料 1.代码地址 https://github.com/iBelieveCJM/pseudo_label-pytorch 2.论文地址 3.数据集地址 论文摘要的翻译 本文提出了一种简单有效的深度神经网络半监督学习方法。基本上&#xff0c;所提出的网络是以有监督的方式同时使用标记数据和未标记数据来训练的…

机器学习——决策树及其可视化

1、决策树概念 顾名思义&#xff0c;决策树是利用数据结构中树结构来进行判断&#xff0c;每一个结点相当于一个判断条件&#xff0c;叶子结点即是最终的类别。以鸢尾花为例&#xff0c;可以得到如下的决策树&#xff1a; 2、决策树分类的依据是什么&#xff1f; 根据前面分…

MySQL---事务管理

1.关于事务 理解和学习事务&#xff0c;不能只站在程序猿的角度来理解事务&#xff0c;而是要站在使用者&#xff08;用户&#xff09;的角度来理解事务。 比如支付宝转账&#xff0c;A转了B100块前&#xff0c;在程序猿的角度来看&#xff0c;是两条update操作&#xff0c;A …

电源设计技巧:DDR内存电源

CMOS逻辑系统的功耗主要与时钟频率、系统内各栅极的输入电容以及电源电压有关。器件形体尺寸减小后&#xff0c;电源电压也随之降低&#xff0c;从而在栅极层大大降低功耗。这种低电压器件拥有更低的功耗和更高的运行速度&#xff0c;允许系统时钟频率升高至千兆赫兹级别。在这…

非参数检测1——概述

在绝大多数的检测理论研究中&#xff0c;都着重于设计最优的检测器&#xff0c;最优检测器拥有最优的性能&#xff0c;但需要知道对输入信号和噪声的完整的统计学描述&#xff0c;这在实际应用中很可能无法实现。 实际情况&#xff1a; 设计检测系统时&#xff0c;无法得知完…

Kafka的简介、架构、安装使用、生产者、消费者、高吞吐、持久化及与Flume整合

Apache Kafka是一个分布式流处理平台&#xff0c;最初由LinkedIn公司开发&#xff0c;后来成为Apache软件基金会的一个顶级项目。Kafka主要用于构建实时数据管道和流处理应用程序。Kafka广泛应用于日志聚合、实时分析、事件源、流处理等场景。它与各种数据处理框架和数据库集成…

纯javascript实现图片批量压缩打包zip下载后端ThinkPHP多国语言切换国际站

最近在做一个多国语言的工具站&#xff0c;需要实现多国语言切换&#xff0c;说到多国语言站&#xff0c;肯定是有2种方式&#xff0c;第一是子域名&#xff0c;第二就是子目录。根据自己的需要来确定。 后台配置如下&#xff1a; 前台显示&#xff1a; 前端纯javascript实现…

VS code修改底部的行号的状态栏颜色

VSCode截图 相信很多小伙伴被底部的蓝色状态栏困扰很久了 处理的方式有两种&#xff1a; 1、隐藏状态栏 2、修改其背景颜色 第一种方法大伙都会&#xff0c;今天就使用第二种方法。 1、点击齿轮进入setting 2、我现在用的新版本&#xff0c;设置不是以前那种json格式展示&…

im即时通讯哪家好?WorkPlus im即时通讯集成底座为企业保驾护航

在当今数字化时代&#xff0c;即时通讯是企业内部沟通和协作的重要工具&#xff0c;提高工作效率和团队协作效果。在众多IM即时通讯提供商中&#xff0c;WorkPlus作为一家具有独特优势的企业IM即时通讯集成底座&#xff0c;为企业提供了全面的功能和安全保障&#xff0c;为企业…

一道有意思的简单题 [NOIP2010 普及组] 接水问题

题目&#xff1a; 题解&#xff1a; 每一次新来的同学的接水时间都加在现在已有的水龙头中接水时间最短的&#xff0c;总时间就为n次操作后水龙头中接水时间的最长值。 #include<bits/stdc.h> using namespace std; multiset<int>s;int main(){int n,m;scanf(&qu…

Linux基础指令及mysql(DQL)

[rootcentos ~]# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/export/server/jdk/bin:/root/binls在/usr/bin/路径下 [rootcentos ~]# which ls alias lsls --colorauto/usr/bin/lschmod ux,gx,o-r work.txt 可以对文件的权限进行修改。 sudo chown 修…

泛微开发修炼之旅--32ecology对接海康威视综合安防管理系统,人脸识别机器数据同步代码方案及源码

文章链接&#xff1a;32ecology对接海康威视综合安防管理系统&#xff0c;人脸识别机器数据同步代码方案及源码

电脑硬盘分区的基本步骤(2个实用的硬盘分区方法)

在现代计算机中&#xff0c;硬盘分区是非常重要的一步。无论是新硬盘的初始化&#xff0c;还是重新组织现有硬盘&#xff0c;分区都是必不可少的操作。本文将详细介绍电脑硬盘分区的基本步骤&#xff0c;帮助您更好地管理和利用硬盘空间。 文章开始&#xff0c;我们先简单说一…

CSS实现图片裁剪居中(只截取剪裁图片中间部分,图片不变形)

1.第一种方式&#xff1a;&#xff08;直接给图片设置&#xff1a;object-fit:cover;&#xff09; .imgbox{width: 100%;height:200px;overflow: hidden;position: relative;img{width: 100%;height: 100%; //图片要设置高度display: block;position: absolute;left: 0;right…

JavaDS预备知识

集合框架 Java 集合框架 Java Collection Framework &#xff0c;又被称为容器 container &#xff0c;是定义在 java.util 包下的一组接口 interfaces和其实现类 classes 。 其主要表现为将多个元素 element 置于一个单元中&#xff0c;对数据进行创建(Create)、读取(Retrieve…

笔记本休眠后自动关闭所有程序

关于主动进入休眠后&#xff0c;笔记本过一晚第二天会关闭所有程序&#xff0c;开始还以为&#xff0c;笔记本没电了&#xff0c;或者公司停电了导致笔记本没电关机&#xff0c;排查后发现不是。。。 原因是笔记本电脑默认设置休眠20分钟后自动关闭硬盘。 解决方案&#xff1a…

K8S 部署 EFK

安装说明 系统版本为 Centos7.9 内核版本为 6.3.5-1.el7 K8S版本为 v1.26.14 ES官网 开始安装 本次安装使用官方ECK方式部署 EFK&#xff0c;部署的是当前的最新版本。 在 Kubernetes 集群中部署 ECK 安装自定义资源 如果能打开这个网址的话直接用这个命令安装,打不开的话…

STM32学习历程(day3)

通过GPIO点灯 首先先创建工程 这步比较繁琐 可以去参考江协科技[3-2]章节 想要驱动LED灯 要先使能时钟、然后再初始化、GPIO模式、引脚、以及输出速率 可以查看RCC的头文件 能看到三个使能函数 使能AHB、APB2、APB1 &#xff0c;GPIO用APB2这个函数、 通过看RCC库函数的源码…

A4-C四驱高防轮式巡检机器人

在当今数字化和智能化迅速发展的时代&#xff0c;旗晟智能带来了一款革命性的创新产品——A4-C四驱高防轮式巡检机器人。这款机器人以其卓越的性能和多功能性&#xff0c;为工业巡检领域带来了全新的解决方案。 一、产品亮点 1、四驱动力与高防护设计 四驱高防轮式巡检机器人…