2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
package com.facesdk.wrapper;
|
|
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
import android.content.Context;
|
|
|
|
|
import android.content.res.AssetManager;
|
|
|
|
|
import android.graphics.Bitmap;
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
|
import java.io.OutputStream;
|
|
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
public class FaceSDKWrapper {
|
|
|
|
|
|
|
|
|
|
private static final String TAG = "FaceSDKWrapper";
|
|
|
|
|
|
|
|
|
|
static {
|
|
|
|
|
try {
|
2025-11-17 15:54:25 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
System.loadLibrary("c++_shared");
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
System.loadLibrary("onnxruntime");
|
|
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
System.loadLibrary("opencv_java4");
|
|
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
System.loadLibrary("face_sdk_jni");
|
|
|
|
|
|
|
|
|
|
} catch (UnsatisfiedLinkError e) {
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
Log.e(TAG, "!!! 致命错误: 无法加载一个或多个 Native 库 !!!", e);
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
throw new RuntimeException("Failed to load native libraries", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
|
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
private native long nativeInit(String modelDir);
|
|
|
|
|
private native float[] nativeExtractFeature(Bitmap bitmap);
|
|
|
|
|
private native float nativeCompare(float[] feat1, float[] feat2);
|
|
|
|
|
private native void nativeRelease();
|
|
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
private long nativeHandle = 0;
|
|
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
public boolean init(Context context) {
|
|
|
|
|
if (nativeHandle != 0) {
|
|
|
|
|
Log.w(TAG, "SDK already initialized.");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
String modelPath = copyModelsFromAssets(context);
|
|
|
|
|
if (modelPath == null) {
|
|
|
|
|
Log.e(TAG, "Failed to copy models from assets.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
try {
|
|
|
|
|
this.nativeHandle = nativeInit(modelPath);
|
|
|
|
|
if (this.nativeHandle == 0) {
|
|
|
|
|
Log.e(TAG, "JNI nativeInit() returned 0 (Init failed).");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e(TAG, "Exception during nativeInit()", e);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log.i(TAG, "SDK Initialized successfully. Handle: " + this.nativeHandle);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
public float[] extractFeature(Bitmap bitmap) {
|
|
|
|
|
if (nativeHandle == 0) {
|
|
|
|
|
Log.e(TAG, "SDK not initialized. Call init() first.");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
if (bitmap == null) {
|
|
|
|
|
Log.e(TAG, "Input bitmap is null.");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
return nativeExtractFeature(bitmap);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e(TAG, "Exception during nativeExtractFeature()", e);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
public float compare(float[] feat1, float[] feat2) {
|
|
|
|
|
if (nativeHandle == 0) {
|
|
|
|
|
Log.e(TAG, "SDK not initialized.");
|
2025-11-17 15:54:25 +08:00
|
|
|
return -2.0f;
|
2025-10-31 13:59:24 +08:00
|
|
|
}
|
|
|
|
|
if (feat1 == null || feat2 == null || feat1.length != 512 || feat2.length != 512) {
|
|
|
|
|
Log.e(TAG, "Invalid feature vectors for comparison.");
|
|
|
|
|
return -2.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
return nativeCompare(feat1, feat2);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e(TAG, "Exception during nativeCompare()", e);
|
|
|
|
|
return -2.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
public void release() {
|
|
|
|
|
if (nativeHandle != 0) {
|
|
|
|
|
nativeRelease();
|
|
|
|
|
Log.i(TAG, "SDK Released. Handle: " + nativeHandle);
|
|
|
|
|
nativeHandle = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
private String copyModelsFromAssets(Context context) {
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
final String[] modelFiles = {
|
|
|
|
|
"faceboxesv2-640x640.onnx",
|
|
|
|
|
"face_landmarker_pts5_net1.onnx",
|
|
|
|
|
"face_landmarker_pts5_net2.onnx",
|
|
|
|
|
"face_recognizer.onnx",
|
|
|
|
|
"model_gray_mobilenetv2_rotcls.onnx",
|
|
|
|
|
"fsanet-var.onnx",
|
|
|
|
|
"fsanet-conv.onnx"
|
|
|
|
|
};
|
|
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
File modelDir = new File(context.getFilesDir(), "models");
|
|
|
|
|
if (!modelDir.exists()) {
|
|
|
|
|
if (!modelDir.mkdirs()) {
|
|
|
|
|
Log.e(TAG, "Failed to create directory: " + modelDir.getAbsolutePath());
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AssetManager assetManager = context.getAssets();
|
|
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
for (String filename : modelFiles) {
|
|
|
|
|
File outFile = new File(modelDir, filename);
|
|
|
|
|
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
if (outFile.exists()) {
|
|
|
|
|
Log.i(TAG, "Model exists, skipping: " + filename);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log.i(TAG, "Copying model: " + filename);
|
|
|
|
|
try (InputStream is = assetManager.open(filename);
|
|
|
|
|
OutputStream os = new FileOutputStream(outFile)) {
|
|
|
|
|
|
|
|
|
|
byte[] buffer = new byte[1024 * 4];
|
|
|
|
|
int bytesRead;
|
|
|
|
|
while ((bytesRead = is.read(buffer)) != -1) {
|
|
|
|
|
os.write(buffer, 0, bytesRead);
|
|
|
|
|
}
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
Log.e(TAG, "Failed to copy model: " + filename, e);
|
2025-11-17 15:54:25 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log.i(TAG, "All models copied successfully to: " + modelDir.getAbsolutePath());
|
2025-11-17 15:54:25 +08:00
|
|
|
|
2025-10-31 13:59:24 +08:00
|
|
|
return modelDir.getAbsolutePath();
|
|
|
|
|
}
|
|
|
|
|
}
|