From 18d649a63680cc401c8bea90d1b02dd883be6502 Mon Sep 17 00:00:00 2001 From: wdp <544209413@qq.com> Date: Sun, 19 Jan 2025 23:41:10 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E6=9B=B4=E6=96=B0=E3=80=91=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E4=BA=BA=E8=84=B8=E6=A3=80=E6=B5=8B=E5=92=8C=E7=89=B9?= =?UTF-8?q?=E5=BE=81=E6=8F=90=E5=8F=96=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 +- app/main.cpp | 66 +++++++-- include/AppCfg.h | 14 ++ src/AppCfg.cpp | 23 +++ src/AppCfg.h | 31 +++++ src/CenterFaceMnn.cpp2 | 261 +++++++++++++++++++++++++++++++++++ src/MobileFaceFeatureMnn.cpp | 220 +++++++++++++++++++++++++++++ src/MobileFaceFeatureMnn.h | 38 +++++ src/MobileFaceModel_0.cpp | 6 + src/MobileFaceModel_1.cpp | 7 + src/MobileFaceModel_2.cpp | 8 ++ src/TypeInfo.cpp | 3 + src/TypeInfo.h | 20 ++- 13 files changed, 677 insertions(+), 22 deletions(-) create mode 100644 include/AppCfg.h create mode 100644 src/AppCfg.cpp create mode 100644 src/AppCfg.h create mode 100644 src/CenterFaceMnn.cpp2 create mode 100644 src/MobileFaceFeatureMnn.cpp create mode 100644 src/MobileFaceFeatureMnn.h create mode 100644 src/MobileFaceModel_0.cpp create mode 100644 src/MobileFaceModel_1.cpp create mode 100644 src/MobileFaceModel_2.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b695eb..ff3b9bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,9 @@ cmake_minimum_required(VERSION 3.8) project(Demo) +set(CMAKE_BUILD_PARALLEL_LEVEL 8) set(CMAKE_CXX_STANDARD 11) if(WIN32) set(CMAKE_CXX_COMPILER "MSVC") - elseif(UNIX) set(CMAKE_CXX_COMPILER "g++") endif() diff --git a/app/main.cpp b/app/main.cpp index 20054b7..c395cd3 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -2,26 +2,72 @@ #include #include "util/TimeCount.h" #include "CenterFaceMnn.h" +#include "MobileFaceFeatureMnn.h" -int32_t main(int32_t argc, char** argv) { - CenterFaceMnn::GetInstance(); +void test_face_detect(std::string img_path) { + cv::Mat img = cv::imread(img_path); std::vector faces; - cv::Mat img = cv::imread("F:/33.jpg"); -int32_t count = 0; -re_test: - count++; { USE_TIME t(USE_TIME_US, "face_detect: "); CenterFaceMnn::GetInstance()->Detect(img, faces, 1); } - if (count < 10) { - goto re_test; - } for(auto& face : faces) { - cv::rectangle(img, cv::Rect(face.x1, face.y1, face.x2 - face.x1, face.y2 - face.y1), cv::Scalar(0, 0, 255), 2); + cv::rectangle(img, cv::Rect(face.x1, face.y1, FACE_BOX_WIDTH(face), FACE_BOX_HEIGHT(face)), cv::Scalar(0, 0, 255), 2); } cv::imshow("test", img); cv::waitKey(0); +} + +void test_face_compare(std::string img1, std::string img2) { + cv::Mat img1_ = cv::imread(img1); + cv::Mat img2_ = cv::imread(img2); + std::vector faces1; + std::vector faces2; + CenterFaceMnn::GetInstance()->Detect(img1_, faces1, 1); + CenterFaceMnn::GetInstance()->Detect(img2_, faces2, 1); + + if (faces1.size() == 0 || faces2.size() == 0) { + std::cout << faces1.size() << " == " << faces2.size() << std::endl; + return; + } + float feature1[512]; + float feature2[512]; + float score = 0.f; + { + USE_TIME t(USE_TIME_US, "GetFaceFeature img1 time: "); + MobileFaceFeatureMnn::GetInstance()->GetFaceFeature(img1_, faces1[0].landmarks, feature1); + } + + { + USE_TIME t(USE_TIME_US, "GetFaceFeature img2 time: "); + MobileFaceFeatureMnn::GetInstance()->GetFaceFeature(img2_, faces2[0].landmarks, feature2); + } + + { + USE_TIME t(USE_TIME_US, "DeepCamFaceFeatureCompare time: "); + MobileFaceFeatureMnn::GetInstance()->MobileFaceFeatureCompare(feature1, feature2, score); + } + + std::cout << "score: " << score << std::endl; + + for(auto& face : faces2) { + cv::rectangle(img2_, cv::Rect(face.x1, face.y1, FACE_BOX_WIDTH(face), FACE_BOX_HEIGHT(face)), cv::Scalar(0, 0, 255), 2); + } + for(auto& face : faces1) { + cv::rectangle(img1_, cv::Rect(face.x1, face.y1, FACE_BOX_WIDTH(face), FACE_BOX_HEIGHT(face)), cv::Scalar(0, 0, 255), 2); + } + + cv::imshow("img1", img1_); + cv::imshow("img2", img2_); + cv::waitKey(0); +} +int32_t main(int32_t argc, char** argv) { + CenterFaceMnn::GetInstance(); + MobileFaceFeatureMnn::GetInstance(); + // test_face_detect("E:/dd.jpg"); + + test_face_compare("F:/1.jpg", "E:\\6.jpg"); + return 0; } \ No newline at end of file diff --git a/include/AppCfg.h b/include/AppCfg.h new file mode 100644 index 0000000..a59a4fc --- /dev/null +++ b/include/AppCfg.h @@ -0,0 +1,14 @@ +#pragma once +#include + +class AppCfg { +public: + static void SetWorkPath(const std::string& work_path); + static const std::string GetWorkPath(); + static bool SetLicense(const std::string& license); + static void SetFaceMatchThreshold(float threshold); + +private: + static std::string m_work_path; // 静态成员变量声明 + static bool m_auth; +}; diff --git a/src/AppCfg.cpp b/src/AppCfg.cpp new file mode 100644 index 0000000..f107517 --- /dev/null +++ b/src/AppCfg.cpp @@ -0,0 +1,23 @@ +#include "AppCfg.h" + +bool AppCfg::m_auth = false; +std::string AppCfg::m_work_path=""; +std::string AppCfg::m_license=""; +float AppCfg::m_face_match_threshold = 0.78f; +void AppCfg::SetWorkPath(const std::string& work_path) { + +} + +const std::string AppCfg::GetWorkPath() { + return AppCfg::m_work_path; +} + +bool AppCfg::SetLicense(const std::string& license) { + + return AppCfg::m_auth; +} + +void AppCfg::SetFaceMatchThreshold(float threshold) { + +} + diff --git a/src/AppCfg.h b/src/AppCfg.h new file mode 100644 index 0000000..fb61237 --- /dev/null +++ b/src/AppCfg.h @@ -0,0 +1,31 @@ + +#ifndef __APP_CFG_H__ +#define __APP_CFG_H__ + +#include +#include + +class AppCfg { +private: + AppCfg() {} + AppCfg(const AppCfg&) = delete; + AppCfg& operator=(const AppCfg&) = delete; + +public: + static void SetWorkPath(const std::string& work_path); + static const std::string GetWorkPath(); + + /// 设置授权信息 + static bool SetLicense(const std::string& license); + + /// @brief 设置人脸比对阈值 + static void SetFaceMatchThreshold(float threshold); + +private: +static std::string m_work_path; +static std::string m_license; +static float m_face_match_threshold; + +static bool m_auth; +}; +#endif diff --git a/src/CenterFaceMnn.cpp2 b/src/CenterFaceMnn.cpp2 new file mode 100644 index 0000000..e8870df --- /dev/null +++ b/src/CenterFaceMnn.cpp2 @@ -0,0 +1,261 @@ +#include "CenterFaceMnn.h" + + + +static const unsigned char centerface_model[] = { +#include "centerface_small_mnn.dat" +}; + +CenterFaceMnn* CenterFaceMnn::m_hInstance; + + +CenterFaceMnn* CenterFaceMnn::GetInstance() +{ + if (!m_hInstance) + { + m_hInstance = new CenterFaceMnn(); + } + return m_hInstance; +} + +CenterFaceMnn::CenterFaceMnn() +{ + m_detector = std::shared_ptr(MNN::Interpreter::createFromBuffer(centerface_model, sizeof(centerface_model))); + + MNN::ScheduleConfig config; + MNN::BackendConfig backendConfig; + backendConfig.precision = MNN::BackendConfig::Precision_High; + backendConfig.power = MNN::BackendConfig::Power_High; + backendConfig.memory = MNN::BackendConfig::Memory_High; + config.backendConfig = &backendConfig; + config.type = MNN_FORWARD_CPU; + config.numThread = 4; + m_session = m_detector->createSession(config); + + const float mean_vals[3] = { 127.5f, 127.5f, 127.5f }; + const float norm_vals[3] = { 0.0078431373f, 0.0078431373f, 0.0078431373f }; + ::memcpy(m_img_config.mean, mean_vals, sizeof(mean_vals)); + ::memcpy(m_img_config.normal, norm_vals, sizeof(norm_vals)); + m_img_config.sourceFormat = (MNN::CV::ImageFormat)2; + m_img_config.destFormat = (MNN::CV::ImageFormat)1; + m_img_config.filterType = (MNN::CV::Filter)(1); + m_img_config.wrap = (MNN::CV::Wrap)(1); + + input_tensor = m_detector->getSessionInput(m_session, NULL); + hm_tensor = m_detector->getSessionOutput(m_session, "hm"); + wh_tensor = m_detector->getSessionOutput(m_session, "wh"); + reg_tensor = m_detector->getSessionOutput(m_session, "reg"); + lm_tensor = m_detector->getSessionOutput(m_session, "lm"); +} + +CenterFaceMnn::~CenterFaceMnn() +{ + m_detector->releaseSession(m_session); +} + +int CenterFaceMnn::Detect(const cv::Mat& img, std::vector& faces, float scale) +{ + std::lock_guard lock(m_mt); + faces.clear(); + if (img.cols * img.rows == 0) + { + return -1; + } + + if (scale <= 0 || scale > 1) { + scale = img.cols > img.rows ? 160.0f / img.cols : 160.0f / img.rows; + } + int resize_w = (int)(img.cols * scale) / 32 * 32; + int resize_h = (int)(img.rows * scale) / 32 * 32; + float scale_w = (float)img.cols / (float)resize_w; + float scale_h = (float)img.rows / (float)resize_h; + + + cv::Mat input; + cv::resize(img, input, cv::Size(resize_w, resize_h)); + m_detector->resizeTensor(input_tensor, 1, 3, resize_h, resize_w); + m_detector->resizeSession(m_session); + //prepare data + std::shared_ptr pretreat(MNN::CV::ImageProcess::create(m_img_config)); + pretreat->convert(input.data, resize_w, resize_h, input.step[0], input_tensor); + m_detector->runSession(m_session); + + MNN::Tensor tensor_hm(hm_tensor, MNN::Tensor::CAFFE); + MNN::Tensor tensor_wh(wh_tensor, MNN::Tensor::CAFFE); + MNN::Tensor tensor_reg(reg_tensor, MNN::Tensor::CAFFE); + MNN::Tensor tensor_lm(lm_tensor, MNN::Tensor::CAFFE); + + hm_tensor->copyToHostTensor(&tensor_hm); + wh_tensor->copyToHostTensor(&tensor_wh); + reg_tensor->copyToHostTensor(&tensor_reg); + lm_tensor->copyToHostTensor(&tensor_lm); + + std::vector hm_shape = tensor_hm.shape(); + + float* heatmap = tensor_hm.host(); + float* wh = tensor_wh.host(); + float* reg = tensor_reg.host(); + float* lm = tensor_lm.host(); + + Decode(heatmap, wh, reg, lm, hm_shape[2], hm_shape[3], faces, 0.4, 0.3); + for (int i = 0; i < faces.size(); i++) + { + FaceInfo& tmp = faces[i]; + tmp.x1 *= scale_w; + tmp.x2 *= scale_w; + tmp.y1 *= scale_h; + tmp.y2 *= scale_h; + + for (int j = 0; j < 5; j++) + { + tmp.landmarks[j * 2] *= scale_w; + tmp.landmarks[j * 2 + 1] *= scale_h; + } + } + + return faces.size(); +} + +void CenterFaceMnn::Decode(float* heatmap, float* scale, float* offset, float* landmarks, int h, int w, std::vector& faces, float scoreThresh, float nmsThresh) +{ + int fea_h = h; + int fea_w = w; + int d_w = w * 4; + int d_h = h * 4; + int spacial_size = fea_w*fea_h; + + + float *scale1 = (float*)(scale); + float *scale0 = scale1 + spacial_size; + + float *offset1 = (float*)(offset); + float *offset0 = offset1 + spacial_size; + + std::vector ids = GetIds(heatmap, fea_h, fea_w, scoreThresh); + + std::vector faces_tmp; + for (int i = 0; i < ids.size() / 2; i++) { + int id_h = ids[2 * i]; + int id_w = ids[2 * i + 1]; + int index = id_h*fea_w + id_w; + + float s0 = std::exp(scale0[index]) * 4; + float s1 = std::exp(scale1[index]) * 4; + //cout << s0 << "," << s1 << endl; + float o0 = offset0[index]; + float o1 = offset1[index]; + + //std::cout << s0 << " " << s1 << " " << o0 << " " << o1 << std::endl; + + float x1 = std::max(0., (id_w + o1 + 0.5) * 4 - s1 / 2); + float y1 = std::max(0., (id_h + o0 + 0.5) * 4 - s0 / 2); + float x2 = std::max(0., (id_w + o1 + 0.5) * 4 + s1 / 2); + float y2 = std::max(0., (id_h + o0 + 0.5) * 4 + s0 / 2); + x1 = std::min(x1, (float)d_w); + y1 = std::min(y1, (float)d_h); + x2 = std::min(x2, (float)d_w); + y2 = std::min(y2, (float)d_h); + + //std::cout << x1 << " " << y1 << " " << x2 << " " << y2 << std::endl; + + FaceInfo facebox; + facebox.x1 = x1; + facebox.y1 = y1; + facebox.x2 = x2; + facebox.y2 = y2; + facebox.score = heatmap[index]; + + float box_w = x2 - x1;//s1? + float box_h = y2 - y1;// s0 ? + + for (int j = 0; j < 5; j++) { + float *xmap = (float*)landmarks + (2 * j)*spacial_size; + float *ymap = (float*)landmarks + (2 * j + 1)*spacial_size; + facebox.landmarks[2 * j] = x1 + xmap[index] * s1; + facebox.landmarks[2 * j + 1] = y1 + ymap[index] * s0; + + } + faces_tmp.push_back(facebox); + } + NMS(faces_tmp, faces, nmsThresh); +} + +void CenterFaceMnn::NMS(std::vector& input, std::vector& output, float nmsthreshold) +{ + std::sort(input.begin(), input.end(), + [](const FaceInfo& a, const FaceInfo& b) + { + return a.score > b.score; + }); + + int box_num = input.size(); + + std::vector merged(box_num, 0); + + for (int i = 0; i < box_num; i++) + { + if (merged[i]) + continue; + + output.push_back(input[i]); + + float h0 = input[i].y2 - input[i].y1 + 1; + float w0 = input[i].x2 - input[i].x1 + 1; + + float area0 = h0 * w0; + + + for (int j = i + 1; j < box_num; j++) + { + if (merged[j]) + continue; + + float inner_x0 = input[i].x1 > input[j].x1 ? input[i].x1 : input[j].x1;//std::max(input[i].x1, input[j].x1); + float inner_y0 = input[i].y1 > input[j].y1 ? input[i].y1 : input[j].y1; + + float inner_x1 = input[i].x2 < input[j].x2 ? input[i].x2 : input[j].x2; //bug fixed ,sorry + float inner_y1 = input[i].y2 < input[j].y2 ? input[i].y2 : input[j].y2; + + float inner_h = inner_y1 - inner_y0 + 1; + float inner_w = inner_x1 - inner_x0 + 1; + + + if (inner_h <= 0 || inner_w <= 0) + continue; + + float inner_area = inner_h * inner_w; + + float h1 = input[j].y2 - input[j].y1 + 1; + float w1 = input[j].x2 - input[j].x1 + 1; + + float area1 = h1 * w1; + + float score; + + score = inner_area / (area0 + area1 - inner_area); + + if (score > nmsthreshold) + merged[j] = 1; + } + + } +} + +std::vector CenterFaceMnn::GetIds(float *heatmap, int h, int w, float thresh) +{ + std::vector ids; + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + if (heatmap[i*w + j] > thresh) { + ids.push_back(i); + ids.push_back(j); + } + } + } + return ids; +} + +const std::string CenterFaceMnn::GetModelVer() +{ + return m_model_ver; +} \ No newline at end of file diff --git a/src/MobileFaceFeatureMnn.cpp b/src/MobileFaceFeatureMnn.cpp new file mode 100644 index 0000000..cc535fb --- /dev/null +++ b/src/MobileFaceFeatureMnn.cpp @@ -0,0 +1,220 @@ +#include +#include + + +MobileFaceFeatureMnn* MobileFaceFeatureMnn::m_hInstance = nullptr; + + +#define FEATURE_IMG_SIZE 112 + +extern unsigned char mobile_face_model0[]; +extern unsigned char mobile_face_model1[]; +extern unsigned char mobile_face_model2[]; + +extern int mobile_face_model0_len; +extern int mobile_face_model1_len; +extern int mobile_face_model2_len; + + +MobileFaceFeatureMnn* MobileFaceFeatureMnn::GetInstance(){ + if (m_hInstance == nullptr){ + m_hInstance = new MobileFaceFeatureMnn; + } + return m_hInstance; +} + +MobileFaceFeatureMnn::MobileFaceFeatureMnn(){ + const unsigned char pw[] = "~12321@AAA"; + std::vector model; + model.insert(model.end(), mobile_face_model0, mobile_face_model0 + mobile_face_model0_len); + model.insert(model.end(), mobile_face_model1, mobile_face_model1 + mobile_face_model1_len); + model.insert(model.end(), mobile_face_model2, mobile_face_model2 + mobile_face_model2_len); + + int len = mobile_face_model0_len + mobile_face_model1_len + mobile_face_model2_len; + + for (int i = 0; i < len; i++) { + model[i] = model[i] ^ pw[i % sizeof(pw)]; + } + + //m_detector = std::shared_ptr(MNN::Interpreter::createFromFile(R"(I:\DeepCamPro\DeepCamFace\Release\MobileFaceNet_v6.6.4.mnn)")); + m_detector = std::shared_ptr(MNN::Interpreter::createFromBuffer(model.data(), len)); + + MNN::ScheduleConfig config; + config.type = MNN_FORWARD_OPENCL; + config.numThread = 4; + MNN::BackendConfig backendConfig; + backendConfig.precision = MNN::BackendConfig::Precision_High; + backendConfig.power = MNN::BackendConfig::Power_High; + config.backendConfig = &backendConfig; + + m_sess_mobileface = m_detector->createSession(config); + m_input_tensor = m_detector->getSessionInput(m_sess_mobileface, NULL); + m_feature_tensor = m_detector->getSessionOutput(m_sess_mobileface, "feature"); + m_detector->resizeTensor(m_input_tensor, 1, 3, FEATURE_IMG_SIZE, FEATURE_IMG_SIZE); + m_detector->resizeSession(m_sess_mobileface); + + const static float mean_vals[3] = { 127.5f, 127.5f, 127.5f }; + const static float norm_vals[3] = { 0.0078431373, 0.0078431373, 0.0078431373 }; + ::memcpy(m_img_config.mean, mean_vals, sizeof(mean_vals)); + ::memcpy(m_img_config.normal, norm_vals, sizeof(norm_vals)); + + m_img_config.sourceFormat = (MNN::CV::ImageFormat)2; + m_img_config.destFormat = (MNN::CV::ImageFormat)1; + + m_img_config.filterType = (MNN::CV::Filter)(1); + m_img_config.wrap = (MNN::CV::Wrap)(1); +} + +MobileFaceFeatureMnn::~MobileFaceFeatureMnn(){ + m_detector->releaseModel(); +} + +ret_t MobileFaceFeatureMnn::GetFaceFeature(const cv::Mat& img, const float* landmarks, float* feature){ + std::lock_guard lock(m_mt); + cv::Mat alignFace = FaceAlign(img, landmarks); + //cv::imshow("alignFace", alignFace); + //cv::waitKey(1); + if (alignFace.cols != FEATURE_IMG_SIZE || alignFace.rows != FEATURE_IMG_SIZE){ + cv::resize(alignFace, alignFace, cv::Size(FEATURE_IMG_SIZE, FEATURE_IMG_SIZE)); + } + + std::shared_ptr pretreat(MNN::CV::ImageProcess::create(m_img_config)); + pretreat->convert(alignFace.data, FEATURE_IMG_SIZE, FEATURE_IMG_SIZE, alignFace.step[0], m_input_tensor); + + m_detector->runSession(m_sess_mobileface); + + std::shared_ptr tensor_feature = std::make_shared(m_feature_tensor, MNN::Tensor::CAFFE); + m_feature_tensor->copyToHostTensor(tensor_feature.get()); + + //std::vector feature_shape = tensor_feature->shape(); + + //float* face_feature = tensor_feature->host(); + + memcpy(feature, tensor_feature->host(), 512 * sizeof(float)); + + //feature.insert(feature.end(), face_feature, face_feature + 512); + //for (int i = 0; i < 512; i++) { + // feature.push_back(face_feature[i]); + //} + return RET_OK; +} + +cv::Mat MobileFaceFeatureMnn::estimateTrans(std::vector& srcLmks, std::vector& dstLmks) +{ + cv::Mat A(2 * srcLmks.size(), 4, CV_32FC1); + cv::Mat B(2 * srcLmks.size(), 1, CV_32FC1); + for (int i = 0; i < srcLmks.size(); i++) + { + A.at(2 * i, 0) = srcLmks[i].x; + A.at(2 * i, 1) = -srcLmks[i].y; + A.at(2 * i, 2) = 1; + A.at(2 * i, 3) = 0; + B.at(2 * i, 0) = dstLmks[i].x; + + A.at(2 * i + 1, 0) = srcLmks[i].y; + A.at(2 * i + 1, 1) = srcLmks[i].x; + A.at(2 * i + 1, 2) = 0; + A.at(2 * i + 1, 3) = 1; + B.at(2 * i + 1, 0) = dstLmks[i].y; + } + + cv::Mat C, X; + C = (A.t() * A); + X = C.inv() * A.t() * B; + cv::Mat transformMatrix(2, 3, CV_32FC1); + transformMatrix.at(0, 0) = X.at(0, 0); + transformMatrix.at(0, 1) = -X.at(1, 0); + transformMatrix.at(0, 2) = X.at(2, 0); + transformMatrix.at(1, 0) = X.at(1, 0); + transformMatrix.at(1, 1) = X.at(0, 0); + transformMatrix.at(1, 2) = X.at(3, 0); + return transformMatrix; +} + +cv::Mat MobileFaceFeatureMnn::FaceAlign(const cv::Mat& inputImage, const float* landmarks) +{ + std::vector templateLmks; + std::vector salientLmks; + for (int l = 0; l < 5; l++) { + salientLmks.push_back(cv::Point(landmarks[l * 2], landmarks[l * 2 + 1])); + } + static double const template_points[] = { 30.2946, 65.5318, 48.0252, 33.5493, 62.7299, 51.6963, 51.5014, 71.7366, 92.3655, 92.2041 }; + static double shift_x = 8.0; + static size_t n = sizeof(template_points) / (2 * sizeof(template_points[0])); + for (int i = 0; i < n; i++) + { + templateLmks.push_back(cv::Point2f(template_points[i] + shift_x, template_points[i + n])); + } + + cv::Mat normalizedImage; + cv::Mat noFace(0, 0, CV_8UC1); + + cv::Point2f leftEye; + cv::Point2f rightEye; + + leftEye = salientLmks.at(0); + rightEye = salientLmks.at(1); + + cv::Point2f nose; + cv::Point2f leftMouth; + cv::Point2f rightMouth; + + nose = salientLmks.at(2); + leftMouth = salientLmks.at(3); + rightMouth = salientLmks.at(4); + + std::vector srcLmks; + srcLmks.push_back(leftEye); + srcLmks.push_back(rightEye); + srcLmks.push_back(nose); + srcLmks.push_back(leftMouth); + srcLmks.push_back(rightMouth); + + cv::Mat matTransform = estimateTrans(srcLmks, templateLmks); + + if (matTransform.empty()) + { + normalizedImage = noFace; + } + else { + cv::warpAffine(inputImage, normalizedImage, matTransform, cv::Size(FEATURE_IMG_SIZE, FEATURE_IMG_SIZE)); + } + return normalizedImage; +} + +ret_t MobileFaceFeatureMnn::MobileFaceFeatureCompare(const float* feature1, const float* feature2, float& fSimilarity) { + fSimilarity = 0.f; + + if (feature1 == nullptr || feature2 == nullptr) { + return RET_INVALID_FEATURE; + } + float tmp0 = 0, tmp1 = 0, tmp2 = 0; + + #pragma omp parallel for reduction(+:tmp0,tmp1,tmp2) + for (int i = 0; i < 512; i++) { + tmp0 += feature1[i] * feature2[i]; + tmp1 += feature1[i] * feature1[i]; + tmp2 += feature2[i] * feature2[i]; + } + + float score = (float(tmp0 / (sqrt(tmp1) * sqrt(tmp2)))); + + // 拉高分数 + float max_score = log10f(1.01); + float min_score = log10f(0.02); + float ret, temp; + if (score <= 0) { + temp = fabs(score); + if (temp > 0.3) { + ret = 0.0001; + } + else { + ret = temp; + } + } + else { + temp = log10f(score + 0.01); + fSimilarity = fabsf(temp - min_score) / (max_score - min_score); + } + return RET_OK; +} diff --git a/src/MobileFaceFeatureMnn.h b/src/MobileFaceFeatureMnn.h new file mode 100644 index 0000000..59a70f4 --- /dev/null +++ b/src/MobileFaceFeatureMnn.h @@ -0,0 +1,38 @@ +#ifndef _MOBILEFACEFEATURE_MNN_H +#define _MOBILEFACEFEATURE_MNN_H +#include +#include +#include +#include +#include +#include +#include +#include +#include "TypeInfo.h" + +class MobileFaceFeatureMnn{ +public: + static MobileFaceFeatureMnn* GetInstance(); + + ret_t GetFaceFeature(const cv::Mat& img, const float* landmarks, float* feature); + + ret_t MobileFaceFeatureCompare(const float* feature1, const float* feature2, float& fSimilarity); +private: + MobileFaceFeatureMnn(); + ~MobileFaceFeatureMnn(); + + cv::Mat estimateTrans(std::vector& srcLmks, std::vector& dstLmks); + cv::Mat FaceAlign(const cv::Mat& inputImage, const float* landmarks); + +private: + static MobileFaceFeatureMnn* m_hInstance; + std::mutex m_mt; + + std::shared_ptr m_detector; + MNN::CV::ImageProcess::Config m_img_config; + MNN::Session* m_sess_mobileface; + MNN::Tensor* m_input_tensor; + MNN::Tensor* m_feature_tensor; +}; + +#endif \ No newline at end of file diff --git a/src/MobileFaceModel_0.cpp b/src/MobileFaceModel_0.cpp new file mode 100644 index 0000000..462572e --- /dev/null +++ b/src/MobileFaceModel_0.cpp @@ -0,0 +1,6 @@ +//v6.6.4 +unsigned char mobile_face_model0[] = { +#include "MobileFace/mnn_v6.64/mobile_face_mnn_v6.64_p1.dat" +}; + +int mobile_face_model0_len = sizeof(mobile_face_model0) / sizeof(mobile_face_model0[0]); diff --git a/src/MobileFaceModel_1.cpp b/src/MobileFaceModel_1.cpp new file mode 100644 index 0000000..e007a42 --- /dev/null +++ b/src/MobileFaceModel_1.cpp @@ -0,0 +1,7 @@ + +//v6.6.4 +unsigned char mobile_face_model1[] = { +#include "MobileFace/mnn_v6.64/mobile_face_mnn_v6.64_p2.dat" +}; + +int mobile_face_model1_len = sizeof(mobile_face_model1) / sizeof(mobile_face_model1[0]); diff --git a/src/MobileFaceModel_2.cpp b/src/MobileFaceModel_2.cpp new file mode 100644 index 0000000..42d93d0 --- /dev/null +++ b/src/MobileFaceModel_2.cpp @@ -0,0 +1,8 @@ + +//v6.6.4 +unsigned char mobile_face_model2[] = { +#include "MobileFace/mnn_v6.64/mobile_face_mnn_v6.64_p3.dat" +}; + +int mobile_face_model2_len = sizeof(mobile_face_model2) / sizeof(mobile_face_model2[0]); + diff --git a/src/TypeInfo.cpp b/src/TypeInfo.cpp index 29aed55..f99ac0f 100644 --- a/src/TypeInfo.cpp +++ b/src/TypeInfo.cpp @@ -1 +1,4 @@ +#include #include "TypeInfo.h" +// #include "MobileFaceFeatureMnn.h" + diff --git a/src/TypeInfo.h b/src/TypeInfo.h index 33094e7..5183d19 100644 --- a/src/TypeInfo.h +++ b/src/TypeInfo.h @@ -12,21 +12,19 @@ typedef enum _ret_t { // #define ERR_FACE_RECT -10 //人脸框无效 // #define ERR_INDEX_INVALID -20 //索引无效 -struct FaceInfo { - float x1; //人脸框 左上x坐标 +#define FACE_BOX_WIDTH(info) static_cast(info.x2 - info.x1) +#define FACE_BOX_HEIGHT(info) static_cast(info.y2 - info.y1) + + + +class FaceInfo { +public: + float x1; //人脸框 左上x坐标 float y1; //人脸框 左上y坐标 float x2; //人脸框 右下x坐标 float y2; //人脸框 右下y坐标 float score; //人脸框 置信度 - float landmarks[10]; //人脸框 关键点坐标 - - int GetWidth() { - return static_cast(x2 - x1); - } - - int GetHeight() { - return static_cast(y2 - y1); - } + float landmarks[10]; //人脸框 关键点坐标 }; #endif \ No newline at end of file