无极安卓网

安卓手机面部识别 Android人脸识别技术的应用与实现

来源:无极安卓网

现代科技不断发展,人脸识别技术也得到了越来越广泛的应用。在移动设备方面,安卓手机面部识别技术已经成为了越来越多手机厂商的标配之一。随着这一技术的不断成熟和完善,它在移动支付、手机解锁、社交互动等各个领域的应用也越来越普及。那么作为一种安全、快速、高效的识别方式,Android人脸识别技术的应用与实现究竟有哪些值得我们深入了解的方面呢?接下来我们将对此进行分析和探讨。

Android人脸识别技术的应用与实现

前言OpenCV (API level 8 +)识别效果一般,侧脸无法识别.对识别的距离有限制(2~3米).如果需要做静态图片识别的话,需要对 Java library层进行修改.项目里有我编好的动态链接库,拿来就能用,不需要再装官方 OpencvManger.apk 了.文档:http://www.opencv.org/platforms/android/

2、Camera内部的 API (API level 14+)

效果很好.几乎所有的手机都支持(小米系统相机的人脸检测就是用这种方法做的).可以识别侧脸.如果需要做静态图片识别的话,成本很高.文档:https://developer.android.google.com/reference/android/hardware/Camera.html

3、android.media.FaceDetector 静态检测 (API level 1 +)

底层代码:android/external/neven/ 只能接受Bitmap 格式的数据. Bitmap 编码格式必须为Bitmap.Config.RGB_565. - Bitmap 的宽度一定要是整数. - 只能识别双眼距离大于20 像素的人脸像,这个限制应该可以在 FrameWork 中做修改. 文档:https://developer.android.google.com/reference/android/media/FaceDetector.html

4、Google Play Service 的 Vision API (API 9,在 API 17 增加了一些功能)

非常强大,效果基本能和 Camera API 持平.静态识别支持比较低清晰度的图片.可以识别是否睁眼.可以得到眼睛,鼻子嘴巴等的位置.有关于情绪的返回值.可以识别头部姿势.手机必须安装了 Google 服务框架才能使用.文档:https://developers.google.com/vision/face-detection-concepts

5、Face++ Android SDK

试用需要发邮件申请.文档很挫.没有示例 demo.效果应该没问题.官网:https://www.faceplusplus.com.cn/

一、正文

1、效果图

本文重点介绍FaceDetector基于静态人脸的检测实现,先上效果图~

安卓手机面部识别 Android人脸识别技术的应用与实现效果图

2、检测说明

由于FaceDetector是只接收bitmap的静态图片的人脸检测方案,因此我们在做检测的时候需要将每一帧预览帧拿去做检验。

但是你以为这样就完了,太天真了,你每一帧是一个完整的手机屏幕里面的人脸可能检测的时候根本就没有出现在圆圈内。因此我们需要用前景遮挡图+背景预览帧画面组合合成一张待检测图片进行送检。

3、FaceDetector检测核心代码

FaceDetector face_detector = new FaceDetector(newBP.getWidth(), newBP.getHeight(), faceNum);
FaceDetector.Face[] faces = new FaceDetector.Face[faceNum];
安卓手机面部识别 Android人脸识别技术的应用与实现FaceDetector构造方法安卓手机面部识别 Android人脸识别技术的应用与实现FaceDetector检测人脸方法

4、注意事项

FaceDetector检测的bitmap要求为RGB_565格式(The bitmap must be in 565 format)

二、实例

1、相机实时预览

使用相机实时预览这边使用的是SurfaceView

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <SurfaceView
            android:id="@+id/surfaceView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>
</layout>

2、定义圆形透明遮挡层

2.1 使用Canvas首先绘制整屏幕的白色遮挡层

canvas.drawARGB(255, 255, 255, 255);

2.2 使用Canvas在白色遮挡层上抠出一个透明的原型显示预览画面

mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAlpha(0);
// android.graphics.PorterDuff.Mode.CLEAR 显示挖空canvas为透明
mPaint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.CLEAR));

canvas.drawCircle(宽度, 高度, 大小, mPaint);

3、开始进行相机预览

使用SurfaceHolder对象增加回调监听,在监听中预览和处理响应识别业务

