成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

如何解析利用人臉識(shí)別SDK實(shí)現(xiàn)人證比對(duì)全過(guò)程

這篇文章將為大家詳細(xì)講解有關(guān)如何解析利用人臉識(shí)別SDK實(shí)現(xiàn)人證比對(duì)全過(guò)程,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

10余年的清水河網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開(kāi)發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。全網(wǎng)營(yíng)銷(xiāo)推廣的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整清水河建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無(wú)論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)從事“清水河網(wǎng)站設(shè)計(jì)”,“清水河網(wǎng)站推廣”以來(lái),每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。

人證比對(duì)在如今的社會(huì)中隨處可見(jiàn),如高鐵、飛機(jī)、酒店入住、甚至景區(qū)入口都可以看到各種各樣的人證應(yīng)用,人臉識(shí)別SDK的也如雨后春筍一般層出不窮,如百度、商湯、Face++、虹軟等。在嘗試使用各家的SDK之后,最讓我青睞的要數(shù)虹軟科技的SDK了,最直接的一個(gè)原因就是虹軟承諾永久免費(fèi)。我從2.0版本開(kāi)始就在使用了,實(shí)測(cè)效果確實(shí)不錯(cuò),就在上個(gè)月收到消息ArcFace3.0更新了,作為一個(gè)白嫖黨自然不會(huì)錯(cuò)過(guò)這次的更新,在上手了3.0 之后,發(fā)現(xiàn)ArcFace 3.0有以下新特性。

  • 特征比對(duì)支持比對(duì)模型選擇,有生活照比對(duì)模型人證比對(duì)模型

  • Android平臺(tái)新增64位的SDK

  • 新增了一種圖像數(shù)據(jù)傳入方式

一、ArcFace 3.0 SDK接口變動(dòng)的得與失

接口變動(dòng)的優(yōu)勢(shì):

1.業(yè)務(wù)自由度變高

??以人證 2.0為例,我們只能傳入數(shù)據(jù)、傳出結(jié)果,而一些中間產(chǎn)物,例如人臉特?cái)?shù)據(jù)征就獲取不到了?,F(xiàn)在采用ArcFace 3.0之后,取消了固定的流程,檢測(cè)、比對(duì)、提取等流程都可以由自己控制。

2.可以在同一個(gè)工程內(nèi)實(shí)現(xiàn)生活照比對(duì)與人證比對(duì)

??人證 SDK與ArcFace SDK 存在沖突,無(wú)法同時(shí)使用,若我們既想用人證又想用生活照,就要寫(xiě)兩個(gè)工程,并且兩個(gè)工程的流程還有些不同。而現(xiàn)在只需要接口內(nèi)選擇模型就可以實(shí)現(xiàn)模型的切換,完全可以在一個(gè)工程內(nèi)實(shí)現(xiàn)人證與生活照程序的集成。

3.代碼復(fù)用性

??ArcFace 3.0中人證與身份證區(qū)別只有compare接口中的模型選擇,其他完全一致,因此大部分的代碼都可以復(fù)用,大大提高了開(kāi)發(fā)的效率。

接口變動(dòng)的缺點(diǎn):

1.接口變動(dòng)

??萬(wàn)事有得必有失,由于ArcFace 3.0沒(méi)有關(guān)于人證部分的封裝,致使在升級(jí)過(guò)程中所有的接口都需要變更,相信也是所有程序員都不愿意看到的問(wèn)題。

2.實(shí)現(xiàn)變困難

??同樣由于ArcFace 3.0沒(méi)有關(guān)于人證部分的封裝,使得原本接口中自帶的一些流程與回調(diào)需要自己來(lái)實(shí)現(xiàn),這對(duì)于剛上手的人來(lái)說(shuō),不是十分友好。

小結(jié):

