feat:人脸快速注册
This commit is contained in:
1 parent
c75b441dea
commit
154122a847
7 files changed
+1210
-50
No files matched your search
@@ -86,6 +86,65 @@ public class DataBaseUtils {
|
||||
}
|
||||
}
|
||||
|
||||
// 状态检查专用轻量查询:只读取数量与 sampleId 集合所需列,不加载 faceModel 特征大字段。
|
||||
// face 表把特征以 JSON 文本存在行内(每条约数 KB),SELECT * 全表读取会反复撑爆 2MB
|
||||
// CursorWindow 并把调用线程阻塞数秒;状态一致性比较不需要特征数据。
|
||||
static public List<FaceEntity> getFaceProfiles(Context context, String queryUserId) {
|
||||
List<FaceEntity> result = new ArrayList<>();
|
||||
DatabaseHelper databaseHelper = null;
|
||||
SQLiteDatabase database = null;
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
databaseHelper = new DatabaseHelper(context);
|
||||
database = databaseHelper.getWritableDatabase();
|
||||
String sql = "SELECT userId, sampleId, userName, path FROM face";
|
||||
if (Objects.nonNull(queryUserId) && !Objects.equals(queryUserId, "")) {
|
||||
sql = sql.concat(" WHERE userId = ?");
|
||||
cursor = database.rawQuery(sql, new String[]{queryUserId});
|
||||
} else {
|
||||
cursor = database.rawQuery(sql, null);
|
||||
}
|
||||
Log.i(TAG, "getFaceProfiles,sql:" + sql + ";queryUserId:" + queryUserId + ";");
|
||||
while (cursor.moveToNext()) {
|
||||
int userIdIndex = cursor.getColumnIndex("userId");
|
||||
int sampleIdIndex = cursor.getColumnIndex("sampleId");
|
||||
int userNameIndex = cursor.getColumnIndex("userName");
|
||||
int pathIndex = cursor.getColumnIndex("path");
|
||||
FaceEntity item = new FaceEntity();
|
||||
if (userIdIndex != -1) {
|
||||
item.setUserId(cursor.getString(userIdIndex));
|
||||
}
|
||||
if (sampleIdIndex != -1) {
|
||||
int sampleId = cursor.getInt(sampleIdIndex);
|
||||
item.setSampleId(sampleId);
|
||||
item.setFaceId(sampleId);
|
||||
}
|
||||
if (userNameIndex != -1) {
|
||||
item.setUserName(cursor.getString(userNameIndex));
|
||||
}
|
||||
if (pathIndex != -1) {
|
||||
item.setFaceFilePath(cursor.getString(pathIndex));
|
||||
}
|
||||
result.add(item);
|
||||
}
|
||||
Log.i(TAG, "查询人脸概况成功总数:" + result.size() + ";");
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "查询人脸概况错误error:" + e.getMessage(), e);
|
||||
return result;
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
if (database != null) {
|
||||
database.close();
|
||||
}
|
||||
if (databaseHelper != null) {
|
||||
databaseHelper.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public Boolean updateFaceModel(Context context, FaceEntity faceEntity) {
|
||||
DatabaseHelper databaseHelper = null;
|
||||
SQLiteDatabase database = null;
|
||||
|
||||
+25
-1
@@ -298,7 +298,7 @@ public class FlutterFaceDiscernPlugin implements FlutterPlugin, MethodChannel.Me
|
||||
result.success(FlutterTool.getConfig(context));
|
||||
break;
|
||||
case "getFaceStatus":
|
||||
result.success(FlutterTool.getFaceStatus(context, stringArgument(call, "appId"), stringArgument(call, "activeKey"), stringArgument(call, "sdkKey")));
|
||||
runFaceStatus(call, result);
|
||||
break;
|
||||
case "activateFaceSdk":
|
||||
result.success(FlutterTool.activateFaceSdk(context, stringArgument(call, "appId"), stringArgument(call, "activeKey"), stringArgument(call, "sdkKey")));
|
||||
@@ -344,6 +344,30 @@ public class FlutterFaceDiscernPlugin implements FlutterPlugin, MethodChannel.Me
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 人脸状态查询:引擎空闲时在统一人脸单线程执行器上执行(内部含数据库读取,
|
||||
* 不再占用平台主线程);注册/特征提取/质量审计占线时直接返回轻量状态,
|
||||
* 避免状态查询在执行器队列里等待整库任务完成后才能应答。
|
||||
*/
|
||||
private void runFaceStatus(MethodCall call, MethodChannel.Result result) {
|
||||
String appId = stringArgument(call, "appId");
|
||||
String activeKey = stringArgument(call, "activeKey");
|
||||
String sdkKey = stringArgument(call, "sdkKey");
|
||||
if (FlutterTool.isRegistrationInProgress()) {
|
||||
result.success(FlutterTool.getFaceStatusWhileRegistering(context, appId, activeKey, sdkKey));
|
||||
return;
|
||||
}
|
||||
FACE_EXECUTOR.execute(() -> {
|
||||
try {
|
||||
Map<String, Object> status = FlutterTool.getFaceStatus(context, appId, activeKey, sdkKey);
|
||||
MAIN_HANDLER.post(() -> result.success(status));
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "读取人脸状态失败:" + e.getMessage(), e);
|
||||
MAIN_HANDLER.post(() -> result.error("FACE_STATUS_FAILED", "读取人脸状态失败,请稍后重试", null));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void startRegistrationTask(String userId, MethodChannel.Result result, boolean legacyResult) {
|
||||
if (!FlutterTool.tryStartRegistration()) {
|
||||
result.error("REGISTRATION_IN_PROGRESS", "人脸库正在注册,请稍候", null);
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.flutter.plugins.facediscern.flutter;
|
||||
import static com.arcsoft.face.FaceEngine.activeOnline;
|
||||
import static com.arcsoft.face.FaceEngine.getActiveFileInfo;
|
||||
|
||||
import static io.flutter.plugins.facediscern.database.DataBaseUtils.getFaceProfiles;
|
||||
import static io.flutter.plugins.facediscern.database.DataBaseUtils.getUserFace;
|
||||
import static io.flutter.plugins.facediscern.database.DataBaseUtils.updateFaceModel;
|
||||
|
||||
@@ -115,7 +116,9 @@ public class FlutterTool {
|
||||
|
||||
FaceServer faceServer = FaceServer.getInstance();
|
||||
if (activated) faceServer.init(context);
|
||||
List<FaceEntity> databaseFaces = getUserFace(context, null);
|
||||
// 状态检查只需要数量与 sampleId 集合,走不含 faceModel 大字段的轻量查询,
|
||||
// 避免整库特征 JSON 反序列化把调用线程(主线程)阻塞数秒。
|
||||
List<FaceEntity> databaseFaces = getFaceProfiles(context, null);
|
||||
int databaseCount = databaseFaces.size();
|
||||
int memoryCount = activated && faceServer.isEngineReady() ? Math.max(faceServer.getTotalFaceCount(), 0) : 0;
|
||||
boolean registrationInProgress = REGISTRATION_IN_PROGRESS.get();
|
||||
@@ -147,6 +150,38 @@ public class FlutterTool {
|
||||
return REGISTRATION_IN_PROGRESS.get();
|
||||
}
|
||||
|
||||
// 注册/特征提取/质量审计占线期间的状态查询:只读授权文件与最新进度缓存,
|
||||
// 不触碰 FaceServer 锁也不查数据库,供主线程即时返回,避免在单线程执行器里
|
||||
// 排队等待整库任务完成后才能应答。
|
||||
static Map<String, Object> getFaceStatusWhileRegistering(Context context, String appId, String activeKey, String sdkKey) {
|
||||
updateConfig(appId, activeKey, sdkKey);
|
||||
Map<String, Object> status = new HashMap<>();
|
||||
ActiveFileInfo activeFileInfo = new ActiveFileInfo();
|
||||
int activeCode = getActiveFileInfo(context, activeFileInfo);
|
||||
boolean activated = activeCode == ErrorInfo.MOK;
|
||||
Constants.IS_ACTIVE = activated;
|
||||
Map<String, Object> progress = new HashMap<>(latestRegistrationProgress);
|
||||
int total = progress.get("total") instanceof Number
|
||||
? ((Number) progress.get("total")).intValue() : -1;
|
||||
int registered = progress.get("successCount") instanceof Number
|
||||
? ((Number) progress.get("successCount")).intValue() : -1;
|
||||
status.put("activated", activated);
|
||||
status.put("activationCode", activeCode);
|
||||
status.put("parametersComplete", hasCompleteConfig());
|
||||
status.put("activationStartTime", activated ? activeFileInfo.getStartTime() : "");
|
||||
status.put("activationEndTime", activated ? activeFileInfo.getEndTime() : "");
|
||||
// 引擎正被整库任务占用,本轮一律按未就绪回报;数量用进度缓存近似,-1 表示尚未可知。
|
||||
status.put("engineReady", false);
|
||||
status.put("engineCode", -1);
|
||||
status.put("databaseCount", total);
|
||||
status.put("memoryCount", registered);
|
||||
status.put("registrationInProgress", true);
|
||||
status.put("libraryConsistent", false);
|
||||
status.put("registrationProgress", progress);
|
||||
status.put("lastRegistrationResult", latestRegistrationResult == null ? null : new HashMap<>(latestRegistrationResult));
|
||||
return status;
|
||||
}
|
||||
|
||||
static boolean tryStartRegistration() {
|
||||
return REGISTRATION_IN_PROGRESS.compareAndSet(false, true);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user