/**
     * 开始预览
     */
    private void startPreview() {
        SurfaceHolder holder = binding.surfaceView.getHolder();
        holder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder surfaceHolder) {
                mCamera = getCustomCamera();
                mCamera.setPreviewCallback((data, camera) -> {
                    // 是否已经检测成功,如果是则不继续检测
                    if (isIdentify) {
                        checkFaces(data, camera, surfaceHolder, this);
                    }
                });
            }

            @Override
            public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
                if (mCamera != null) {
                    Camera.Parameters parameters = mCamera.getParameters();
                    // 选择合适的图片尺寸,必须是手机支持的尺寸
                    List<Camera.Size> sizeList = parameters.getSupportedPictureSizes();
                    // 如果sizeList只有一个我们也没有必要做什么了,因为就他一个别无选择
                    if (sizeList.size() > 1) {
                        for (int j = 0; j < sizeList.size(); j++) {
                            Camera.Size size = sizeList.get(j);
                            previewWidth = size.width;
                            previewHeight = size.height;
                        }
                    }
                    //设置照片的大小
                    parameters.setPictureSize(previewWidth, previewHeight);
                    mCamera.setParameters(parameters);
                    try {
                        mCamera.setPreviewDisplay(holder);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    CameraUtils.takePicture((data, camera) -> {
                        CameraUtils.startPreview();
                        Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                        if (bitmap != null) {
                            bitmap = ImageUtils.getRotatedBitmap(bitmap, 180);
                        }
                        CameraUtils.startPreview();
                    });
                    //调用相机预览功能
                    mCamera.startPreview();
                }
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
                if (null != mCamera) {
                    holder.removeCallback(this);
                    mCamera.setPreviewCallback(null);
                    //停止预览
                    mCamera.stopPreview();
                    mCamera.lock();
                    //释放相机资源
                    mCamera.release();
                    mCamera = null;
                }
            }
        });
    }

4、人脸识别检测

4.1 预览图片

通过回调方法我们可以实时获取相机预览的图片字节数据,但是需要注意的是这个图片的格式是Yuv格式的。如果要在Android中正常的显示和操作则需要进行常规的转换,这里Yuv转bitmap的方法如下:

    public Bitmap convertYUVtoRGB(byte[] yuvData, int width, int height) {
        if (yuvType == null) {
            yuvType = new Type.Builder(rs, Element.U8(rs)).setX(yuvData.length);
            in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);

            rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height);
            out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);
        }
        in.copyFrom(yuvData);
        yuvToRgbIntrinsic.setInput(in);
        yuvToRgbIntrinsic.forEach(out);
        Bitmap bmpout = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        out.copyTo(bmpout);
        return bmpout;
    }

4.2 构建检测图片

其中核心的如前面说的我们需要将整个画面截屏出来进行识别,但是SurfaceView由于他的缓存机制是无法通过常规的getDrawableCache获取其截图的。就算你获取了也是空白图片,所以这里需要获取非SurfaceView部分和相机预览部分进行人为的叠拼。

/**
     * 合并两张bitmap图片
     *
     * @param firstBitmap
     * @param secondBitmap
     * @return
     */
    private Bitmap mergeBitmap(Bitmap firstBitmap, Bitmap secondBitmap) {
        Bitmap bitmap = Bitmap.createBitmap(firstBitmap.getWidth(), firstBitmap.getHeight(), Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(bitmap);
        canvas.drawBitmap(firstBitmap, new Matrix(), null);
        canvas.drawBitmap(secondBitmap, new Matrix(), null);
        return bitmap;
    }

4.3 进行人脸检测

进行检测时直接调用上述的系统API即可完成操作,需要注意的是根据测试,当设置的检测数量大于人脸数量时,有时会直接返回最大数量而非实际数量。

Bitmap bitmap565 = bp.copy(Bitmap.Config.RGB_565, true);
Bitmap newBP = mergeBitmap(bitmap565, getViewBitmap());
FaceDetector face_detector = new FaceDetector(newBP.getWidth(), newBP.getHeight(), 1);
FaceDetector.Face[] faces = new FaceDetector.Face[1];
int face_count = face_detector.findFaces(newBP, faces);
三、结束语

至此Android使用FaceDetector进行人脸识别检测已经可以实现了,本身FaceDetector存在的一些不稳定性和缺陷,我们也可以利用一些程序进行进一步的控制和改良,这样保证我们的结果更加准确。

虽说授人以鱼不如授人以渔,我觉得两则兼有岂不更好,文章demo大家可以点击此处查看~

No.N/FaceDetectorDemo

至于其他的实现方案,本文不再累述,有兴趣的朋友可以自行研究,后续我也会逐步推出相应方案的说明文章,有兴趣的朋友可以持续关注~

通过安卓手机面部识别技术,我们可以更加方便、快捷地解锁我们的手机,保护我们的隐私安全。同时,在支付、社交、游戏等领域也可以有更多的创新应用。随着技术的不断进步,相信该技术会越来越成熟,为我们的生活带来更多的便利。

相关文章

猜你喜欢