??雖然上面說(shuō)了一些ArcFace 3.0的缺點(diǎn),但是我本人還是很贊成這次的升級(jí),畢竟每個(gè)產(chǎn)品的革新總會(huì)帶來(lái)一些沖擊,但是相對(duì)于這些沖擊來(lái)說(shuō),我相信接口、識(shí)別流程的統(tǒng)一為程序的適用性與業(yè)務(wù)的自由性都提高了,相信對(duì)于人證2.0來(lái)說(shuō)這次“壯士斷腕”的舉措長(zhǎng)遠(yuǎn)來(lái)看是值得的。

二、人證 2.0 Demo集成ArcFace 3.0 SDK

??在上面我們看到了由于接口的變動(dòng),致使人證2.0程序所有的接口都要修改,接下來(lái)我將以 人證2.0  Demo為例,講解一下我是如何使用ArcFace 3.0 SDK進(jìn)行升級(jí)的。

1、人證 2.0 Demo工程配置

??考慮到可能有些用戶對(duì)人證 2.0 Demo不太熟悉,先簡(jiǎn)單介紹一下官方Demo如何配置使用。

如何解析利用人臉識(shí)別SDK實(shí)現(xiàn)人證比對(duì)全過(guò)程
?首先,先將人證引擎如圖所示放入demo內(nèi),接下來(lái)修改Constants內(nèi)的APP_ID與SDK_KEY,APP_ID與SDK_KEY以及人證引擎均由官網(wǎng)的 開(kāi)放平臺(tái)上進(jìn)行獲取。然后在設(shè)備的SDCard根目錄下放置一張命名為“sample.jpg”的圖片做為模擬人證輸入的圖片(圖片路徑可以在MainActivity下的SAMPLE_FACE變量?jī)?nèi)進(jìn)行修改),下圖為配置完畢后運(yùn)行的截圖。

如何解析利用人臉識(shí)別SDK實(shí)現(xiàn)人證比對(duì)全過(guò)程

2.ArcFace 3.0 SDK替換

??首先我們要先獲取ArcFace3.0的SDK,同樣可以在 開(kāi)放平臺(tái)上進(jìn)行獲取。用新的SDK庫(kù)替換掉原本的SDK,替換后的項(xiàng)目目錄如下圖所示

如何解析利用人臉識(shí)別SDK實(shí)現(xiàn)人證比對(duì)全過(guò)程

3.ArcFace3.0接口替換

??上面提到了,由于3.0的全面變更,所有的接口全部都發(fā)生了改變,因此我們要把原本2.0的接口全部替換為3.0。

?3.1 引擎激活:

??激活方面接口參數(shù)沒(méi)有任何變化

人證 2.0 :

IdCardVerifyManager.getInstance().active(Context context, String appId, String sdkKey);

ArcFace 3.0 :

FaceEngine.active(Context context, String appId, String sdkKey);
?3.2 引擎初始化:

??從初始化開(kāi)始,人證 2.0與ArcFace3.0接口有了較大的區(qū)別,人證 2.0有對(duì)Id Card信息與Camera信息監(jiān)聽(tīng),而3.0取消了這個(gè)監(jiān)聽(tīng)機(jī)制,接口內(nèi)的參數(shù)就不一一介紹了, 官方文檔介紹的非常詳細(xì),大家可以去參考一下官方文檔。

人證 2.0 :

IdCardVerifyManager.getInstance().init(Context context, IdCardVerifyListener listener)

ArcFace 3.0 :

FaceEngine.init(Context context, DetectMode detectMode, DetectFaceOrientPriority detectFaceOrientPriority, int detectFaceScaleVal, int detectFaceMaxNum, int combinedMask)
?3.3 激活&初始化demo:

??下面是我對(duì)2.0進(jìn)行替換后的前后代碼,可以給大家做一個(gè)參考:

