FaceRecog/src/face_pipeline.cpp

117 lines
4.4 KiB
C++
Raw Normal View History

2025-10-30 18:37:30 +08:00
#include "face_pipeline.h"
#include <iostream> // 用于日志
// 构造函数初始化ORT环境、会话选项并加载模型
FacePipeline::FacePipeline(const std::string& model_dir)
: m_env(ORT_LOGGING_LEVEL_WARNING, "FaceSDK") // 初始化ORT环境
{
// 配置会话选项
m_session_options.SetIntraOpNumThreads(1); // 移动端通常设置为1
m_session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL);
// 立即加载模型
m_initialized = LoadModels(model_dir);
if (m_initialized) {
std::cout << "FacePipeline initialized successfully." << std::endl;
} else {
std::cerr << "FacePipeline initialization failed." << std::endl;
}
}
// 析构函数 (由于使用unique_ptr, 资源会自动释放)
FacePipeline::~FacePipeline() {}
// (私有) 加载所有模型
bool FacePipeline::LoadModels(const std::string& model_dir) {
try {
// 【【修正点】】:
// 我们不再使用 to_wstring()。
// 我们直接使用 .c_str()因为Android API需要 const char*
// 1. 人脸检测
std::string detector_path = model_dir + "/faceboxesv2-640x640.onnx";
m_session_detector = std::make_unique<Ort::Session>(m_env, detector_path.c_str(), m_session_options);
std::cout << "Loaded model: " << detector_path << std::endl;
// 2. 关键点 (Net1)
std::string lm1_path = model_dir + "/face_landmarker_pts5_net1.onnx";
m_session_landmarker1 = std::make_unique<Ort::Session>(m_env, lm1_path.c_str(), m_session_options);
std::cout << "Loaded model: " << lm1_path << std::endl;
// 3. 关键点 (Net2)
std::string lm2_path = model_dir + "/face_landmarker_pts5_net2.onnx";
m_session_landmarker2 = std::make_unique<Ort::Session>(m_env, lm2_path.c_str(), m_session_options);
std::cout << "Loaded model: " << lm2_path << std::endl;
// 4. 人脸识别
std::string rec_path = model_dir + "/face_recognizer.onnx";
m_session_recognizer = std::make_unique<Ort::Session>(m_env, rec_path.c_str(), m_session_options);
std::cout << "Loaded model: " << rec_path << std::endl;
// 5. 旋转分类
std::string rot_path = model_dir + "/model_gray_mobilenetv2_rotcls.onnx";
m_session_rotator = std::make_unique<Ort::Session>(m_env, rot_path.c_str(), m_session_options);
std::cout << "Loaded model: " << rot_path << std::endl;
// 6. 姿态估计 (VAR)
std::string pose_var_path = model_dir + "/fsanet-var.onnx";
m_session_pose_var = std::make_unique<Ort::Session>(m_env, pose_var_path.c_str(), m_session_options);
std::cout << "Loaded model: " << pose_var_path << std::endl;
// 7. 姿态估计 (CONV)
std::string pose_conv_path = model_dir + "/fsanet-conv.onnx";
m_session_pose_conv = std::make_unique<Ort::Session>(m_env, pose_conv_path.c_str(), m_session_options);
std::cout << "Loaded model: " << pose_conv_path << std::endl;
} catch (const Ort::Exception& e) {
// 如果任何模型加载失败,捕获异常
std::cerr << "Error loading models: " << e.what() << std::endl;
return false;
}
std::cout << "All 7 models loaded successfully." << std::endl;
return true;
}
// L2 归一化 (将在Extract中使用)
void FacePipeline::normalize_l2(std::vector<float>& v) {
double norm = 0.0;
for (float val : v) {
norm += val * val;
}
if (norm > 1e-6) { // 避免除以零
norm = std::sqrt(norm);
for (float& val : v) {
val = static_cast<float>(val / norm);
}
}
}
// Extract 方法的桩函数 (我们将在下一步实现)
bool FacePipeline::Extract(const cv::Mat& image, std::vector<float>& feature) {
if (!m_initialized) {
std::cerr << "Pipeline is not initialized." << std::endl;
return false;
}
if (image.empty()) {
std::cerr << "Input image is empty." << std::endl;
return false;
}
// --------------------------------------------------
// TODO: 在这里实现完整的 7 模型推理管线
// --------------------------------------------------
// std::cout << "Extract method is not implemented yet." << std::endl;
// 临时填充一个假的特征向量
feature.assign(512, 0.5f);
normalize_l2(feature);
return true;
}