Android使用虹软进行人脸检测+使用zxing二维码扫描

时间:2024-04-10 18:20:16

最近项目中有一个比较奇葩的需求,我相信很多人都没有听过这个需求,可能这个需求分开做过,但是合在一起的需求肯定没有做过。那么这个需求是什么呢?

需求:同一个入口进入,先判断是不是人脸,如果是人脸的话,就把人脸的照片截取下来传到后台进行比对。如果不是人脸,要求对二维码进行扫描,当时刚接到这个需求的时候,也是一脸懵逼,还可以这样操作?

这个需求困扰了我好几天,人脸检测倒还可以,通过第三方的SDK可以判断是不是人脸,加上二维码检测就不会写了,两个是共用一个相机,如果两个分开的话,这个需求就很简单了。

人脸检测

人脸检测我用的是虹软的SDK,这个SDK是免费的(如果不需要活体检测,活体检测是收费的),Android端的是有3个版本,分别是1.2、2.0、2.1三个版本,当时这三个版本我都用过,最早是用的2.1版本的,然后不行,2.0也用了,也不行,没法和二维码扫描兼容,最后用的是1.2版本的。1.2版本的,虹软是没有例子的,不过大部分的方法是有的,这个可以根据自己的需求来定制,这个还是非常好的。

一.使用虹软SDK

1.准备工作

①需要先去虹软官网https://ai.arcsoft.com.cn,进行开发者的注册,个人开发者注册是需要上传个人身份证。注册成功以后就可以使用虹软的服务了。

②进入下载界面,点击下载,填写所需要的信息。

Android使用虹软进行人脸检测+使用zxing二维码扫描

③填写完毕后,就会得到很多key,这些key根据项目的需要,看看是否能够用到,点击下载ArcFace v1.2,下载相应的SDK。

Android使用虹软进行人脸检测+使用zxing二维码扫描

④下载完成以后,需要导入依赖包,虹软人脸SDK的包是so包,我们可以在下载的压缩包中把这些文件找到并导入。因为我这里只需要人脸检测功能,不需要识别之类,我只需要导入检测的so包就可以

Android使用虹软进行人脸检测+使用zxing二维码扫描

准备动作到这里差不多就已经完成了,下面就要开始我们的代码的编写了。

代码编写

1.初始化引擎

    public static String FREESDKAPPID = "DB37dp1wuNFxpjdZioe64J5hYJaw8PX44ovK11JxkzVi";
    public static String FDSDKKEY = "EkMaQskfHUqAduqp3a6UdPenb8TgKoupppjXaaHrjrqg";
    public static String FTSDKKEY = "EkMaQskfHUqAduqp3a6UdPenb8TgKoupppjXaaHrjrqg";

 

 ftEngine = new AFT_FSDKEngine();
        int ftInitErrorCode = ftEngine.AFT_FSDK_InitialFaceEngine(APPID,
                FT_SDKKEY, AFT_FSDKEngine.AFT_OPF_0_HIGHER_EXT,
                16, 5).getCode();
        if (ftInitErrorCode != 0) {
            Log.d("FT初始化失败,errorcode:" , ftInitErrorCode+"");
        }

 2.使用相机预览图像,判断获取到的图像是不是人脸,这里我们需要调用AFT_FSDKEngine中的AFT_FSDK_FaceFeatureDetect()方法来获取人脸的位置

List<AFT_FSDKFace> ftFaceList = new ArrayList<>();
        //视频FT检测人脸
        int ftCode = ftEngine.AFT_FSDK_FaceFeatureDetect(data, width, height,
                AFT_FSDKEngine.CP_PAF_NV21, ftFaceList).getCode();
        if (ftCode != AFT_FSDKError.MOK) {
            Log.d("FaceTrackService","AFT_FSDK_FaceFeatureDetect: errorcode "+ftCode);
        }
        return ftFaceList;