人證 2.0 :

  private void initEngine() {
        int result = IdCardVerifyManager.getInstance().init(this, idCardVerifyListener);
        LogUtils.dTag(TAG, "initResult: " + result);
        if (result == IdCardVerifyError.MERR_ASF_NOT_ACTIVATED) {
            Executors.newSingleThreadExecutor().execute(new Runnable() {
                @Override
                public void run() {
                    int activeResult = IdCardVerifyManager.getInstance().active(
                            MainActivity.this, APP_ID, SDK_KEY);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            LogUtils.dTag(TAG, "activeResult: " + activeResult);
                            if (activeResult == IdCardVerifyError.OK) {
                                int initResult = IdCardVerifyManager.getInstance().init(
                                        MainActivity.this, idCardVerifyListener);
                                LogUtils.dTag(TAG, "initResult: " + initResult);
                                if (initResult != IdCardVerifyError.OK) {
                                    toast("人證引擎初始化失敗,錯(cuò)誤碼: " + initResult);
                                }
                            } else {
                                toast("人證引擎激活失敗,錯(cuò)誤碼: " + activeResult);
                            }
                        }
                    });
                }
            });
        } else if (result != IdCardVerifyError.OK) {
            toast("人證引擎初始化失敗,錯(cuò)誤碼: " + result);
        }
    }

ArcFace 3.0 :

 private void initEngine() {
        int result = faceEngine.init(this, DetectMode.ASF_DETECT_MODE_VIDEO, DetectFaceOrientPriority.ASF_OP_ALL_OUT, 16, 1,
                FaceEngine.ASF_FACE_DETECT | FaceEngine.ASF_FACE_RECOGNITION);
        LogUtils.dTag(TAG, "initResult: " + result);
        if (result == ErrorInfo.MERR_ASF_NOT_ACTIVATED) {
            Executors.newSingleThreadExecutor().execute(() -> {
                int activeResult = FaceEngine.active(
                        MainActivity.this, Constants.APP_ID, Constants.SDK_KEY);
                runOnUiThread(() -> {
                    LogUtils.dTag(TAG, "activeResult: " + activeResult);
                    if (activeResult == ErrorInfo.MOK) {
                        int initResult = faceEngine.init(this, DetectMode.ASF_DETECT_MODE_VIDEO, DetectFaceOrientPriority.ASF_OP_ALL_OUT, 16, 1,
                                FaceEngine.ASF_FACE_DETECT | FaceEngine.ASF_FACE_RECOGNITION);
                        LogUtils.dTag(TAG, "initResult: " + initResult);
                        if (initResult != ErrorInfo.MOK) {
                            toast("人證引擎初始化失敗,錯(cuò)誤碼: ", initResult));
                        }
                    } else {
                        toast("人證引擎激活失敗,錯(cuò)誤碼: ", activeResult));
                    }
                });
            });
        } else if (result != ErrorInfo.MOK) {
            toast("人證引擎初始化失敗,錯(cuò)誤碼: " , result));
        }
    }
?3.4 證件照部分的識(shí)別及特征提取

??證件照部分我們需要將原本2.0的引擎自帶的圖像處理方法換成3.0包內(nèi)的ArcSoftImageUtil的方法,同時(shí)由于特征提取成功后的回調(diào)監(jiān)聽(tīng)從引擎內(nèi)刪除掉了,所以這個(gè)回調(diào)需要自己來(lái)寫(xiě),這里我偷了一下懶,抄了一下人證 2.0 demo與3.0 demo中均有的faceHelper中的FaceListener作為監(jiān)聽(tīng)回調(diào),當(dāng)然大家也可以自己實(shí)現(xiàn)回調(diào)。

人證 2.0 :

    private void inputIdCard() {
        if (bmp == null) {
            return;
        }
        int width = bmp.getWidth();
        int height = bmp.getHeight();
        //圖像裁剪
        boolean needAdjust = false;
        while (width % 4 != 0) {
            width--;
            needAdjust = true;
        }
        if (height % 2 != 0) {
            height--;
            needAdjust = true;
        }
        if (needAdjust) {
            bmp = ImageUtils.imageCrop(bmp, new Rect(0, 0, width, height));
        }
        //轉(zhuǎn)換為NV21數(shù)據(jù)格式
        byte[] nv21Data = ImageUtils.getNV21(width, height, bmp);
        //身份證圖像數(shù)據(jù)輸入
        DetectFaceResult result = IdCardVerifyManager.getInstance().inputIdCardData(
                nv21Data, width, height);
        LogUtils.dTag(TAG, "inputIdCardData result: " + result.getErrCode());
    }

