修改gitignore,移除无用的注释
This commit is contained in:
parent
290360c4f0
commit
ed875db3e5
|
|
@ -44,7 +44,7 @@ Generated\ Files/
|
||||||
# MSTest test Results
|
# MSTest test Results
|
||||||
[Tt]est[Rr]esult*/
|
[Tt]est[Rr]esult*/
|
||||||
[Bb]uild[Ll]og.*
|
[Bb]uild[Ll]og.*
|
||||||
|
[Bb]uild/
|
||||||
# NUnit
|
# NUnit
|
||||||
*.VisualState.xml
|
*.VisualState.xml
|
||||||
TestResult.xml
|
TestResult.xml
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// 声明包名,必须与您的项目一致
|
|
||||||
package com.facesdk.wrapper;
|
package com.facesdk.wrapper;
|
||||||
|
|
||||||
// 导入所有必需的 Android 工具
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.AssetManager;
|
import android.content.res.AssetManager;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
|
@ -13,72 +13,63 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
/**
|
|
||||||
* 封装了所有 JNI 调用的 SDK 包装器。
|
|
||||||
* 这是 Android App 唯一应该交互的类。
|
|
||||||
*/
|
|
||||||
public class FaceSDKWrapper {
|
public class FaceSDKWrapper {
|
||||||
|
|
||||||
private static final String TAG = "FaceSDKWrapper";
|
private static final String TAG = "FaceSDKWrapper";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
// 【【【关键修正】】】
|
|
||||||
// 我们必须在加载我们自己的库之前,
|
|
||||||
// 首先加载我们的库所依赖的第三方库。
|
|
||||||
System.loadLibrary("c++_shared");
|
System.loadLibrary("c++_shared");
|
||||||
// 1. 加载 ONNX Runtime (来自 build.gradle.kts)
|
|
||||||
System.loadLibrary("onnxruntime");
|
System.loadLibrary("onnxruntime");
|
||||||
|
|
||||||
// 2. 加载 OpenCV (来自 build.gradle.kts, 库名是 opencv_java4)
|
|
||||||
System.loadLibrary("opencv_java4");
|
System.loadLibrary("opencv_java4");
|
||||||
|
|
||||||
// 3. 最后加载我们自己的库
|
|
||||||
System.loadLibrary("face_sdk_jni");
|
System.loadLibrary("face_sdk_jni");
|
||||||
|
|
||||||
} catch (UnsatisfiedLinkError e) {
|
} catch (UnsatisfiedLinkError e) {
|
||||||
// 如果这里出错,App 无法运行
|
|
||||||
Log.e(TAG, "!!! 致命错误: 无法加载一个或多个 Native 库 !!!", e);
|
Log.e(TAG, "!!! 致命错误: 无法加载一个或多个 Native 库 !!!", e);
|
||||||
// 抛出运行时异常,使 App 立即停止,而不是稍后崩溃
|
|
||||||
throw new RuntimeException("Failed to load native libraries", e);
|
throw new RuntimeException("Failed to load native libraries", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 声明 C++ JNI 函数 (必须与 face_sdk_jni.cpp 匹配)
|
|
||||||
// 这些是 Java 和 C++ 之间的“秘密通道”
|
|
||||||
private native long nativeInit(String modelDir);
|
private native long nativeInit(String modelDir);
|
||||||
private native float[] nativeExtractFeature(Bitmap bitmap);
|
private native float[] nativeExtractFeature(Bitmap bitmap);
|
||||||
private native float nativeCompare(float[] feat1, float[] feat2);
|
private native float nativeCompare(float[] feat1, float[] feat2);
|
||||||
private native void nativeRelease();
|
private native void nativeRelease();
|
||||||
|
|
||||||
// -----------------------------------------------------------------
|
|
||||||
// 公开的 Java API 接口
|
|
||||||
// -----------------------------------------------------------------
|
|
||||||
|
|
||||||
// C++ FaceSDK 实例的指针 (句柄)
|
|
||||||
private long nativeHandle = 0;
|
private long nativeHandle = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* [API 1] 初始化 SDK
|
|
||||||
* 负责复制模型并初始化 C++ 引擎
|
|
||||||
*
|
|
||||||
* @param context Android 应用上下文
|
|
||||||
* @return true 成功, false 失败
|
|
||||||
*/
|
|
||||||
public boolean init(Context context) {
|
public boolean init(Context context) {
|
||||||
if (nativeHandle != 0) {
|
if (nativeHandle != 0) {
|
||||||
Log.w(TAG, "SDK already initialized.");
|
Log.w(TAG, "SDK already initialized.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 步骤 1: 复制模型
|
|
||||||
String modelPath = copyModelsFromAssets(context);
|
String modelPath = copyModelsFromAssets(context);
|
||||||
if (modelPath == null) {
|
if (modelPath == null) {
|
||||||
Log.e(TAG, "Failed to copy models from assets.");
|
Log.e(TAG, "Failed to copy models from assets.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 步骤 2: 调用 C++ JNI 进行初始化
|
|
||||||
try {
|
try {
|
||||||
this.nativeHandle = nativeInit(modelPath);
|
this.nativeHandle = nativeInit(modelPath);
|
||||||
if (this.nativeHandle == 0) {
|
if (this.nativeHandle == 0) {
|
||||||
|
|
@ -94,12 +85,7 @@ public class FaceSDKWrapper {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* [API 2] 提取特征
|
|
||||||
*
|
|
||||||
* @param bitmap 包含人脸的 Bitmap
|
|
||||||
* @return 512维特征向量, 或在失败时返回 null
|
|
||||||
*/
|
|
||||||
public float[] extractFeature(Bitmap bitmap) {
|
public float[] extractFeature(Bitmap bitmap) {
|
||||||
if (nativeHandle == 0) {
|
if (nativeHandle == 0) {
|
||||||
Log.e(TAG, "SDK not initialized. Call init() first.");
|
Log.e(TAG, "SDK not initialized. Call init() first.");
|
||||||
|
|
@ -118,17 +104,11 @@ public class FaceSDKWrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* [API 3] 比较特征
|
|
||||||
*
|
|
||||||
* @param feat1 特征1
|
|
||||||
* @param feat2 特征2
|
|
||||||
* @return 余弦相似度
|
|
||||||
*/
|
|
||||||
public float compare(float[] feat1, float[] feat2) {
|
public float compare(float[] feat1, float[] feat2) {
|
||||||
if (nativeHandle == 0) {
|
if (nativeHandle == 0) {
|
||||||
Log.e(TAG, "SDK not initialized.");
|
Log.e(TAG, "SDK not initialized.");
|
||||||
return -2.0f; // -2.0 作为错误码
|
return -2.0f;
|
||||||
}
|
}
|
||||||
if (feat1 == null || feat2 == null || feat1.length != 512 || feat2.length != 512) {
|
if (feat1 == null || feat2 == null || feat1.length != 512 || feat2.length != 512) {
|
||||||
Log.e(TAG, "Invalid feature vectors for comparison.");
|
Log.e(TAG, "Invalid feature vectors for comparison.");
|
||||||
|
|
@ -143,10 +123,7 @@ public class FaceSDKWrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* [API 4] 释放 SDK
|
|
||||||
* 在 App 退出时调用
|
|
||||||
*/
|
|
||||||
public void release() {
|
public void release() {
|
||||||
if (nativeHandle != 0) {
|
if (nativeHandle != 0) {
|
||||||
nativeRelease();
|
nativeRelease();
|
||||||
|
|
@ -155,19 +132,13 @@ public class FaceSDKWrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------
|
|
||||||
// 任务 2.6: 模型复制逻辑
|
|
||||||
// -----------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将 assets 中的所有 .onnx 模型复制到应用的内部存储。
|
|
||||||
* C++ 只能从内部存储读取,不能直接读取 assets。
|
|
||||||
*
|
|
||||||
* @param context 上下文
|
|
||||||
* @return 模型的存储目录路径, 或在失败时返回 null
|
|
||||||
*/
|
|
||||||
private String copyModelsFromAssets(Context context) {
|
private String copyModelsFromAssets(Context context) {
|
||||||
// 这是 C++ 需要的 7 个模型
|
|
||||||
final String[] modelFiles = {
|
final String[] modelFiles = {
|
||||||
"faceboxesv2-640x640.onnx",
|
"faceboxesv2-640x640.onnx",
|
||||||
"face_landmarker_pts5_net1.onnx",
|
"face_landmarker_pts5_net1.onnx",
|
||||||
|
|
@ -178,7 +149,7 @@ public class FaceSDKWrapper {
|
||||||
"fsanet-conv.onnx"
|
"fsanet-conv.onnx"
|
||||||
};
|
};
|
||||||
|
|
||||||
// 目标目录: /data/data/com.facesdk.wrapper/files/models
|
|
||||||
File modelDir = new File(context.getFilesDir(), "models");
|
File modelDir = new File(context.getFilesDir(), "models");
|
||||||
if (!modelDir.exists()) {
|
if (!modelDir.exists()) {
|
||||||
if (!modelDir.mkdirs()) {
|
if (!modelDir.mkdirs()) {
|
||||||
|
|
@ -189,11 +160,11 @@ public class FaceSDKWrapper {
|
||||||
|
|
||||||
AssetManager assetManager = context.getAssets();
|
AssetManager assetManager = context.getAssets();
|
||||||
|
|
||||||
// 循环复制每一个模型
|
|
||||||
for (String filename : modelFiles) {
|
for (String filename : modelFiles) {
|
||||||
File outFile = new File(modelDir, filename);
|
File outFile = new File(modelDir, filename);
|
||||||
|
|
||||||
// 如果文件已存在,跳过复制 (提高启动速度)
|
|
||||||
if (outFile.exists()) {
|
if (outFile.exists()) {
|
||||||
Log.i(TAG, "Model exists, skipping: " + filename);
|
Log.i(TAG, "Model exists, skipping: " + filename);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -210,15 +181,15 @@ public class FaceSDKWrapper {
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "Failed to copy model: " + filename, e);
|
Log.e(TAG, "Failed to copy model: " + filename, e);
|
||||||
// 如果任何一个文件复制失败,则清理并返回失败
|
|
||||||
// (清理是可选的,但更健壮)
|
|
||||||
// cleanUpModels(modelDir);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i(TAG, "All models copied successfully to: " + modelDir.getAbsolutePath());
|
Log.i(TAG, "All models copied successfully to: " + modelDir.getAbsolutePath());
|
||||||
// 返回包含模型的目录路径
|
|
||||||
return modelDir.getAbsolutePath();
|
return modelDir.getAbsolutePath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,196 +1,181 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <array>
|
|
||||||
#include <cmath>
|
|
||||||
#include <numeric>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
#include <array>
|
||||||
|
#include <cmath>
|
||||||
|
#include <memory>
|
||||||
|
#include <numeric>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "onnxruntime_cxx_api.h"
|
#include "onnxruntime_cxx_api.h"
|
||||||
|
#include "opencv2/calib3d.hpp"
|
||||||
#include "opencv2/opencv.hpp"
|
#include "opencv2/opencv.hpp"
|
||||||
#include "opencv2/calib3d.hpp" // for estimateAffinePartial2D
|
|
||||||
|
|
||||||
// --- 日志宏 ---
|
|
||||||
#define LOG_TAG "FacePipeline_CPP"
|
#define LOG_TAG "FacePipeline_CPP"
|
||||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||||
|
|
||||||
|
inline float compare_features(const std::vector<float> &v1,
|
||||||
/**
|
const std::vector<float> &v2) {
|
||||||
* @brief 计算两个L2归一化的特征向量的余弦相似度
|
if (v1.empty() || v1.size() != v2.size()) {
|
||||||
*/
|
return 0.0f;
|
||||||
inline float compare_features(const std::vector<float>& v1, const std::vector<float>& v2) {
|
}
|
||||||
if (v1.empty() || v1.size() != v2.size()) {
|
double dot_product = 0.0;
|
||||||
return 0.0f;
|
for (size_t i = 0; i < v1.size(); ++i) {
|
||||||
}
|
dot_product += v1[i] * v2[i];
|
||||||
double dot_product = 0.0;
|
}
|
||||||
for (size_t i = 0; i < v1.size(); ++i) {
|
return std::max(-1.0f, std::min(1.0f, static_cast<float>(dot_product)));
|
||||||
dot_product += v1[i] * v2[i];
|
|
||||||
}
|
|
||||||
return std::max(-1.0f, std::min(1.0f, static_cast<float>(dot_product)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 辅助结构体 (与 facedetector.py::Box 对应) ---
|
|
||||||
struct FaceBox {
|
struct FaceBox {
|
||||||
float x1, y1, x2, y2, score;
|
float x1, y1, x2, y2, score;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FaceLandmark {
|
struct FaceLandmark {
|
||||||
std::array<cv::Point2f, 5> points;
|
std::array<cv::Point2f, 5> points;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FacePose {
|
struct FacePose {
|
||||||
float yaw, pitch, roll;
|
float yaw, pitch, roll;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- NMS 辅助函数 (与 facedetector.py::hard_nms 对应) ---
|
inline float iou_of(const FaceBox &a, const FaceBox &b) {
|
||||||
inline float iou_of(const FaceBox& a, const FaceBox& b) {
|
float inter_x1 = std::max(a.x1, b.x1);
|
||||||
float inter_x1 = std::max(a.x1, b.x1);
|
float inter_y1 = std::max(a.y1, b.y1);
|
||||||
float inter_y1 = std::max(a.y1, b.y1);
|
float inter_x2 = std::min(a.x2, b.x2);
|
||||||
float inter_x2 = std::min(a.x2, b.x2);
|
float inter_y2 = std::min(a.y2, b.y2);
|
||||||
float inter_y2 = std::min(a.y2, b.y2);
|
|
||||||
|
|
||||||
if (inter_x1 < inter_x2 && inter_y1 < inter_y2) {
|
if (inter_x1 < inter_x2 && inter_y1 < inter_y2) {
|
||||||
float inter_area = (inter_x2 - inter_x1 + 1.0f) * (inter_y2 - inter_y1 + 1.0f);
|
float inter_area =
|
||||||
float a_area = (a.x2 - a.x1 + 1.0f) * (a.y2 - a.y1 + 1.0f);
|
(inter_x2 - inter_x1 + 1.0f) * (inter_y2 - inter_y1 + 1.0f);
|
||||||
float b_area = (b.x2 - b.x1 + 1.0f) * (b.y2 - b.y1 + 1.0f);
|
float a_area = (a.x2 - a.x1 + 1.0f) * (a.y2 - a.y1 + 1.0f);
|
||||||
float union_area = a_area + b_area - inter_area;
|
float b_area = (b.x2 - b.x1 + 1.0f) * (b.y2 - b.y1 + 1.0f);
|
||||||
return inter_area / union_area;
|
float union_area = a_area + b_area - inter_area;
|
||||||
}
|
return inter_area / union_area;
|
||||||
return 0.0f;
|
}
|
||||||
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::vector<FaceBox> hard_nms(std::vector<FaceBox>& boxes, float iou_threshold, int topk) {
|
inline std::vector<FaceBox> hard_nms(std::vector<FaceBox> &boxes,
|
||||||
if (boxes.empty()) return {};
|
float iou_threshold, int topk) {
|
||||||
std::sort(boxes.begin(), boxes.end(), [](const FaceBox& a, const FaceBox& b) {
|
if (boxes.empty())
|
||||||
return a.score > b.score;
|
return {};
|
||||||
});
|
std::sort(boxes.begin(), boxes.end(), [](const FaceBox &a, const FaceBox &b) {
|
||||||
|
return a.score > b.score;
|
||||||
|
});
|
||||||
|
|
||||||
std::vector<int> merged(boxes.size(), 0);
|
std::vector<int> merged(boxes.size(), 0);
|
||||||
std::vector<FaceBox> output;
|
std::vector<FaceBox> output;
|
||||||
|
|
||||||
for (int i = 0; i < boxes.size(); ++i) {
|
for (int i = 0; i < boxes.size(); ++i) {
|
||||||
if (merged[i]) continue;
|
if (merged[i])
|
||||||
|
continue;
|
||||||
output.push_back(boxes[i]);
|
|
||||||
merged[i] = 1;
|
|
||||||
|
|
||||||
for (int j = i + 1; j < boxes.size(); ++j) {
|
output.push_back(boxes[i]);
|
||||||
if (merged[j]) continue;
|
merged[i] = 1;
|
||||||
if (iou_of(boxes[i], boxes[j]) > iou_threshold) {
|
|
||||||
merged[j] = 1;
|
for (int j = i + 1; j < boxes.size(); ++j) {
|
||||||
}
|
if (merged[j])
|
||||||
}
|
continue;
|
||||||
if (output.size() >= topk) break;
|
if (iou_of(boxes[i], boxes[j]) > iou_threshold) {
|
||||||
|
merged[j] = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return output;
|
if (output.size() >= topk)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class FacePipeline
|
|
||||||
* @brief 管理7个ONNX模型并执行完整的人脸识别管线
|
|
||||||
*/
|
|
||||||
class FacePipeline {
|
class FacePipeline {
|
||||||
public:
|
public:
|
||||||
FacePipeline(const std::string& model_dir);
|
FacePipeline(const std::string &model_dir);
|
||||||
~FacePipeline();
|
~FacePipeline();
|
||||||
bool IsInitialized() const { return m_initialized; }
|
bool IsInitialized() const { return m_initialized; }
|
||||||
bool Extract(const cv::Mat& image, std::vector<float>& feature);
|
bool Extract(const cv::Mat &image, std::vector<float> &feature);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- 模型加载与初始化 ---
|
bool LoadModels(const std::string &model_dir);
|
||||||
bool LoadModels(const std::string& model_dir);
|
void InitMemoryAllocators();
|
||||||
void InitMemoryAllocators();
|
|
||||||
|
|
||||||
// --- 核心管线步骤 ---
|
void preprocess_rotation(const cv::Mat &image, std::vector<float> &blob_data);
|
||||||
void preprocess_rotation(const cv::Mat &image, std::vector<float> &blob_data);
|
int RunRotation(const cv::Mat &image);
|
||||||
int RunRotation(const cv::Mat& image); // [模型5]
|
bool RunDetection(const cv::Mat &image, std::vector<FaceBox> &boxes);
|
||||||
bool RunDetection(const cv::Mat& image, std::vector<FaceBox>& boxes); // [模型1]
|
bool RunPose(const cv::Mat &face_crop, FacePose &pose);
|
||||||
bool RunPose(const cv::Mat& face_crop, FacePose& pose); // [模型6, 7]
|
bool RunLandmark(const cv::Mat &image, const FaceBox &box,
|
||||||
bool RunLandmark(const cv::Mat& image, const FaceBox& box, FaceLandmark& landmark); // [模型2, 3]
|
FaceLandmark &landmark);
|
||||||
cv::Mat RunAlignment(const cv::Mat& image, const FaceLandmark& landmark); //
|
cv::Mat RunAlignment(const cv::Mat &image, const FaceLandmark &landmark);
|
||||||
bool RunRecognition(const cv::Mat& aligned_face, std::vector<float>& feature); // [模型4]
|
bool RunRecognition(const cv::Mat &aligned_face, std::vector<float> &feature);
|
||||||
|
|
||||||
// --- 预处理/后处理 辅助函数 ---
|
|
||||||
|
|
||||||
// [模型1] FaceBoxesV2
|
|
||||||
struct Anchor { float cx, cy, s_kx, s_ky; };
|
|
||||||
std::vector<Anchor> m_anchors;
|
|
||||||
void generate_anchors_faceboxes(int target_height, int target_width);
|
|
||||||
void preprocess_detection(const cv::Mat& img, std::vector<float>& blob_data);
|
|
||||||
|
|
||||||
// [模型6, 7] FSANet
|
struct Anchor {
|
||||||
void preprocess_pose(const cv::Mat& img, std::vector<float>& blob_data);
|
float cx, cy, s_kx, s_ky;
|
||||||
|
};
|
||||||
|
std::vector<Anchor> m_anchors;
|
||||||
|
void generate_anchors_faceboxes(int target_height, int target_width);
|
||||||
|
void preprocess_detection(const cv::Mat &img, std::vector<float> &blob_data);
|
||||||
|
|
||||||
// [模型2, 3] Landmark5er
|
void preprocess_pose(const cv::Mat &img, std::vector<float> &blob_data);
|
||||||
void preprocess_landmark_net1(const cv::Mat& img, std::vector<float>& blob_data);
|
|
||||||
std::vector<float> shape_index_process(const Ort::Value& feat_data, const Ort::Value& pos_data);
|
|
||||||
|
|
||||||
// [模型4] FaceRecognizer
|
void preprocess_landmark_net1(const cv::Mat &img,
|
||||||
void preprocess_recognition(const cv::Mat& img, std::vector<float>& blob_data);
|
std::vector<float> &blob_data);
|
||||||
void normalize_sqrt_l2(std::vector<float>& v); //
|
std::vector<float> shape_index_process(const Ort::Value &feat_data,
|
||||||
|
const Ort::Value &pos_data);
|
||||||
|
|
||||||
// 通用
|
void preprocess_recognition(const cv::Mat &img,
|
||||||
void image_to_blob(const cv::Mat& img, std::vector<float>& blob, const float* mean, const float* std);
|
std::vector<float> &blob_data);
|
||||||
Ort::Value create_tensor(const std::vector<float>& blob_data, const std::vector<int64_t>& input_shape);
|
void normalize_sqrt_l2(std::vector<float> &v);
|
||||||
|
|
||||||
// --- ONNX Runtime 核心组件 ---
|
void image_to_blob(const cv::Mat &img, std::vector<float> &blob,
|
||||||
Ort::Env m_env;
|
const float *mean, const float *std);
|
||||||
Ort::SessionOptions m_session_options;
|
Ort::Value create_tensor(const std::vector<float> &blob_data,
|
||||||
Ort::AllocatorWithDefaultOptions m_allocator;
|
const std::vector<int64_t> &input_shape);
|
||||||
Ort::MemoryInfo m_memory_info;
|
|
||||||
bool m_initialized = false;
|
|
||||||
|
|
||||||
// --- 7个模型的会话 (Session) ---
|
Ort::Env m_env;
|
||||||
std::unique_ptr<Ort::Session> m_session_detector;
|
Ort::SessionOptions m_session_options;
|
||||||
std::unique_ptr<Ort::Session> m_session_landmarker1;
|
Ort::AllocatorWithDefaultOptions m_allocator;
|
||||||
std::unique_ptr<Ort::Session> m_session_landmarker2;
|
Ort::MemoryInfo m_memory_info;
|
||||||
std::unique_ptr<Ort::Session> m_session_recognizer;
|
bool m_initialized = false;
|
||||||
std::unique_ptr<Ort::Session> m_session_rotator;
|
|
||||||
std::unique_ptr<Ort::Session> m_session_pose_var;
|
|
||||||
std::unique_ptr<Ort::Session> m_session_pose_conv;
|
|
||||||
|
|
||||||
// --- ONNX模型输入/输出名称 (C-style strings) ---
|
std::unique_ptr<Ort::Session> m_session_detector;
|
||||||
// 我们在加载模型时获取这些
|
std::unique_ptr<Ort::Session> m_session_landmarker1;
|
||||||
std::vector<const char*> m_rot_input_names, m_rot_output_names;
|
std::unique_ptr<Ort::Session> m_session_landmarker2;
|
||||||
std::vector<int64_t> m_rot_input_shape;
|
std::unique_ptr<Ort::Session> m_session_recognizer;
|
||||||
|
std::unique_ptr<Ort::Session> m_session_rotator;
|
||||||
|
std::unique_ptr<Ort::Session> m_session_pose_var;
|
||||||
|
std::unique_ptr<Ort::Session> m_session_pose_conv;
|
||||||
|
|
||||||
std::vector<const char*> m_det_input_names, m_det_output_names;
|
std::vector<const char *> m_rot_input_names, m_rot_output_names;
|
||||||
std::vector<int64_t> m_det_input_shape;
|
std::vector<int64_t> m_rot_input_shape;
|
||||||
|
|
||||||
std::vector<const char*> m_pose_var_input_names, m_pose_var_output_names;
|
|
||||||
std::vector<int64_t> m_pose_var_input_shape;
|
|
||||||
|
|
||||||
std::vector<const char*> m_pose_conv_input_names, m_pose_conv_output_names;
|
std::vector<const char *> m_det_input_names, m_det_output_names;
|
||||||
std::vector<int64_t> m_pose_conv_input_shape;
|
std::vector<int64_t> m_det_input_shape;
|
||||||
|
|
||||||
std::vector<const char*> m_lm1_input_names, m_lm1_output_names;
|
std::vector<const char *> m_pose_var_input_names, m_pose_var_output_names;
|
||||||
std::vector<int64_t> m_lm1_input_shape;
|
std::vector<int64_t> m_pose_var_input_shape;
|
||||||
|
|
||||||
std::vector<const char*> m_lm2_input_names, m_lm2_output_names;
|
std::vector<const char *> m_pose_conv_input_names, m_pose_conv_output_names;
|
||||||
std::vector<int64_t> m_lm2_input_shape;
|
std::vector<int64_t> m_pose_conv_input_shape;
|
||||||
|
|
||||||
std::vector<const char*> m_rec_input_names, m_rec_output_names;
|
std::vector<const char *> m_lm1_input_names, m_lm1_output_names;
|
||||||
std::vector<int64_t> m_rec_input_shape;
|
std::vector<int64_t> m_lm1_input_shape;
|
||||||
|
|
||||||
// --- 临时缓冲区 ---
|
|
||||||
std::vector<float> m_blob_buffer;
|
|
||||||
|
|
||||||
// --- 常量 (来自 Python) ---
|
std::vector<const char *> m_lm2_input_names, m_lm2_output_names;
|
||||||
const float m_det_threshold = 0.35f;
|
std::vector<int64_t> m_lm2_input_shape;
|
||||||
const float m_det_iou_threshold = 0.45f;
|
|
||||||
const int m_det_topk = 300;
|
std::vector<const char *> m_rec_input_names, m_rec_output_names;
|
||||||
const float m_pose_threshold = 30.0f; // (来自 face_feature_extractor.py)
|
std::vector<int64_t> m_rec_input_shape;
|
||||||
const cv::Mat m_landmark_template = (cv::Mat_<float>(5, 2) <<
|
|
||||||
89.3095f, 72.9025f, // (来自 facealign.py)
|
std::vector<float> m_blob_buffer;
|
||||||
169.3095f, 72.9025f, //
|
|
||||||
127.8949f, 127.0441f, //
|
const float m_det_threshold = 0.35f;
|
||||||
96.8796f, 184.8907f, //
|
const float m_det_iou_threshold = 0.45f;
|
||||||
159.1065f, 184.7601f); //
|
const int m_det_topk = 300;
|
||||||
const cv::Size m_align_output_size = cv::Size(256, 256); //
|
const float m_pose_threshold = 30.0f;
|
||||||
|
const cv::Mat m_landmark_template =
|
||||||
|
(cv::Mat_<float>(5, 2) << 89.3095f, 72.9025f, 169.3095f, 72.9025f,
|
||||||
|
127.8949f, 127.0441f, 96.8796f, 184.8907f, 159.1065f, 184.7601f);
|
||||||
|
const cv::Size m_align_output_size = cv::Size(256, 256);
|
||||||
};
|
};
|
||||||
Loading…
Reference in New Issue