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开发之虹软人脸识别活体检测基本步骤相关推荐
- Android开发之虹软人脸识别活体检测SDK包Bitmap转NV21方法
/** * Bitmap 转化为 ARGB 数据,再转化为 NV21 数据 * * @param src 传入的 Bitmap,格式为 Bitmap.Config.ARGB_8888 * @param ...
- android bitmap nv21,Android开发之虹软人脸识别活体检测SDK包Bitmap转NV21方法
/** * Bitmap 转化为 ARGB 数据,再转化为 NV21 数据 * * @param src 传入的 Bitmap,格式为 Bitmap.Config.ARGB_8888 * @param ...
- 人脸识别活体检测之张张嘴和眨眨眼
暑 [这段时间有点忙,终于截止今天2018.06.22完成了人脸识别的最后一道程序--活体检测之眨眨眼和张张嘴] 关于人脸识别的内容我之前也写过好几篇博文,其中有: {java实现人脸识别源码} ...
- dlib实现人脸识别+活体检测
目录: 一:dlib的shape_predictor_68_face_landmarks模型 二.眨眼检测 三.张口检测 四.眨眼检测+张口检测 五.人脸识别 六.人脸识别+活体检测 七.人脸识别破解 ...
- 人脸识别--活体检测(眨眼检测)
人脸识别在现在很多的项目中都有应用,最常见的就属此次315曝光的支付宝刷脸登录,当然支付宝也出来做了澄清,我们还是需要相信科技的.支付宝的刷脸可谓是相当成熟了.下面我们来简单的分析一下支付宝的刷脸登录 ...
- 微信公众号人脸识别|活体检测SDK|人证比对API
一.概述 人脸识别特指利用分析比较人脸视觉特征信息进行身份鉴别的计算机技术.人脸识别是一项热门的计算机技术研究领域,可以将人脸明暗侦测,自动调整动态曝光补偿,人脸追踪侦测,自动调整影像放大:它属于生物 ...
- 人脸识别活体检测之张张嘴和眨眨眼——readme
人脸检测返回参数详情 ----------------------------------------------------------------------------------------- ...
- 人脸识别活体检测之张张嘴和眨眨眼——Json_Parsing
/** * @Title: Json_Parsing.java * @Package org.util * @Description: TODO该方法的主要作用: * @author A18ccms ...
- 人脸识别活体检测之张张嘴和眨眨眼——Landmark
/** * @Title: Landmark.java * @Package org.entity * @Description: TODO该方法的主要作用: * @author A18ccms A1 ...
最新文章
- vivo android8公测,vivo 开启安卓P公测不限人数!这四款机型用户别错过了
- Redis查漏补缺:最易错过的技术要点大扫盲
- 直播预告丨数十家平台实战真经,解密 IPTV 数据破局之道
- chromium浏览器_微软将全面向Windows 10用户推送Chromium版Edge浏览器
- python如何安装扩展库openpyxl和numpy_Python第三方库之openpyxl(2)
- 默认选中_双击dwg图纸,怎么设置默认天正打开?
- 组态王调用mysql存储过程_组态王与数据库通讯
- sun8134的Blog
- 正则表达式,小于等于180且大于等于0的浮点型
- 变更日志 批准的变更请求 收尾流程 原型法 名义小组 习题
- 关于“该计算机已安装更高版本的Google Chrome浏览器“问题解决方法
- 锐角三角形的一些结论及证明
- PMP证书,项目经理事业进步的阶梯
- httpclient Post请求 参数用des加密
- apt查看安装包可用版本号
- postma公共变量的设置及使用
- jdk1.8 官网下载 必须注册_【英雄联盟手游】账号注册教程!
- VirtualBox下载、安装,新建虚拟机
- 操作系统---利用“任务管理器”查找病毒
- BookshelfB