ArcFace 3.0 :

   private void inputIdCard() {
        if (bmp == null) {
            return;
        }
        //圖像4字節(jié)對(duì)齊 裁剪
        bmp = ArcSoftImageUtil.getAlignedBitmap(bmp, true);
        int width = bmp.getWidth();
        int height = bmp.getHeight();
        //轉(zhuǎn)換為bgr格式
        byte[] bgrData = ArcSoftImageUtil.createImageData(bmp.getWidth(), bmp.getHeight(), ArcSoftImageFormat.BGR24);
        int translateResult = ArcSoftImageUtil.bitmapToImageData(bmp, bgrData, ArcSoftImageFormat.BGR24);
        //轉(zhuǎn)換成功
        if (translateResult == ArcSoftImageUtilError.CODE_SUCCESS) {
            List<FaceInfo> faceInfoList = new ArrayList<>();
            //video模式不適合靜態(tài)圖片檢測(cè),這里新建了一個(gè)idFaceEngine 除了檢測(cè)模式修改為Image其他參數(shù)與faceEngine一樣
            int detectResult = idFaceEngine.detectFaces(bgrData, width, height, FaceEngine.CP_PAF_BGR24, faceInfoList);
            if (detectResult == ErrorInfo.MOK && faceInfoList.size() > 0) {
                //這里的-2為trackID  因?yàn)镃amera與證件照提取共用faceHelper 用trackID區(qū)分是哪邊來(lái)的數(shù)據(jù)
                faceHelper.requestFaceFeature(bgrData, faceInfoList.get(0), width, height, FaceEngine.CP_PAF_BGR24, -2);
            }
        } else {
            LogUtils.dTag(TAG, "translate Error result: " + translateResult);
        }
    }
?3.5 Camera部分的識(shí)別及特征提取

??人證2.0的onPreviewData接口內(nèi)部其實(shí)是存在一個(gè)特征提取保護(hù),即上一個(gè)特征提取未完成前,不能進(jìn)行下一個(gè)特征提取,但是在3.0沒(méi)有外部的封裝了,所以我們要自己來(lái)進(jìn)行特征提取的控制,基礎(chǔ)的策略就是根據(jù)trackId,每一個(gè)trackId若未進(jìn)行提取或提取失敗才會(huì)進(jìn)行特征提取。

人證 2.0 :

   public void onPreview(byte[] nv21, Camera camera) {
                if (faceRectView != null) {
                    faceRectView.clearFaceInfo();
                }
                if (nv21 == null) {
                    return;
                }
                //預(yù)覽數(shù)據(jù)傳入
                DetectFaceResult result = IdCardVerifyManager.getInstance().onPreviewData(nv21,
                        previewSize.width, previewSize.height, true);
                Rect rect = result.getFaceRect();
                if (faceRectView != null && drawHelper != null && rect != null) {
                    //生成實(shí)時(shí)人臉框
                    drawHelper.draw(faceRectView, new DrawInfo(drawHelper.adjustRect(rect), "", Color.YELLOW));
                }
            }

