feat(face): 集成5.0口罩检测引擎并升级数据库版本
- 将FaceDatabase版本升级至2并添加回退破坏性迁移方案 - FaceHelper中新增maskEngine字段与相关处理逻辑,支持口罩检测 - 更新RecognizeViewModel,初始化和管理口罩检测引擎maskEngine - 在人脸识别流程中使用maskEngine进行口罩检测处理 - 修改ndk配置支持arm64-v8a架构 - 替换项目Gradle和JDK版本为corretto-17 - 优化人脸活体检测代码,移除不再使用的needUpdateFaceData逻辑 - 增加.idea项目设置文件,配置Firebase Crashlytics与设备选择器设置
This commit is contained in:
@@ -13,7 +13,7 @@ android {
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
|
||||
ndk {
|
||||
abiFilters.addAll(listOf("armeabi-v7a"/*, "arm64-v8a"*/))
|
||||
abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -39,7 +39,6 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -104,6 +103,10 @@ public class FaceHelper implements FaceListener {
|
||||
* 活体检测引擎
|
||||
*/
|
||||
private FaceEngine flEngine;
|
||||
/**
|
||||
* 口罩检测引擎(5.0 独立引擎)
|
||||
*/
|
||||
private FaceEngine maskEngine;
|
||||
|
||||
private Camera.Size previewSize;
|
||||
|
||||
@@ -148,11 +151,6 @@ public class FaceHelper implements FaceListener {
|
||||
*/
|
||||
private boolean onlyDetectLiveness;
|
||||
|
||||
/**
|
||||
* 是否需要更新faceData
|
||||
*/
|
||||
private boolean needUpdateFaceData;
|
||||
|
||||
/**
|
||||
* 识别的配置项
|
||||
*/
|
||||
@@ -182,9 +180,9 @@ public class FaceHelper implements FaceListener {
|
||||
}
|
||||
|
||||
private FaceHelper(Builder builder) {
|
||||
needUpdateFaceData = builder.needUpdateFaceData;
|
||||
onlyDetectLiveness = builder.onlyDetectLiveness;
|
||||
ftEngine = builder.ftEngine;
|
||||
maskEngine = builder.maskEngine;
|
||||
trackedFaceCount = builder.trackedFaceCount;
|
||||
previewSize = builder.previewSize;
|
||||
frEngine = builder.frEngine;
|
||||
@@ -352,11 +350,11 @@ public class FaceHelper implements FaceListener {
|
||||
return facePreviewInfoList;
|
||||
}
|
||||
}
|
||||
if (!onlyDetectLiveness) {
|
||||
code = ftEngine.process(rgbNv21, previewSize.width, previewSize.height, FaceEngine.CP_PAF_NV21, faceInfoList,
|
||||
if (!onlyDetectLiveness && maskEngine != null) {
|
||||
code = maskEngine.process(rgbNv21, previewSize.width, previewSize.height, FaceEngine.CP_PAF_NV21, faceInfoList,
|
||||
FaceEngine.ASF_MASK_DETECT);
|
||||
if (code == ErrorInfo.MOK) {
|
||||
code = ftEngine.getMask(maskInfoList);
|
||||
code = maskEngine.getMask(maskInfoList);
|
||||
if (code != ErrorInfo.MOK) {
|
||||
onFail(new Exception("process getMask failed,code is " + code));
|
||||
return facePreviewInfoList;
|
||||
@@ -880,18 +878,7 @@ public class FaceHelper implements FaceListener {
|
||||
int fdCode = flEngine.detectFaces(nv21Data, width, height, format, faceInfoList);
|
||||
boolean isFaceExists = isFaceExists(faceInfoList, faceInfo);
|
||||
if (fdCode == ErrorInfo.MOK && isFaceExists) {
|
||||
if (needUpdateFaceData) {
|
||||
/*
|
||||
* 若IR人脸框有偏移,则需要对IR的人脸数据进行updateFaceData处理,再将处理后的FaceInfo信息传输给活体检测接口
|
||||
*/
|
||||
flCode = flEngine.updateFaceData(nv21Data, previewSize.width, previewSize.height, FaceEngine.CP_PAF_NV21,
|
||||
new ArrayList<>(Collections.singletonList(faceInfo)));
|
||||
if (flCode == ErrorInfo.MOK) {
|
||||
flCode = flEngine.processIr(nv21Data, width, height, format, Arrays.asList(faceInfo), FaceEngine.ASF_IR_LIVENESS);
|
||||
}
|
||||
} else {
|
||||
flCode = flEngine.processIr(nv21Data, width, height, format, Arrays.asList(faceInfo), FaceEngine.ASF_IR_LIVENESS);
|
||||
}
|
||||
flCode = flEngine.processIr(nv21Data, width, height, format, Arrays.asList(faceInfo), FaceEngine.ASF_IR_LIVENESS);
|
||||
} else {
|
||||
onFail(new Exception("ir detectFaces failed fdCode:" + fdCode + ",isFaceExists:" + isFaceExists));
|
||||
}
|
||||
@@ -1098,9 +1085,9 @@ public class FaceHelper implements FaceListener {
|
||||
private FaceEngine ftEngine;
|
||||
private FaceEngine frEngine;
|
||||
private FaceEngine flEngine;
|
||||
private FaceEngine maskEngine;
|
||||
private Camera.Size previewSize;
|
||||
private boolean onlyDetectLiveness;
|
||||
private boolean needUpdateFaceData;
|
||||
private RecognizeConfiguration recognizeConfiguration;
|
||||
private RecognizeCallback recognizeCallback;
|
||||
private IDualCameraFaceInfoTransformer dualCameraFaceInfoTransformer;
|
||||
@@ -1141,6 +1128,11 @@ public class FaceHelper implements FaceListener {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder maskEngine(FaceEngine val) {
|
||||
maskEngine = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder previewSize(Camera.Size val) {
|
||||
previewSize = val;
|
||||
return this;
|
||||
@@ -1166,11 +1158,6 @@ public class FaceHelper implements FaceListener {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder needUpdateFaceData(boolean val) {
|
||||
needUpdateFaceData = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FaceHelper build() {
|
||||
return new FaceHelper(this);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import androidx.room.RoomDatabase;
|
||||
import com.sw.plate.utils.arcface.facedb.dao.FaceDao;
|
||||
import com.sw.plate.utils.arcface.facedb.entity.FaceEntity;
|
||||
|
||||
@Database(entities = {FaceEntity.class}, version = 1, exportSchema = false)
|
||||
@Database(entities = {FaceEntity.class}, version = 2, exportSchema = false)
|
||||
public abstract class FaceDatabase extends RoomDatabase {
|
||||
public abstract FaceDao faceDao();
|
||||
|
||||
@@ -22,7 +22,10 @@ public abstract class FaceDatabase extends RoomDatabase {
|
||||
faceDatabase = Room.databaseBuilder(context, FaceDatabase.class,
|
||||
context.getDatabasePath("faceDB.db").getPath()
|
||||
// context.getExternalFilesDir("database") + File.separator + "faceDB.db"
|
||||
).build();
|
||||
)
|
||||
// 5.0 特征模型不兼容,升级时直接删除旧表重建
|
||||
.fallbackToDestructiveMigration()
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+28
-25
@@ -12,7 +12,6 @@ import androidx.lifecycle.ViewModel;
|
||||
|
||||
import com.arcsoft.face.AgeInfo;
|
||||
import com.arcsoft.face.ErrorInfo;
|
||||
import com.arcsoft.face.FaceAttributeParam;
|
||||
import com.arcsoft.face.FaceEngine;
|
||||
import com.arcsoft.face.FaceInfo;
|
||||
import com.arcsoft.face.GenderInfo;
|
||||
@@ -132,13 +131,14 @@ public class RecognizeViewModel extends ViewModel implements RecognizeCallback {
|
||||
private MutableLiveData<Integer> ftInitCode = new MutableLiveData<>();
|
||||
private MutableLiveData<Integer> frInitCode = new MutableLiveData<>();
|
||||
private MutableLiveData<Integer> flInitCode = new MutableLiveData<>();
|
||||
private MutableLiveData<Integer> maskInitCode = new MutableLiveData<>();
|
||||
|
||||
/**
|
||||
* 人脸操作辅助类,推帧即可,内部会进行特征提取、识别
|
||||
*/
|
||||
private FaceHelper faceHelper;
|
||||
/**
|
||||
* VIDEO模式人脸检测引擎,用于预览帧人脸追踪及图像质量检测
|
||||
* VIDEO模式人脸检测引擎,用于预览帧人脸追踪
|
||||
*/
|
||||
private FaceEngine ftEngine;
|
||||
/**
|
||||
@@ -149,6 +149,10 @@ public class RecognizeViewModel extends ViewModel implements RecognizeCallback {
|
||||
* IMAGE模式活体检测引擎,用于预览帧人脸活体检测
|
||||
*/
|
||||
private FaceEngine flEngine;
|
||||
/**
|
||||
* IMAGE模式口罩检测引擎(5.0 独立引擎)
|
||||
*/
|
||||
private FaceEngine maskEngine;
|
||||
|
||||
private PreviewConfig previewConfig;
|
||||
|
||||
@@ -160,10 +164,6 @@ public class RecognizeViewModel extends ViewModel implements RecognizeCallback {
|
||||
|
||||
private MutableLiveData<CompareResult> recognizeUserId = new MutableLiveData<>();
|
||||
|
||||
/**
|
||||
* 检测ir活体前,是否需要更新faceData
|
||||
*/
|
||||
private boolean needUpdateFaceData;
|
||||
/**
|
||||
* 当前活体检测的检测类型
|
||||
*/
|
||||
@@ -297,22 +297,22 @@ public class RecognizeViewModel extends ViewModel implements RecognizeCallback {
|
||||
.similarThreshold(ConfigUtil.getRecognizeThreshold(context))
|
||||
.imageQualityNoMaskRecognizeThreshold(ConfigUtil.getImageQualityNoMaskRecognizeThreshold(context))
|
||||
.imageQualityMaskRecognizeThreshold(ConfigUtil.getImageQualityMaskRecognizeThreshold(context))
|
||||
.livenessParam(new LivenessParam(ConfigUtil.getRgbLivenessThreshold(context), ConfigUtil.getIrLivenessThreshold(context),
|
||||
ConfigUtil.getLivenessFqThreshold(context)))
|
||||
.livenessParam(new LivenessParam(ConfigUtil.getRgbLivenessThreshold(context), ConfigUtil.getIrLivenessThreshold(context)))
|
||||
.build();
|
||||
int cameraOffsetX = ConfigUtil.getDualCameraHorizontalOffset(context);
|
||||
int cameraOffsetY = ConfigUtil.getDualCameraVerticalOffset(context);
|
||||
needUpdateFaceData = (livenessType == LivenessType.IR && (cameraOffsetX != 0 || cameraOffsetY != 0));
|
||||
|
||||
// 人脸追踪引擎(VIDEO模式,仅检测)
|
||||
ftEngine = new FaceEngine();
|
||||
int ftEngineMask = FaceEngine.ASF_FACE_DETECT | FaceEngine.ASF_MASK_DETECT;
|
||||
int ftEngineMask = FaceEngine.ASF_FACE_DETECT;
|
||||
ftInitCode.postValue(ftEngine.init(context, DetectMode.ASF_DETECT_MODE_VIDEO, ConfigUtil.getFtOrient(context),
|
||||
ConfigUtil.getRecognizeMaxDetectFaceNum(context), ftEngineMask));
|
||||
FaceAttributeParam attributeParam = new FaceAttributeParam(
|
||||
ConfigUtil.getRecognizeEyeOpenThreshold(context), ConfigUtil.getRecognizeMouthCloseThreshold(context),
|
||||
ConfigUtil.getRecognizeWearGlassesThreshold(context));
|
||||
ftEngine.setFaceAttributeParam(attributeParam);
|
||||
|
||||
// 口罩检测引擎(5.0 独立引擎)
|
||||
maskEngine = new FaceEngine();
|
||||
maskInitCode.postValue(maskEngine.init(context, DetectMode.ASF_DETECT_MODE_IMAGE,
|
||||
DetectFaceOrientPriority.ASF_OP_ALL_OUT,
|
||||
ConfigUtil.getRecognizeMaxDetectFaceNum(context), FaceEngine.ASF_MASK_DETECT));
|
||||
|
||||
// 特征提取引擎
|
||||
frEngine = new FaceEngine();
|
||||
int frEngineMask = FaceEngine.ASF_FACE_RECOGNITION;
|
||||
if (enableFaceQualityDetect) {
|
||||
@@ -322,16 +322,13 @@ public class RecognizeViewModel extends ViewModel implements RecognizeCallback {
|
||||
10, frEngineMask));
|
||||
FaceServer.getInstance().initFaceList(context, frEngine, faceCount -> loadFaceList = true, true);
|
||||
|
||||
//启用活体检测时,才初始化活体引擎
|
||||
// 启用活体检测时,才初始化活体引擎
|
||||
if (enableLive) {
|
||||
flEngine = new FaceEngine();
|
||||
int flEngineMask = (livenessType == LivenessType.RGB ? FaceEngine.ASF_LIVENESS : (FaceEngine.ASF_IR_LIVENESS | FaceEngine.ASF_FACE_DETECT));
|
||||
if (needUpdateFaceData) {
|
||||
flEngineMask |= FaceEngine.ASF_UPDATE_FACEDATA;
|
||||
}
|
||||
flInitCode.postValue(flEngine.init(context, DetectMode.ASF_DETECT_MODE_IMAGE,
|
||||
DetectFaceOrientPriority.ASF_OP_ALL_OUT, 10, flEngineMask));
|
||||
LivenessParam livenessParam = new LivenessParam(ConfigUtil.getRgbLivenessThreshold(context), ConfigUtil.getIrLivenessThreshold(context), ConfigUtil.getLivenessFqThreshold(context));
|
||||
LivenessParam livenessParam = new LivenessParam(ConfigUtil.getRgbLivenessThreshold(context), ConfigUtil.getIrLivenessThreshold(context));
|
||||
flEngine.setLivenessParam(livenessParam);
|
||||
}
|
||||
|
||||
@@ -356,19 +353,25 @@ public class RecognizeViewModel extends ViewModel implements RecognizeCallback {
|
||||
if (ftEngine != null) {
|
||||
synchronized (ftEngine) {
|
||||
int ftUnInitCode = ftEngine.unInit();
|
||||
Log.i(TAG, "unInitEngine: " + ftUnInitCode);
|
||||
Log.i(TAG, "unInitEngine ft: " + ftUnInitCode);
|
||||
}
|
||||
}
|
||||
if (maskEngine != null) {
|
||||
synchronized (maskEngine) {
|
||||
int maskUnInitCode = maskEngine.unInit();
|
||||
Log.i(TAG, "unInitEngine mask: " + maskUnInitCode);
|
||||
}
|
||||
}
|
||||
if (frEngine != null) {
|
||||
synchronized (frEngine) {
|
||||
int frUnInitCode = frEngine.unInit();
|
||||
Log.i(TAG, "unInitEngine: " + frUnInitCode);
|
||||
Log.i(TAG, "unInitEngine fr: " + frUnInitCode);
|
||||
}
|
||||
}
|
||||
if (flEngine != null) {
|
||||
synchronized (flEngine) {
|
||||
int flUnInitCode = flEngine.unInit();
|
||||
Log.i(TAG, "unInitEngine: " + flUnInitCode);
|
||||
Log.i(TAG, "unInitEngine fl: " + flUnInitCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -469,7 +472,7 @@ public class RecognizeViewModel extends ViewModel implements RecognizeCallback {
|
||||
.ftEngine(ftEngine)
|
||||
.frEngine(frEngine)
|
||||
.flEngine(flEngine)
|
||||
.needUpdateFaceData(needUpdateFaceData)
|
||||
.maskEngine(maskEngine)
|
||||
.frQueueSize(maxDetectFaceNum)
|
||||
.flQueueSize(maxDetectFaceNum)
|
||||
.previewSize(previewSize)
|
||||
|
||||
Reference in New Issue
Block a user