Android开发之虹软人脸识别活体检测基本步骤
生活随笔
收集整理的這篇文章主要介紹了
Android开发之虹软人脸识别活体检测基本步骤
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
首先,我簡單說下虹軟的人臉識別基本步驟:
1.你的設置好設置視頻模式方向用于人臉檢測
有如下幾個可設置方向
//設置視頻模式全方向人臉檢測ConfigUtil.setFtOrient(this, FaceEngine.ASF_OP_0_ONLY);ConfigUtil.setFtOrient(this, FaceEngine.ASF_OP_90_ONLY);ConfigUtil.setFtOrient(this, FaceEngine.ASF_OP_180_ONLY);ConfigUtil.setFtOrient(this, FaceEngine.ASF_OP_270_ONLY);ConfigUtil.setFtOrient(this, FaceEngine.ASF_OP_0_HIGHER_EXT);2.以下設置之前記得先獲取相應的權限<相機和讀取SD卡權限>
if (!checkPermissions(NEEDED_PERMISSIONS)) {ActivityCompat.requestPermissions(this, NEEDED_PERMISSIONS, ACTION_REQUEST_PERMISSIONS);return;}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == ACTION_REQUEST_PERMISSIONS) {boolean isAllGranted = true;for (int grantResult : grantResults) {isAllGranted &= (grantResult == PackageManager.PERMISSION_GRANTED);}if (isAllGranted) {//拿到相機個讀取SD卡權限后再激活引擎activeEngine();} else {Toast.makeText(this, R.string.permission_denied, Toast.LENGTH_SHORT).show();}}}3.你的先激活引擎
Observable.create(new ObservableOnSubscribe<Integer>() {@Overridepublic void subscribe(ObservableEmitter<Integer> emitter) throws Exception {FaceEngine faceEngine = new FaceEngine();int activeCode = faceEngine.active(RegisterAndRecognizeActivity.this, Constants.APP_ID, Constants.SDK_KEY);emitter.onNext(activeCode);}}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<Integer>() {@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(Integer activeCode) {if (activeCode == ErrorInfo.MOK) {showToast(getString(R.string.active_success));initEngine();initCamera();if (cameraHelper != null) {//啟動相機cameraHelper.start();}} else if (activeCode == ErrorInfo.MERR_ASF_ALREADY_ACTIVATED) { // showToast(getString(R.string.already_activated));initEngine();initCamera();if (cameraHelper != null) {//啟動相機cameraHelper.start();}} else { // activeCode:94209表示未聯網showToast(getString(R.string.active_failed, activeCode));}}@Overridepublic void onError(Throwable e) {}@Overridepublic void onComplete() {}});4.開始注冊你的人臉到虹軟本地數據庫,為了進行人臉對比,以下是注冊的主要方法
@Overridepublic void onPreview(final byte[] nv21, Camera camera) {if (faceRectView != null) {faceRectView.clearFaceInfo();}List<FacePreviewInfo> facePreviewInfoList = faceHelper.onPreviewFrame(nv21);if (facePreviewInfoList != null && faceRectView != null && drawHelper != null) {List<DrawInfo> drawInfoList = new ArrayList<>();for (int i = 0; i < facePreviewInfoList.size(); i++) {String name = faceHelper.getName(facePreviewInfoList.get(i).getTrackId());drawInfoList.add(new DrawInfo(facePreviewInfoList.get(i).getFaceInfo().getRect(), GenderInfo.UNKNOWN, AgeInfo.UNKNOWN_AGE, LivenessInfo.UNKNOWN,name == null ? String.valueOf(facePreviewInfoList.get(i).getTrackId()) : name));}drawHelper.draw(faceRectView, drawInfoList);}if (registerStatus == REGISTER_STATUS_READY && facePreviewInfoList != null && facePreviewInfoList.size() > 0) {registerStatus = REGISTER_STATUS_PROCESSING;Observable.create(new ObservableOnSubscribe<Boolean>() {@Overridepublic void subscribe(ObservableEmitter<Boolean> emitter) {boolean success = FaceServer.getInstance().register(RegisterAndRecognizeActivity.this, nv21.clone(), previewSize.width, previewSize.height, "registered " + faceHelper.getCurrentTrackId());emitter.onNext(success);}}).subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<Boolean>() {@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(Boolean success) {String result = success ? "人臉注冊成功!" : "人臉注冊失敗!";Toast.makeText(RegisterAndRecognizeActivity.this, result, Toast.LENGTH_SHORT).show();registerStatus = REGISTER_STATUS_DONE;if (success) {//人臉注冊成功,彈框提示,點擊按鈕退出new AlertDialog.Builder(RegisterAndRecognizeActivity.this).setTitle("注冊人臉").setMessage("人臉注冊成功!").setPositiveButton("確定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();finish();}}).show();}}@Overridepublic void onError(Throwable e) {Toast.makeText(RegisterAndRecognizeActivity.this, "人臉注冊失敗了!", Toast.LENGTH_SHORT).show();registerStatus = REGISTER_STATUS_DONE;}@Overridepublic void onComplete() {}});}clearLeftFace(facePreviewInfoList);if (facePreviewInfoList != null && facePreviewInfoList.size() > 0 && previewSize != null) {for (int i = 0; i < facePreviewInfoList.size(); i++) {if (livenessDetect) {livenessMap.put(facePreviewInfoList.get(i).getTrackId(), facePreviewInfoList.get(i).getLivenessInfo().getLiveness());}/*** 對于每個人臉,若狀態為空或者為失敗,則請求FR(可根據需要添加其他判斷以限制FR次數),* FR回傳的人臉特征結果在{@link FaceListener#onFaceFeatureInfoGet(FaceFeature, Integer)}中回傳*/if (requestFeatureStatusMap.get(facePreviewInfoList.get(i).getTrackId()) == null|| requestFeatureStatusMap.get(facePreviewInfoList.get(i).getTrackId()) == RequestFeatureStatus.FAILED) {requestFeatureStatusMap.put(facePreviewInfoList.get(i).getTrackId(), RequestFeatureStatus.SEARCHING);faceHelper.requestFaceFeature(nv21, facePreviewInfoList.get(i).getFaceInfo(), previewSize.width, previewSize.height, FaceEngine.CP_PAF_NV21, facePreviewInfoList.get(i).getTrackId()); // Log.i(TAG, "onPreview: fr start = " + System.currentTimeMillis() + " trackId = " + facePreviewInfoList.get(i).getTrackId());}}}}5.注冊成功后就可以進行人臉比對了
private void searchFace(final FaceFeature frFace, final Integer requestId) {Observable.create(new ObservableOnSubscribe<CompareResult>() {@Overridepublic void subscribe(ObservableEmitter<CompareResult> emitter) { // Log.i(TAG, "subscribe: fr search start = " + System.currentTimeMillis() + " trackId = " + requestId);//下面的人臉比對信息CompareResult compareResult = FaceServer.getInstance().getTopOfFaceLib(frFace); // Log.i(TAG, "subscribe: fr search end = " + System.currentTimeMillis() + " trackId = " + requestId);if (compareResult == null) {emitter.onError(null);} else {emitter.onNext(compareResult);}}}).subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<CompareResult>() {@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(CompareResult compareResult) {if (compareResult == null || compareResult.getUserName() == null) {requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED);faceHelper.addName(requestId, "VISITOR " + requestId);return;}Log.i(TAG, "onNext:查詢到的結果:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(System.currentTimeMillis()) + " trackId = " + requestId + " similar = " + compareResult.getSimilar());if (compareResult.getSimilar() > SIMILAR_THRESHOLD) {boolean isAdded = false;if (compareResultList == null) {requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED);faceHelper.addName(requestId, "VISITOR " + requestId);return;}for (CompareResult compareResult1 : compareResultList) {if (compareResult1.getTrackId() == requestId) {isAdded = true;break;}}if (!isAdded) {//對于多人臉搜索,假如最大顯示數量為 MAX_DETECT_NUM 且有新的人臉進入,則以隊列的形式移除if (compareResultList.size() >= MAX_DETECT_NUM) {compareResultList.remove(0);adapter.notifyItemRemoved(0);}//添加顯示人員時,保存其trackIdcompareResult.setTrackId(requestId);compareResultList.add(compareResult);adapter.notifyItemInserted(compareResultList.size() - 1);}requestFeatureStatusMap.put(requestId, RequestFeatureStatus.SUCCEED);Toast.makeText(RegisterAndRecognizeActivity.this, "人臉比對成功,相似度:" + compareResult.getSimilar(), Toast.LENGTH_LONG).show();//調用下單接口mPresenter.orderDinner(valueParams);faceHelper.addName(requestId, compareResult.getUserName());} else {requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED);faceHelper.addName(requestId, "VISITOR " + requestId);Toast.makeText(RegisterAndRecognizeActivity.this, "人臉比對失敗,相似度:" + compareResult.getSimilar(), Toast.LENGTH_LONG).show();}}@Overridepublic void onError(Throwable e) {requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED);}@Overridepublic void onComplete() {}});}6.也可以進行活體檢測,主要代碼:
final FaceListener faceListener = new FaceListener() {@Overridepublic void onFail(Exception e) {Log.e(TAG, "onFail: " + e.getMessage());}//請求FR的回調@Overridepublic void onFaceFeatureInfoGet(@Nullable final FaceFeature faceFeature, final Integer requestId) {//FR成功if (faceFeature != null) { // Log.i(TAG, "onPreview: fr end = " + System.currentTimeMillis() + " trackId = " + requestId);//不做活體檢測的情況,直接搜索if (!livenessDetect) { // searchFace(faceFeature, requestId);}//活體檢測通過,搜索特征else if (livenessMap.get(requestId) != null && livenessMap.get(requestId) == LivenessInfo.ALIVE) {runOnUiThread(new Runnable() {@Overridepublic void run() {showToast("活體檢測通過");}});if (isComplete) {//確認活體,開始對比searchFace(faceFeature, requestId);} else {//開始注冊if (registerStatus == REGISTER_STATUS_DONE) {registerStatus = REGISTER_STATUS_READY;}}}//活體檢測未出結果,延遲100ms再執行該函數else if (livenessMap.get(requestId) != null && livenessMap.get(requestId) == LivenessInfo.UNKNOWN) {getFeatureDelayedDisposables.add(Observable.timer(WAIT_LIVENESS_INTERVAL, TimeUnit.MILLISECONDS).subscribe(new Consumer<Long>() {@Overridepublic void accept(Long aLong) {onFaceFeatureInfoGet(faceFeature, requestId);}}));}//活體檢測失敗else {runOnUiThread(new Runnable() {@Overridepublic void run() {showToast("活體檢測失敗");}}); // requestFeatureStatusMap.put(requestId, RequestFeatureStatus.NOT_ALIVE);}}//FR 失敗else {requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED);}}};上面的代碼看起來可能很凌亂,我說的只是基本的思路
所以我將核心完整代碼粘貼如下:
RegisterAndRecognizeActivity.java這個是人臉識別,人臉注冊,活體檢測,人臉對比的主要頁面的代碼 import android.Manifest; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Point; import android.hardware.Camera; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.DisplayMetrics; import android.util.Log; import android.view.View; import android.view.ViewTreeObserver; import android.view.WindowManager; import android.widget.CompoundButton; import android.widget.Switch; import android.widget.Toast;import com.arcsoft.face.AgeInfo; import com.arcsoft.face.ErrorInfo; import com.arcsoft.face.FaceEngine; import com.arcsoft.face.FaceFeature; import com.arcsoft.face.GenderInfo; import com.arcsoft.face.LivenessInfo; import com.arcsoft.face.VersionInfo;import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit;import io.reactivex.Observable; import io.reactivex.ObservableEmitter; import io.reactivex.ObservableOnSubscribe; import io.reactivex.Observer; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; import io.reactivex.functions.Consumer; import io.reactivex.schedulers.Schedulers;/*** @author 輕飛揚* 2019年3月7日10:48:09*/ public class RegisterAndRecognizeActivity extends AppCompatActivity implements ViewTreeObserver.OnGlobalLayoutListener {private static final String TAG = "RegisterAndRecognize";private static final int MAX_DETECT_NUM = 10;/*** 當FR成功,活體未成功時,FR等待活體的時間*/private static final int WAIT_LIVENESS_INTERVAL = 50;private CameraHelper cameraHelper;private DrawHelper drawHelper;private Camera.Size previewSize;/*** 優先打開的攝像頭*/private Integer cameraID = Camera.CameraInfo.CAMERA_FACING_FRONT;private FaceEngine faceEngine;private FaceHelper faceHelper;private List<CompareResult> compareResultList;private ShowFaceInfoAdapter adapter;/*** 活體檢測的開關*/private boolean livenessDetect = true;/*** 注冊人臉狀態碼,準備注冊*/private static final int REGISTER_STATUS_READY = 0;/*** 注冊人臉狀態碼,注冊中*/private static final int REGISTER_STATUS_PROCESSING = 1;/*** 注冊人臉狀態碼,注冊結束(無論成功失敗)*/private static final int REGISTER_STATUS_DONE = 2;private int registerStatus = REGISTER_STATUS_DONE;private int afCode = -1;private ConcurrentHashMap<Integer, Integer> requestFeatureStatusMap = new ConcurrentHashMap<>();private ConcurrentHashMap<Integer, Integer> livenessMap = new ConcurrentHashMap<>();private CompositeDisposable getFeatureDelayedDisposables = new CompositeDisposable();/*** 相機預覽顯示的控件,可為SurfaceView或TextureView*/private View previewView;/*** 繪制人臉框的控件*/private FaceRectView faceRectView;private Switch switchLivenessDetect;private static final int ACTION_REQUEST_PERMISSIONS = 0x001;private static final float SIMILAR_THRESHOLD = 0.8F;private Toast toast = null;/*** 所需的所有權限信息*/private static final String[] NEEDED_PERMISSIONS = new String[]{Manifest.permission.CAMERA,Manifest.permission.READ_PHONE_STATE};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//設置視頻模式全方向人臉檢測ConfigUtil.setFtOrient(this, FaceEngine.ASF_OP_0_HIGHER_EXT);setContentView(R.layout.activity_register_and_recognize);//保持亮屏getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {WindowManager.LayoutParams attributes = getWindow().getAttributes();attributes.systemUiVisibility = View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;getWindow().setAttributes(attributes);}// Activity啟動后就鎖定為啟動時的方向switch (getResources().getConfiguration().orientation) {case Configuration.ORIENTATION_PORTRAIT:setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);break;case Configuration.ORIENTATION_LANDSCAPE:setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);break;default:break;}//本地人臉庫初始化FaceServer.getInstance().init(this);previewView = findViewById(R.id.texture_preview);//在布局結束后才做初始化操作previewView.getViewTreeObserver().addOnGlobalLayoutListener(this);faceRectView = findViewById(R.id.face_rect_view);switchLivenessDetect = findViewById(R.id.switch_liveness_detect);switchLivenessDetect.setChecked(livenessDetect);switchLivenessDetect.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {livenessDetect = isChecked;}});RecyclerView recyclerShowFaceInfo = findViewById(R.id.recycler_view_person);compareResultList = new ArrayList<>();adapter = new ShowFaceInfoAdapter(compareResultList, this);recyclerShowFaceInfo.setAdapter(adapter);DisplayMetrics dm = getResources().getDisplayMetrics();int spanCount = (int) (dm.widthPixels / (getResources().getDisplayMetrics().density * 100 + 0.5f));recyclerShowFaceInfo.setLayoutManager(new GridLayoutManager(this, spanCount));recyclerShowFaceInfo.setItemAnimator(new DefaultItemAnimator());}private void showToast(String s) {if (toast == null) {toast = Toast.makeText(this, s, Toast.LENGTH_SHORT);toast.show();} else {toast.setText(s);toast.show();}}/*** 初始化引擎*/private void initEngine() {faceEngine = new FaceEngine();afCode = faceEngine.init(this, FaceEngine.ASF_DETECT_MODE_VIDEO, ConfigUtil.getFtOrient(this),16, MAX_DETECT_NUM, FaceEngine.ASF_FACE_RECOGNITION | FaceEngine.ASF_FACE_DETECT | FaceEngine.ASF_LIVENESS);VersionInfo versionInfo = new VersionInfo();faceEngine.getVersion(versionInfo);Log.i(TAG, "initEngine: init: " + afCode + " version:" + versionInfo);if (afCode != ErrorInfo.MOK) {Toast.makeText(this, getString(R.string.init_failed, afCode), Toast.LENGTH_SHORT).show();}}/*** 銷毀引擎*/private void unInitEngine() {if (afCode == ErrorInfo.MOK) {afCode = faceEngine.unInit();Log.i(TAG, "unInitEngine: " + afCode);}}@Overrideprotected void onDestroy() {if (cameraHelper != null) {cameraHelper.release();cameraHelper = null;}//faceHelper中可能會有FR耗時操作仍在執行,加鎖防止crashif (faceHelper != null) {synchronized (faceHelper) {unInitEngine();}ConfigUtil.setTrackId(this, faceHelper.getCurrentTrackId());faceHelper.release();} else {unInitEngine();}if (getFeatureDelayedDisposables != null) {getFeatureDelayedDisposables.dispose();getFeatureDelayedDisposables.clear();}FaceServer.getInstance().unInit();super.onDestroy();}private boolean checkPermissions(String[] neededPermissions) {if (neededPermissions == null || neededPermissions.length == 0) {return true;}boolean allGranted = true;for (String neededPermission : neededPermissions) {allGranted &= ContextCompat.checkSelfPermission(this, neededPermission) == PackageManager.PERMISSION_GRANTED;}return allGranted;}private void initCamera() {DisplayMetrics metrics = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(metrics);final FaceListener faceListener = new FaceListener() {@Overridepublic void onFail(Exception e) {Log.e(TAG, "onFail: " + e.getMessage());}//請求FR的回調@Overridepublic void onFaceFeatureInfoGet(@Nullable final FaceFeature faceFeature, final Integer requestId) {//FR成功if (faceFeature != null) { // Log.i(TAG, "onPreview: fr end = " + System.currentTimeMillis() + " trackId = " + requestId);//不做活體檢測的情況,直接搜索if (!livenessDetect) {searchFace(faceFeature, requestId);}//活體檢測通過,搜索特征else if (livenessMap.get(requestId) != null && livenessMap.get(requestId) == LivenessInfo.ALIVE) {runOnUiThread(new Runnable() {@Overridepublic void run() {showToast("活體檢測通過");}});searchFace(faceFeature, requestId);}//活體檢測未出結果,延遲100ms再執行該函數else if (livenessMap.get(requestId) != null && livenessMap.get(requestId) == LivenessInfo.UNKNOWN) {getFeatureDelayedDisposables.add(Observable.timer(WAIT_LIVENESS_INTERVAL, TimeUnit.MILLISECONDS).subscribe(new Consumer<Long>() {@Overridepublic void accept(Long aLong) {onFaceFeatureInfoGet(faceFeature, requestId);}}));}//活體檢測失敗else {runOnUiThread(new Runnable() {@Overridepublic void run() {showToast("活體檢測失敗");}});requestFeatureStatusMap.put(requestId, RequestFeatureStatus.NOT_ALIVE);}}//FR 失敗else {requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED);}}};CameraListener cameraListener = new CameraListener() {@Overridepublic 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);faceHelper = new FaceHelper.Builder().faceEngine(faceEngine).frThreadNum(MAX_DETECT_NUM).previewSize(previewSize).faceListener(faceListener).currentTrackId(ConfigUtil.getTrackId(RegisterAndRecognizeActivity.this.getApplicationContext())).build();}@Overridepublic void onPreview(final byte[] nv21, Camera camera) {if (faceRectView != null) {faceRectView.clearFaceInfo();}List<FacePreviewInfo> facePreviewInfoList = faceHelper.onPreviewFrame(nv21);if (facePreviewInfoList != null && faceRectView != null && drawHelper != null) {List<DrawInfo> drawInfoList = new ArrayList<>();for (int i = 0; i < facePreviewInfoList.size(); i++) {String name = faceHelper.getName(facePreviewInfoList.get(i).getTrackId());drawInfoList.add(new DrawInfo(facePreviewInfoList.get(i).getFaceInfo().getRect(), GenderInfo.UNKNOWN, AgeInfo.UNKNOWN_AGE, LivenessInfo.UNKNOWN,name == null ? String.valueOf(facePreviewInfoList.get(i).getTrackId()) : name));}drawHelper.draw(faceRectView, drawInfoList);}if (registerStatus == REGISTER_STATUS_READY && facePreviewInfoList != null && facePreviewInfoList.size() > 0) {registerStatus = REGISTER_STATUS_PROCESSING;Observable.create(new ObservableOnSubscribe<Boolean>() {@Overridepublic void subscribe(ObservableEmitter<Boolean> emitter) {boolean success = FaceServer.getInstance().register(RegisterAndRecognizeActivity.this, nv21.clone(), previewSize.width, previewSize.height, "registered " + faceHelper.getCurrentTrackId());emitter.onNext(success);}}).subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<Boolean>() {@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(Boolean success) {String result = success ? "register success!" : "register failed!";Toast.makeText(RegisterAndRecognizeActivity.this, result, Toast.LENGTH_SHORT).show();registerStatus = REGISTER_STATUS_DONE;}@Overridepublic void onError(Throwable e) {Toast.makeText(RegisterAndRecognizeActivity.this, "register failed!", Toast.LENGTH_SHORT).show();registerStatus = REGISTER_STATUS_DONE;}@Overridepublic void onComplete() {}});}clearLeftFace(facePreviewInfoList);if (facePreviewInfoList != null && facePreviewInfoList.size() > 0 && previewSize != null) {for (int i = 0; i < facePreviewInfoList.size(); i++) {if (livenessDetect) {livenessMap.put(facePreviewInfoList.get(i).getTrackId(), facePreviewInfoList.get(i).getLivenessInfo().getLiveness());}/*** 對于每個人臉,若狀態為空或者為失敗,則請求FR(可根據需要添加其他判斷以限制FR次數),* FR回傳的人臉特征結果在{@link FaceListener#onFaceFeatureInfoGet(FaceFeature, Integer)}中回傳*/if (requestFeatureStatusMap.get(facePreviewInfoList.get(i).getTrackId()) == null|| requestFeatureStatusMap.get(facePreviewInfoList.get(i).getTrackId()) == RequestFeatureStatus.FAILED) {requestFeatureStatusMap.put(facePreviewInfoList.get(i).getTrackId(), RequestFeatureStatus.SEARCHING);faceHelper.requestFaceFeature(nv21, facePreviewInfoList.get(i).getFaceInfo(), previewSize.width, previewSize.height, FaceEngine.CP_PAF_NV21, facePreviewInfoList.get(i).getTrackId()); // Log.i(TAG, "onPreview: fr start = " + System.currentTimeMillis() + " trackId = " + facePreviewInfoList.get(i).getTrackId());}}}}@Overridepublic void onCameraClosed() {Log.i(TAG, "onCameraClosed: ");}@Overridepublic void onCameraError(Exception e) {Log.i(TAG, "onCameraError: " + e.getMessage());}@Overridepublic void onCameraConfigurationChanged(int cameraID, int displayOrientation) {if (drawHelper != null) {drawHelper.setCameraDisplayOrientation(displayOrientation);}Log.i(TAG, "onCameraConfigurationChanged: " + cameraID + " " + displayOrientation);}};cameraHelper = new CameraHelper.Builder().previewViewSize(new Point(previewView.getMeasuredWidth(), previewView.getMeasuredHeight())).rotation(getWindowManager().getDefaultDisplay().getRotation()).specificCameraId(cameraID != null ? cameraID : Camera.CameraInfo.CAMERA_FACING_FRONT).isMirror(false).previewOn(previewView).cameraListener(cameraListener).build();cameraHelper.init();}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == ACTION_REQUEST_PERMISSIONS) {boolean isAllGranted = true;for (int grantResult : grantResults) {isAllGranted &= (grantResult == PackageManager.PERMISSION_GRANTED);}if (isAllGranted) {initEngine();initCamera();if (cameraHelper != null) {cameraHelper.start();}} else {Toast.makeText(this, R.string.permission_denied, Toast.LENGTH_SHORT).show();}}}/*** 刪除已經離開的人臉** @param facePreviewInfoList 人臉和trackId列表*/private void clearLeftFace(List<FacePreviewInfo> facePreviewInfoList) {Set<Integer> keySet = requestFeatureStatusMap.keySet();if (compareResultList != null) {for (int i = compareResultList.size() - 1; i >= 0; i--) {if (!keySet.contains(compareResultList.get(i).getTrackId())) {compareResultList.remove(i);adapter.notifyItemRemoved(i);}}}if (facePreviewInfoList == null || facePreviewInfoList.size() == 0) {requestFeatureStatusMap.clear();livenessMap.clear();return;}for (Integer integer : keySet) {boolean contained = false;for (FacePreviewInfo facePreviewInfo : facePreviewInfoList) {if (facePreviewInfo.getTrackId() == integer) {contained = true;break;}}if (!contained) {requestFeatureStatusMap.remove(integer);livenessMap.remove(integer);}}}private void searchFace(final FaceFeature frFace, final Integer requestId) {Observable.create(new ObservableOnSubscribe<CompareResult>() {@Overridepublic void subscribe(ObservableEmitter<CompareResult> emitter) { // Log.i(TAG, "subscribe: fr search start = " + System.currentTimeMillis() + " trackId = " + requestId);//下面的人臉比對信息CompareResult compareResult = FaceServer.getInstance().getTopOfFaceLib(frFace); // Log.i(TAG, "subscribe: fr search end = " + System.currentTimeMillis() + " trackId = " + requestId);if (compareResult == null) {emitter.onError(null);} else {emitter.onNext(compareResult);}}}).subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<CompareResult>() {@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(CompareResult compareResult) {if (compareResult == null || compareResult.getUserName() == null) {requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED);faceHelper.addName(requestId, "VISITOR " + requestId);return;}Log.i(TAG, "onNext:查詢到的結果:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(System.currentTimeMillis()) + " trackId = " + requestId + " similar = " + compareResult.getSimilar());if (compareResult.getSimilar() > SIMILAR_THRESHOLD) {boolean isAdded = false;if (compareResultList == null) {requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED);faceHelper.addName(requestId, "VISITOR " + requestId);return;}for (CompareResult compareResult1 : compareResultList) {if (compareResult1.getTrackId() == requestId) {isAdded = true;break;}}if (!isAdded) {//對于多人臉搜索,假如最大顯示數量為 MAX_DETECT_NUM 且有新的人臉進入,則以隊列的形式移除if (compareResultList.size() >= MAX_DETECT_NUM) {compareResultList.remove(0);adapter.notifyItemRemoved(0);}//添加顯示人員時,保存其trackIdcompareResult.setTrackId(requestId);compareResultList.add(compareResult);adapter.notifyItemInserted(compareResultList.size() - 1);}requestFeatureStatusMap.put(requestId, RequestFeatureStatus.SUCCEED);Toast.makeText(RegisterAndRecognizeActivity.this, "人臉比對成功,相似度:" + compareResult.getSimilar(), Toast.LENGTH_LONG).show();faceHelper.addName(requestId, compareResult.getUserName());} else {requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED);faceHelper.addName(requestId, "VISITOR " + requestId);Toast.makeText(RegisterAndRecognizeActivity.this, "人臉比對失敗,相似度:" + compareResult.getSimilar(), Toast.LENGTH_LONG).show();}}@Overridepublic void onError(Throwable e) {requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED);}@Overridepublic void onComplete() {}});}/*** 將準備注冊的狀態置為{@link #REGISTER_STATUS_READY}** @param view 注冊按鈕*/public void register(View view) {if (registerStatus == REGISTER_STATUS_DONE) {registerStatus = REGISTER_STATUS_READY;}}/*** 在{@link #previewView}第一次布局完成后,去除該監聽,并且進行引擎和相機的初始化*/@Overridepublic void onGlobalLayout() {previewView.getViewTreeObserver().removeOnGlobalLayoutListener(this);if (!checkPermissions(NEEDED_PERMISSIONS)) {ActivityCompat.requestPermissions(this, NEEDED_PERMISSIONS, ACTION_REQUEST_PERMISSIONS);} else {initEngine();initCamera();}} }mainactivity.java請求權限和激活引擎頁面
import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Toast;import com.arcsoft.face.ErrorInfo; import com.arcsoft.face.FaceEngine;import io.reactivex.Observable; import io.reactivex.ObservableEmitter; import io.reactivex.ObservableOnSubscribe; import io.reactivex.Observer; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers;/*** @author DELL*/ public class MainActivity extends AppCompatActivity {private Toast toast = null;private static final int ACTION_REQUEST_PERMISSIONS = 0x001;/*** 所需的所有權限信息*/private static final String[] NEEDED_PERMISSIONS = new String[]{Manifest.permission.CAMERA,Manifest.permission.READ_PHONE_STATE};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void requestPermission(View view) {if (!checkPermissions(NEEDED_PERMISSIONS)) {ActivityCompat.requestPermissions(this, NEEDED_PERMISSIONS, ACTION_REQUEST_PERMISSIONS);return;}activeEngine();}/*** 激活引擎*/private void activeEngine() {Observable.create(new ObservableOnSubscribe<Integer>() {@Overridepublic void subscribe(ObservableEmitter<Integer> emitter) throws Exception {FaceEngine 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>() {@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(Integer activeCode) {if (activeCode == ErrorInfo.MOK) {showToast(getString(R.string.active_success));//跳轉頁面goToFaceIdentification();} else if (activeCode == ErrorInfo.MERR_ASF_ALREADY_ACTIVATED) { // showToast(getString(R.string.already_activated));goToFaceIdentification();} else { // activeCode:94209表示未聯網showToast(getString(R.string.active_failed, activeCode));}}@Overridepublic void onError(Throwable e) {}@Overridepublic void onComplete() {}});}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == ACTION_REQUEST_PERMISSIONS) {boolean isAllGranted = true;for (int grantResult : grantResults) {isAllGranted &= (grantResult == PackageManager.PERMISSION_GRANTED);}if (isAllGranted) {//激活引擎activeEngine();} else {Toast.makeText(this, R.string.permission_denied, Toast.LENGTH_SHORT).show();}}}private void showToast(String s) {if (toast == null) {toast = Toast.makeText(this, s, Toast.LENGTH_SHORT);toast.show();} else {toast.setText(s);toast.show();}}private boolean checkPermissions(String[] neededPermissions) {if (neededPermissions == null || neededPermissions.length == 0) {return true;}boolean allGranted = true;for (String neededPermission : neededPermissions) {allGranted &= ContextCompat.checkSelfPermission(this, neededPermission) == PackageManager.PERMISSION_GRANTED;}return allGranted;}/*** 打打開人臉識別的方法(注冊)*/private void goToFaceIdentification() {Intent intent = new Intent(MainActivity.this, RegisterAndRecognizeActivity.class);startActivity(intent);} }可以下載我的安裝包體驗下:???????
鏈接: https://pan.baidu.com/s/1tKevp5huoJOlKPU-cwhj5g 提取碼: 2yyj 復制這段內容后打開百度網盤手機App,操作更方便哦
體驗完apk后可以下載源碼:點擊下載(注意: 解壓后是導入module,不是導入project!!!!!)
總結
以上是生活随笔為你收集整理的Android开发之虹软人脸识别活体检测基本步骤的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 估算概算预算结算决算的区别和联系
- 下一篇: 富士胶片发布 Instax Mini 1