zoukankan      html  css  js  c++  java
  • 人脸识别(基于ArcFace)

     我们先来看看效果

    上面是根据图片检测出其中的人脸、每个人脸的年龄还有性别,非常强大

    第一步:

    登录https://ai.arcsoft.com.cn/,注册开发者账号,身份认证,注册应用,得到APPID和SDKKEY

    第二步:

    阅读SDK接入文档https://ai.arcsoft.com.cn/manual/arcface_android_guideV2.html

    其中重要的是下面

    Step1:调用FaceEngine的active方法激活设备,一个设备安装后仅需激活一次,卸载重新安装后需要重新激活。
    
    Step2:调用FaceEngine的init方法初始化SDK,初始化成功后才能进一步使用SDK的功能。
    
    Step3:调用FaceEngine的detectFaces方法进行图像数据或预览数据的人脸检测,若检测成功,则可得到一个人脸列表。(初始化时combineMask需要ASF_FACE_DETECT)
    
    Step4:调用FaceEngine的extractFaceFeature方法可对图像中指定的人脸进行特征提取。(初始化时combineMask需要ASF_FACE_RECOGNITION)
    
    Step5:调用FaceEngine的compareFaceFeature方法可对传入的两个人脸特征进行比对,获取相似度。(初始化时combineMask需要ASF_FACE_RECOGNITION)
    
    Step6:调用FaceEngine的process方法,传入不同的combineMask组合可对Age、Gender、Face3Dangle、Liveness进行检测,传入的combineMask的任一属性都需要在init时进行初始化。
    
    Step7:调用FaceEngine的getAge、getGender、getFace3Dangle、getLiveness方法可获取年龄、性别、三维角度、活体检测结果,且每个结果在获取前都需要在process中进行处理。
    
    Step8:调用FaceEngine的unInit方法销毁引擎。在init成功后如不unInit会导致内存泄漏。

    引擎一定要先激活,只需激活一次,然后初始化,接着就选择你需要的方法调用,step3-step7选择其中一个调用即可,最后的最后一定要销毁引擎

    贴出核心代码:

    /**
     * 激活引擎
     */
    public void activeEngine() {
        if (!checkPermissions(NEEDED_PERMISSIONS)) {
            ActivityCompat.requestPermissions(this, NEEDED_PERMISSIONS, ACTION_REQUEST_PERMISSIONS);
            return;
        }
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                faceEngine = new FaceEngine();
                int activeCode = faceEngine.active(MainActivity.this, Constants.APP_ID, Constants.SDK_KEY);
                emitter.onNext(activeCode);
            }
        })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Integer>() {
                    @Override
                    public void onSubscribe(Disposable d) {
    
                    }
    
                    @Override
                    public void onNext(Integer activeCode) {
                        if (activeCode == ErrorInfo.MOK) {
                            showToast(getString(R.string.active_success));
                        } else if (activeCode == ErrorInfo.MERR_ASF_ALREADY_ACTIVATED) {
                            showToast(getString(R.string.already_activated));
                        } else {
                            showToast(getString(R.string.active_failed, activeCode));
                        }
                    }
    
                    @Override
                    public void onError(Throwable e) {
    
                    }
    
                    @Override
                    public void onComplete() {
    
                    }
                });
    }
    /**
      * 初始化引擎
      **/
    private void initEngine() {
        faceEngineCode = faceEngine.init(this, FaceEngine.ASF_DETECT_MODE_IMAGE, FaceEngine.ASF_OP_0_HIGHER_EXT,
                16, 10, FaceEngine.ASF_FACE_RECOGNITION | FaceEngine.ASF_FACE_DETECT | FaceEngine.ASF_AGE | FaceEngine.ASF_GENDER | FaceEngine.ASF_FACE3DANGLE | FaceEngine.ASF_LIVENESS);
        VersionInfo versionInfo = new VersionInfo();
        faceEngine.getVersion(versionInfo);
    
        if (faceEngineCode != ErrorInfo.MOK) {
            showToast(getString(R.string.init_failed, faceEngineCode));
        }
    }
    //bitmap转bgr
    byte[] bgr24 = ImageUtil.bitmapToBgr(bitmap);
    
    if (bgr24 == null) {
        clearDialog();
        showToast("图片转化失败");
        return;
    }
    
    /**
     * 2.成功获取到了BGR24 数据,开始人脸检测
     */
    List<FaceInfo> faceInfoList = new ArrayList<>();
    faceEngine.detectFaces(bgr24, width, height, FaceEngine.CP_PAF_BGR24, faceInfoList);
    if (faceInfoList.size() == 0) {
        clearDialog();
        showToast("没有检测到人脸");
        startActivity(new Intent(this, MainActivity.class));
    }
    if (faceInfoList.size() > 1) {
        clearDialog();
        showToast("请不要同时出现多个人脸");
        startActivity(new Intent(this, MainActivity.class));
    }
    if (faceInfoList.size() == 1) {
        clearDialog();
        FaceInfo faceInfo = faceInfoList.get(0);
        //得到人脸的宽和高
        final int faceWidth = faceInfo.getRect().width();
        final int faceHeight = faceInfo.getRect().height();
        makeFace();
    }

    我这里只做了识别人脸,其他的功能可以参考官网的Demo

    多次调用ImageView.setImageResource方法,我在开发过程中遇到了OOM,因为这些加载图片的方法最终都是通过java层的createBitmap来完成的,需要消耗很多内存

    可以采用BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的source。decedeStream最大的秘密在于其直接调用JNI>>nativeDecideAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间

    /**
     * 此方法是为了防止内存溢出
     */
    private BitmapDrawable getBitmap(int resId) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        options.inPurgeable = true;
        options.inInputShareable = true;
        InputStream is = getResources().openRawResource(resId);
        Bitmap bitmap = BitmapFactory.decodeStream(is, null, options);
        try {
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new BitmapDrawable(getResources(), bitmap);
    }

    欢迎关注我的微信公众号:安卓圈

  • 相关阅读:
    Http方法:Get请求与Post请求的区别
    udev和rules使用规则
    c++中的动态内存分配
    c++中重载运算符
    c++中静态成员函数
    c++中值传递,址传递,引用传递
    c++中实现单例模式singleton class
    [Windows篇] 在windows 10上源码编译gtest 并编写CMakeLists.txt
    [Ubuntu篇] 在ubuntu上源码编译gtest,编写gtest-config.cmake并测试
    使用boost data_time模块来获取毫秒级时间并转换为string字符串
  • 原文地址:https://www.cnblogs.com/anni-qianqian/p/10945166.html
Copyright © 2011-2022 走看看