ArcFace 3.0 :

   public void onPreview(byte[] nv21, Camera camera) {
                if (faceRectView != null) {
                    faceRectView.clearFaceInfo();
                }
                if (nv21 == null) {
                    return;
                }
                List<FaceInfo> faceInfoList = new ArrayList<>();
                int ftResult = faceEngine.detectFaces(nv21, previewSize.width, previewSize.height, FaceEngine.CP_PAF_NV21, faceInfoList);
                //人證比對(duì)場(chǎng)景下只有最大人臉有效,因此直接取第一個(gè)人臉即可,若有其他場(chǎng)景可以自行調(diào)整
                if (ftResult == ErrorInfo.MOK && faceInfoList.size() > 0) {
                    Rect rect = faceInfoList.get(0).getRect();
                    if (faceRectView != null && drawHelper != null && rect != null) {
                        drawHelper.draw(faceRectView, new DrawInfo(drawHelper.adjustRect(rect), "", Color.YELLOW));
                    }
                    //等待身份證數(shù)據(jù)準(zhǔn)備完畢后,才開(kāi)始對(duì)Camera的數(shù)據(jù)進(jìn)行特征提取 并根據(jù)trackId防止重復(fù)提取
                    int trackId = faceInfoList.get(0).getFaceId();
                    if (isIdCardReady && requestFeatureStatusMap != null && requestFeatureStatusMap.containsKey(trackId)) {
                        //若一個(gè)人臉提取失敗則進(jìn)行重試
                        if (requestFeatureStatusMap.get(trackId) == null || requestFeatureStatusMap.get(trackId) == RequestFeatureStatus.FAILED) {
                            requestFeatureStatusMap.put(trackId, RequestFeatureStatus.SEARCHING);
                            faceHelper.requestFaceFeature(nv21, faceInfoList.get(0), previewSize.width, previewSize.height, FaceEngine.CP_PAF_NV21, faceInfoList.get(0).getFaceId());
                        }
                    }
                }
            }
? 3.6 camera及idCard數(shù)據(jù)回調(diào)

??上文我們已經(jīng)提到過(guò),人證 2.0的引擎內(nèi)對(duì)camera數(shù)據(jù)idCard數(shù)據(jù)分別有兩個(gè)接口作為區(qū)分,同時(shí)有兩個(gè)回調(diào)函數(shù)分別用于兩個(gè)數(shù)據(jù)的處理。而ArcFace3.0時(shí)不僅取消了回調(diào),而且camera數(shù)據(jù)idCard數(shù)據(jù)共用一個(gè)detect、extractFaceFeature,所以我們可以采用trackId來(lái)作為區(qū)分,并且因?yàn)橐娴淖兓?,引擎?nèi)不再存儲(chǔ)特征值,導(dǎo)致我們需要記錄兩個(gè)數(shù)據(jù)源處獲得的特征值。

人證 2.0 :

 private IdCardVerifyListener idCardVerifyListener = new IdCardVerifyListener() {
        @Override
        public void onPreviewResult(DetectFaceResult detectFaceResult, byte[] bytes, int i, int i1) {
            runOnUiThread(() -> {
                //預(yù)覽人臉特征提取成功
                if (detectFaceResult.getErrCode() == IdCardVerifyError.OK) {
                    isCurrentReady = true;
                    compare();
                }
            });
        }
        @Override
        public void onIdCardResult(DetectFaceResult detectFaceResult, byte[] bytes, int i, int i1) {
            LogUtils.dTag(TAG, "onIdCardResult: " + detectFaceResult.getErrCode());
            runOnUiThread(() -> {
                //身份證人臉特征提取成功
                if (detectFaceResult.getErrCode() == IdCardVerifyError.OK) {
                    isIdCardReady = true;
                    restartHandler.removeCallbacks(restartRunnable);
                    readHandler.postDelayed(readRunnable, READ_DELAY);
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    bmp.compress(Bitmap.CompressFormat.PNG, 80, baos);
                    byte[] bmpBytes = baos.toByteArray();
                    Glide.with(MainActivity.this).load(bmpBytes).into(ivIdCard);
                    compare();
                }
            });
        }
    };

ArcFace 3.0 :

 FaceListener faceListener = new FaceListener() {
            @Override
            public void onFail(Exception e) {
            }
            @Override
            public void onFaceFeatureInfoGet(@Nullable FaceFeature faceFeature, Integer requestId, Integer errorCode, long frTime, byte[] nv21) {
                //特征提取失敗 將比對(duì)狀態(tài)置為失敗
                if (ErrorInfo.MOK != errorCode) {
                    requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED);
                    return;
                }
                //requestId 為-2則為身份證數(shù)據(jù)
                if (requestId == -2) {
                    isIdCardReady = true;
                    //由于接口變更feature不能在引擎內(nèi)存儲(chǔ) 所以用全局變量進(jìn)行存儲(chǔ)
                    idFaceFeature = faceFeature;
                    restartHandler.removeCallbacks(restartRunnable);
                    readHandler.postDelayed(readRunnable, 5000);
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    bmp.compress(Bitmap.CompressFormat.PNG, 100, baos);
                    runOnUiThread(() -> {
                        Glide.with(MainActivity.this).load(bmp).into(ivIdCard);
                        compare();
                    });
                } else {
                    //由于接口變更feature不能在引擎內(nèi)存儲(chǔ) 所以用全局變量進(jìn)行存儲(chǔ)
                    MainActivity.this.faceFeature = faceFeature;
                    isCurrentReady = true;
                    runOnUiThread(() -> {
                        compare();
                    });
                }
            }
        };