3.扫描到人脸以后,画出人脸的位置

  if (svRect == null) {
            return;
        }
        if (svRect != null) {
            Canvas canvas = svRect.getHolder().lockCanvas();
            canvas.drawColor(0, PorterDuff.Mode.CLEAR);

            Paint paint = new Paint();
            paint.setColor(Color.RED);
            paint.setStyle(Paint.Style.FILL);
            paint.setStrokeWidth(5);
            paint.setTextSize(80);

            if (fsdkFaces.size() > 0) {
                for (AFT_FSDKFace aft_fsdkFace : fsdkFaces) {
                    Rect rect = new Rect(aft_fsdkFace.getRect());
                    if (rect != null) {
                        //画人脸框
                        Rect adjustedRect = DrawUtils.adjustRect(rect, faceTrackService.getWidth(),
                                faceTrackService.getHeight(),
                                canvas.getWidth(), canvas.getHeight(), cameraOri, cameraId);
                        DrawUtils.drawFaceRect(canvas, adjustedRect, Color.YELLOW, 5);

                    }

                }
            }
            svRect.getHolder().unlockCanvasAndPost(canvas);
        }

4.将识别到的人脸转成图片展示出来,我这里就不写我那种方式了,比较麻烦。这里我就弄一种相对简单的方法,如果检测到人脸以后,直接把检测到的图片展示出来。

    ByteArrayOutputStream baos;
        byte[] rawImage;
        Bitmap bitmap;
        //处理data
        Camera.Size previewSize = camera.getParameters().getPreviewSize();//获取尺寸,格式转换的时候要用到
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        newOpts.inJustDecodeBounds = true;
        YuvImage yuvimage = new YuvImage(
                data,
                ImageFormat.NV21,
                previewSize.width,
                previewSize.height,
                null);
        baos = new ByteArrayOutputStream();
        yuvimage.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 100, baos);// 80--JPG图片的质量[0-100],100最高
        rawImage = baos.toByteArray();
        //将rawImage转换成bitmap
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        bitmap = BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length, options);
        return bitmap;

如果直接通过BitmapFactory.decodeByteArray这个方法的话,是无法转换的。我们这里要对获取到的data进行预处理。

到这里人脸检测基本就已经完成了,我们的人脸识别是后台来完成的,不需要我们来识别,我们只需要把带有人脸的照片传到后台就可以。
上面我说过这个的需求,如果能够检测到人脸,就通过后台来识别人脸,如果没有检测到人脸,我们就需要通过扫描二维码的方式来进行。

二维码扫描

我们这个二维码扫描的方式比较简单,只需要把预览到的data转成bitmap,然后通过zxing来判断图片中是否存在二维码,存在二维码的话,直接扫描二维码就可以。

预览到的图像转成bitmap,上面那个方法就是,这个方法我就不贴出来了

识别图像中的二维码

1.导入zxing

implementation 'com.google.zxing:core:3.2.1'

2.检测图片中是否存在二维码

Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();
        hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); // 设置二维码内容的编码
        Bitmap scanBitmap = Bitmap.createBitmap(mBitmap);

        int px[] = new int[scanBitmap.getWidth() * scanBitmap.getHeight()];
        scanBitmap.getPixels(px, 0, scanBitmap.getWidth(), 0, 0,
                scanBitmap.getWidth(), scanBitmap.getHeight());
        RGBLuminanceSource source = new RGBLuminanceSource(scanBitmap.getWidth(), scanBitmap.getHeight(), px);
        BinaryBitmap tempBitmap = new BinaryBitmap(new HybridBinarizer(source));
        QRCodeReader reader = new QRCodeReader();
        try {
            return reader.decode(tempBitmap, hints);
        } catch (NotFoundException e) {
            e.printStackTrace();
        } catch (ChecksumException e) {
            e.printStackTrace();
        } catch (FormatException e) {
            e.printStackTrace();
        }

这个方法中reader.decode(tempBitmap,hints)返回Result,而result中的getText()方法就是获取到的二维码的内容。

识别二维码这一块比较简单,就是识别图片中的二维码,基本的就是这些了。

源码我就不贴出来了,涉及到公司的东西,后面我会单独把代码提出来写一个demo,如果有需要的话,可以在下面进行留言。