? 3.7 compare接口

??比對(duì)接口相對(duì)于之前的來(lái)說(shuō)改動(dòng)就小很多了,只需要注意一下將比對(duì)模式修改為ID_CARD模式即可。

人證 2.0 :

 private void compare() {
        //.......
        //人證特征比對(duì)接口
        CompareResult compareResult = IdCardVerifyManager.getInstance().compareFeature(THRESHOLD);
        LogUtils.dTag(TAG, "compareResult: result " + compareResult.getResult() + ", isSuccess "
                + compareResult.isSuccess() + ", errCode " + compareResult.getErrCode());
        if (compareResult.isSuccess()) {
            playSound(R.raw.compare_success);
            ivCompareResult.setBackgroundResource(R.mipmap.compare_success);
            tvCompareTip.setText(name);
        } else {
            playSound(R.raw.compare_fail);
            ivCompareResult.setBackgroundResource(R.mipmap.compare_fail);
            tvCompareTip.setText(R.string.tip_retry);
        }
        //.......
    }

ArcFace 3.0 :

   private void compare() {
        //.......
        //人證特征比對(duì)接口
        FaceSimilar compareResult = new FaceSimilar();
        faceEngine.compareFaceFeature(idFaceFeature, faceFeature, CompareModel.ID_CARD, compareResult);
        //人證比對(duì)閾值為0.82
        if (compareResult.getScore() > 0.82) {
            playSound(R.raw.compare_success);
            ivCompareResult.setBackgroundResource(R.mipmap.compare_success);
            tvCompareTip.setText(name);
        } else {
            playSound(R.raw.compare_fail);
            ivCompareResult.setBackgroundResource(R.mipmap.compare_fail);
            tvCompareTip.setText(R.string.tip_retry);
        }
        //.......
    }
?3.8 結(jié)果展示

??至此只要將人證 2.0 demo無(wú)用的代碼刪除掉,我們就將2.0成功升級(jí)為3.0了,讓我們看看部隊(duì)成功后的運(yùn)行截圖。

如何解析利用人臉識(shí)別SDK實(shí)現(xiàn)人證比對(duì)全過(guò)程

三、ArcFace 3.0的demo修改為人證程序

??相比較于將人證 2.0升級(jí)為將ArcFace3.0來(lái)說(shuō),直接在將ArcFace3.0版本上進(jìn)行修改可簡(jiǎn)單太多了,畢竟不用將所有的接口全部都更改一遍,我們需要做的就只是增加人證部分的輸入,人證部分的回調(diào)以及比對(duì)的邏輯。因此在這里我強(qiáng)烈推薦直接上手ArcFace3.0,如果不是有特殊原因修改3.0可比人證2.0快太多了。

修改界面選擇

??首先我們要選擇demo中的一個(gè)Activity做為我們修改的模板,我看了一下RegisterAndRecognizeActivity是我認(rèn)為最為合適的了,因?yàn)樗腃amera的比對(duì)流程已經(jīng)全部完成了,我們需要做的就是兩點(diǎn):

  • 增加Id Card數(shù)據(jù)輸入源
    Id Card數(shù)據(jù)輸入源我們采用與人證demo相同的方式模擬證件信息傳入,因此可以完全套用inputIdCard方法。

 public void onClickIdCard(View view) {
        //模擬身份證姓名,可修改
        FileInputStream fis;
        //身份證圖像數(shù)據(jù)
        bmp = null;
        try {
            //模擬身份證圖像數(shù)據(jù)來(lái)源,可修改
            fis = new FileInputStream(SAMPLE_FACE);
            bmp = BitmapFactory.decodeStream(fis);
            fis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        inputIdCard();
    }
    private void inputIdCard() {
        if (bmp == null) {
            return;
        }
        //圖像4字節(jié)對(duì)齊 裁剪
        bmp = ArcSoftImageUtil.getAlignedBitmap(bmp, true);
        int width = bmp.getWidth();
        int height = bmp.getHeight();
        //轉(zhuǎn)換為bgr格式
        byte[] bgrData = ArcSoftImageUtil.createImageData(bmp.getWidth(), bmp.getHeight(), ArcSoftImageFormat.BGR24);
        int translateResult = ArcSoftImageUtil.bitmapToImageData(bmp, bgrData, ArcSoftImageFormat.BGR24);
        //轉(zhuǎn)換成功
        if (translateResult == ArcSoftImageUtilError.CODE_SUCCESS) {
            List<FaceInfo> faceInfoList = new ArrayList<>();
            //video模式不適合靜態(tài)圖片檢測(cè),我們選擇frEngine 作為檢測(cè)證件照的引擎 初始化時(shí)要增加 FaceEngine.ASF_FACE_DETECT 哦
            int detectResult = frEngine.detectFaces(bgrData, width, height, FaceEngine.CP_PAF_BGR24, faceInfoList);
            if (detectResult == ErrorInfo.MOK && faceInfoList.size() > 0) {
                //這里的-2為trackID  因?yàn)镃amera與證件照提取共用faceHelper 用trackID區(qū)分是哪邊來(lái)的數(shù)據(jù)
                faceHelper.requestFaceFeature(bgrData, faceInfoList.get(0), width, height, FaceEngine.CP_PAF_BGR24, -2);
            }
        } else {
            LogUtils.dTag(TAG, "translate Error result: " + translateResult);
        }
    }
  • 修改比對(duì)的底庫(kù)

??由于絕大部分場(chǎng)景下,人證比對(duì)都是1:1進(jìn)行對(duì)比的,因而要在onFaceFeatureInfoGet回調(diào)內(nèi)進(jìn)行調(diào)整。首先通過(guò)我們?cè)谏厦鎖nputIdCard鋪墊的以-2為trackID,作為標(biāo)識(shí)身份證數(shù)據(jù)的手段。其次我們要記錄一下要對(duì)比的身份證feature與camera下的人臉feature信息,這里我們采用全局變量的方式進(jìn)行記錄。最后由于比對(duì)的feature獲取會(huì)有前后順序區(qū)分,我們用一個(gè)狀態(tài)位進(jìn)行記錄(當(dāng)然也可以判斷兩個(gè)feature是否有數(shù)據(jù),對(duì)此數(shù)據(jù)進(jìn)行維護(hù)來(lái)進(jìn)行兩邊數(shù)據(jù)的同步),等待兩邊的數(shù)據(jù)都準(zhǔn)備完畢后,就可以進(jìn)行比對(duì)了。

      public void onFaceFeatureInfoGet(@Nullable final FaceFeature faceFeature, final Integer requestId, final Integer errorCode) {
                //FR成功
                if (faceFeature != null) {
                    //接收身份證數(shù)據(jù)
                    if (requestId == -2) {
                        isIdCardReady = true;
                        //feature用全局變量進(jìn)行存儲(chǔ)
                        idFaceFeature = faceFeature;
                        compare();
                        return;
                    }
//                    Log.i(TAG, "onPreview: fr end = " + System.currentTimeMillis() + " trackId = " + requestId);
                    Integer liveness = livenessMap.get(requestId);
                    //不做活體檢測(cè)的情況,直接搜索
                    if (!livenessDetect) {
                        isCurrentReady = true;
                        //防止對(duì)同一個(gè)人臉進(jìn)行多次特征提取
                        requestFeatureStatusMap.put(requestId, RequestFeatureStatus.SUCCEED);
                        compare();
//                        searchFace(faceFeature, requestId);
                    }
                    //活體檢測(cè)通過(guò),搜索特征
                    else if (liveness != null && liveness == LivenessInfo.ALIVE) {
                        isCurrentReady = true;
                        //防止對(duì)同一個(gè)人臉進(jìn)行多次特征提取
                        RegisterAndRecognizeActivity.this.faceFeature = faceFeature;
                        requestFeatureStatusMap.put(requestId, RequestFeatureStatus.SUCCEED);
                        compare();
//                        searchFace(faceFeature, requestId);
                    }
                    //活體檢測(cè)未出結(jié)果,或者非活體,延遲執(zhí)行該函數(shù)
                    else {
                        //......
                    }
                }
                //特征提取失敗
                else {
                   //.........
                }
            }
            @Override
            public void onFaceLivenessInfoGet(@Nullable LivenessInfo livenessInfo, final Integer requestId, Integer errorCode) {
                //.....
            }
        };
  • compare 函數(shù):

    private void compare() {
        if (isCurrentReady && isIdCardReady) {
            FaceSimilar similar = new FaceSimilar();
            int compareResult = frEngine.compareFaceFeature(idFaceFeature, faceFeature, CompareModel.ID_CARD, similar);
            if (compareResult == ErrorInfo.MOK && similar.getScore() > 0.82) {
                Log.i(TAG, "compare: success");
            } else {
                Log.i(TAG, "compare: fail");
            }
            //比對(duì)完成后重置比對(duì)狀態(tài)
            isIdCardReady = false;
            isCurrentReady = false;
            //給同一個(gè)人臉若比對(duì)后仍想嘗試,允許其進(jìn)行特征提取
            requestFeatureStatusMap.clear();
        }
    }
小結(jié)

??使用ArcFace3.0進(jìn)行修改,可以明顯的感覺(jué)到修改“絲滑”了很多,我們?cè)谠a的基礎(chǔ)上只需要注意Id Card的數(shù)據(jù)輸入,以及比對(duì)前后的邏輯即可,比對(duì)的難度幾乎可以忽略不計(jì),只是簡(jiǎn)單的調(diào)用接口而已。我這里也寫(xiě)的比較簡(jiǎn)單,有些業(yè)務(wù)邏輯如:增加身份證數(shù)據(jù)有效時(shí)間;規(guī)定雙方數(shù)據(jù)強(qiáng)制的先后順序;界面部分的展示都沒(méi)有做,只打印了一下比對(duì)的結(jié)果。本文只提供思路給大家參考,業(yè)務(wù)邏輯還是需要自己添加,最后給大家看一下修改完成后運(yùn)行比對(duì)成功的日志。

如何解析利用人臉識(shí)別SDK實(shí)現(xiàn)人證比對(duì)全過(guò)程

關(guān)于如何解析利用人臉識(shí)別SDK實(shí)現(xiàn)人證比對(duì)全過(guò)程就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

分享文章:如何解析利用人臉識(shí)別SDK實(shí)現(xiàn)人證比對(duì)全過(guò)程
當(dāng)前地址:http://jinyejixie.com/article42/gpedec.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供動(dòng)態(tài)網(wǎng)站、商城網(wǎng)站、電子商務(wù)、網(wǎng)站設(shè)計(jì)公司、網(wǎng)站設(shè)計(jì)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化
石嘴山市| 舒兰市| 辽宁省| 寻甸| 宿州市| 成都市| 崇州市| 龙州县| 桃园市| 永仁县| 盐亭县| 太和县| 温宿县| 遂宁市| 新竹县| 崇州市| 英吉沙县| 灌阳县| 武强县| 宁明县| 镇赉县| 冷水江市| 浦东新区| 邓州市| 皋兰县| 天镇县| 宜兴市| 龙岩市| 高淳县| 大连市| 丹东市| 建昌县| 黄骅市| 霸州市| 略阳县| 中山市| 阳新县| 太仆寺旗| 孙吴县| 焉耆| 保定市|