mirror of
https://github.com/deepinsight/insightface.git
synced 2026-07-23 15:17:48 +00:00
Update
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(InspireFaceSDK)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
@@ -15,7 +15,7 @@ else()
|
||||
set(EXTENDED_INFORMATION "${EXTENDED_INFORMATION}@General")
|
||||
endif()
|
||||
set(EXTENDED_INFORMATION "${EXTENDED_INFORMATION} - Build Time: ${BUILD_TIMESTAMP}")
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/information.h.in ${CMAKE_CURRENT_SOURCE_DIR}/information.h)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/information.h.in ${CMAKE_CURRENT_SOURCE_DIR}/include/inspireface/information.h)
|
||||
|
||||
file(GLOB_RECURSE SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
||||
set(SOURCE_FILES ${SOURCE_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/c_api/inspireface.cc) # Add C_API file
|
||||
@@ -97,7 +97,6 @@ if(ISF_ENABLE_APPLE_EXTENSION)
|
||||
find_library(FOUNDATION_LIBRARY Foundation)
|
||||
find_library(COREML_LIBRARY CoreML)
|
||||
find_library(ACCELERATE_LIBRARY Accelerate)
|
||||
find_package(OpenCV REQUIRED)
|
||||
set(LINK_THIRD_LIBS ${LINK_THIRD_LIBS} ${FOUNDATION_LIBRARY} ${COREML_LIBRARY} ${ACCELERATE_LIBRARY})
|
||||
|
||||
# Add objective-c files
|
||||
@@ -128,6 +127,9 @@ if (ISF_ENABLE_RKNN)
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
# Add include directory
|
||||
set(NEED_INCLUDE ${NEED_INCLUDE} ${CMAKE_CURRENT_SOURCE_DIR}/include/inspireface)
|
||||
|
||||
if (ISF_BUILD_LINUX_ARM7 OR ANDROID)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon")
|
||||
endif()
|
||||
@@ -221,7 +223,6 @@ if (ISF_ENABLE_TENSORRT)
|
||||
message(STATUS "\t CUDA_RUNTIME_LIBRARY: ${CUDA_RUNTIME_LIBRARY}")
|
||||
endif()
|
||||
|
||||
|
||||
# Install lib
|
||||
install(TARGETS InspireFace
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/lib
|
||||
@@ -233,10 +234,17 @@ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/c_api/inspireface.h DESTINATION ${CMAK
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/c_api/intypedef.h DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/include)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/herror.h DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/include)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/inspireface/herror.h DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/include)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/version.txt DESTINATION ${CMAKE_INSTALL_PREFIX}/)
|
||||
|
||||
if(ISF_INSTALL_CPP_HEADER)
|
||||
# Install cpp api header file
|
||||
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/inspireface/ DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/include/inspireface/)
|
||||
|
||||
install(DIRECTORY ${INSPIRECV_INCLUDE_PATH}/inspirecv DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/include/)
|
||||
endif()
|
||||
|
||||
if (ISF_ENABLE_RKNN AND ISF_RKNPU_MAJOR STREQUAL "rknpu1")
|
||||
# Install rknn 3rd lib
|
||||
install(FILES ${ISF_RKNN_API_LIB}/librknn_api.so DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/lib)
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
/**
|
||||
* Created by Jingyu Yan
|
||||
* @date 2024-10-01
|
||||
*/
|
||||
|
||||
#include "launch.h"
|
||||
#include "log.h"
|
||||
#include "herror.h"
|
||||
#include "isf_check.h"
|
||||
#include "middleware/cuda_toolkit.h"
|
||||
#if defined(ISF_ENABLE_TENSORRT)
|
||||
#include "middleware/cuda_toolkit.h"
|
||||
#endif
|
||||
|
||||
#define APPLE_EXTENSION_SUFFIX ".bundle"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
std::mutex Launch::mutex_;
|
||||
std::shared_ptr<Launch> Launch::instance_ = nullptr;
|
||||
|
||||
InspireArchive& Launch::getMArchive() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!m_archive_) {
|
||||
throw std::runtime_error("Archive not initialized");
|
||||
}
|
||||
return *m_archive_;
|
||||
}
|
||||
|
||||
std::shared_ptr<Launch> Launch::GetInstance() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!instance_) {
|
||||
instance_ = std::shared_ptr<Launch>(new Launch());
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int32_t Launch::Load(const std::string& path) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
#if defined(ISF_ENABLE_TENSORRT)
|
||||
int32_t support_cuda;
|
||||
auto ret = CheckCudaUsability(&support_cuda);
|
||||
if (ret != HSUCCEED) {
|
||||
INSPIRE_LOGE("An error occurred while checking CUDA device support. Please ensure that your environment supports CUDA!");
|
||||
return ret;
|
||||
}
|
||||
if (!support_cuda) {
|
||||
INSPIRE_LOGE("Your environment does not support CUDA! Please ensure that your environment supports CUDA!");
|
||||
return HERR_DEVICE_CUDA_NOT_SUPPORT;
|
||||
}
|
||||
#endif
|
||||
INSPIREFACE_CHECK_MSG(os::IsExists(path), "The package path does not exist because the launch failed.");
|
||||
#if defined(ISF_ENABLE_APPLE_EXTENSION)
|
||||
BuildAppleExtensionPath(path);
|
||||
#endif
|
||||
if (!m_load_) {
|
||||
try {
|
||||
m_archive_ = std::make_unique<InspireArchive>();
|
||||
m_archive_->ReLoad(path);
|
||||
|
||||
if (m_archive_->QueryStatus() == SARC_SUCCESS) {
|
||||
m_load_ = true;
|
||||
INSPIRE_LOGI("Successfully loaded resources");
|
||||
return HSUCCEED;
|
||||
} else {
|
||||
m_archive_.reset();
|
||||
INSPIRE_LOGE("Failed to load resources");
|
||||
return HERR_ARCHIVE_LOAD_MODEL_FAILURE;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
m_archive_.reset();
|
||||
INSPIRE_LOGE("Exception during resource loading: %s", e.what());
|
||||
return HERR_ARCHIVE_LOAD_MODEL_FAILURE;
|
||||
}
|
||||
} else {
|
||||
INSPIRE_LOGW("There is no need to call launch more than once, as subsequent calls will not affect the initialization.");
|
||||
return HSUCCEED;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t Launch::Reload(const std::string& path) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
INSPIREFACE_CHECK_MSG(os::IsExists(path), "The package path does not exist because the launch failed.");
|
||||
#if defined(ISF_ENABLE_APPLE_EXTENSION)
|
||||
BuildAppleExtensionPath(path);
|
||||
#endif
|
||||
try {
|
||||
// Clean up existing archive if it exists
|
||||
if (m_archive_) {
|
||||
m_archive_.reset();
|
||||
m_load_ = false;
|
||||
}
|
||||
|
||||
// Create and load new archive
|
||||
m_archive_ = std::make_unique<InspireArchive>();
|
||||
m_archive_->ReLoad(path);
|
||||
|
||||
if (m_archive_->QueryStatus() == SARC_SUCCESS) {
|
||||
m_load_ = true;
|
||||
INSPIRE_LOGI("Successfully reloaded resources");
|
||||
return HSUCCEED;
|
||||
} else {
|
||||
m_archive_.reset();
|
||||
INSPIRE_LOGE("Failed to reload resources");
|
||||
return HERR_ARCHIVE_LOAD_MODEL_FAILURE;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
m_archive_.reset();
|
||||
INSPIRE_LOGE("Exception during resource reloading: %s", e.what());
|
||||
return HERR_ARCHIVE_LOAD_MODEL_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
bool Launch::isMLoad() const {
|
||||
return m_load_;
|
||||
}
|
||||
|
||||
void Launch::Unload() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (m_load_) {
|
||||
m_archive_.reset();
|
||||
m_load_ = false;
|
||||
INSPIRE_LOGI("All resources have been successfully unloaded and system is reset.");
|
||||
} else {
|
||||
INSPIRE_LOGW("Unload called but system was not loaded.");
|
||||
}
|
||||
}
|
||||
|
||||
void Launch::SetRockchipDmaHeapPath(const std::string& path) {
|
||||
m_rockchip_dma_heap_path_ = path;
|
||||
}
|
||||
|
||||
std::string Launch::GetRockchipDmaHeapPath() const {
|
||||
return m_rockchip_dma_heap_path_;
|
||||
}
|
||||
|
||||
void Launch::ConfigurationExtensionPath(const std::string& path) {
|
||||
#if defined(ISF_ENABLE_APPLE_EXTENSION)
|
||||
INSPIREFACE_CHECK_MSG(os::IsDir(path), "The apple extension path is not a directory, please check.");
|
||||
#endif
|
||||
INSPIREFACE_CHECK_MSG(os::IsExists(path), "The extension path is not exists, please check.");
|
||||
m_extension_path_ = path;
|
||||
}
|
||||
|
||||
std::string Launch::GetExtensionPath() const {
|
||||
return m_extension_path_;
|
||||
}
|
||||
|
||||
void Launch::SetGlobalCoreMLInferenceMode(InferenceWrapper::SpecialBackend mode) {
|
||||
m_global_coreml_inference_mode_ = mode;
|
||||
if (m_global_coreml_inference_mode_ == InferenceWrapper::COREML_CPU) {
|
||||
INSPIRE_LOGW("Global CoreML Compute Units set to CPU Only.");
|
||||
} else if (m_global_coreml_inference_mode_ == InferenceWrapper::COREML_GPU) {
|
||||
INSPIRE_LOGW("Global CoreML Compute Units set to CPU and GPU.");
|
||||
} else if (m_global_coreml_inference_mode_ == InferenceWrapper::COREML_ANE) {
|
||||
INSPIRE_LOGW("Global CoreML Compute Units set to Auto Switch (ANE, GPU, CPU).");
|
||||
}
|
||||
}
|
||||
|
||||
InferenceWrapper::SpecialBackend Launch::GetGlobalCoreMLInferenceMode() const {
|
||||
return m_global_coreml_inference_mode_;
|
||||
}
|
||||
|
||||
void Launch::BuildAppleExtensionPath(const std::string& resource_path) {
|
||||
std::string basename = os::Basename(resource_path);
|
||||
m_extension_path_ = os::PathJoin(os::Dirname(resource_path), basename + APPLE_EXTENSION_SUFFIX);
|
||||
INSPIREFACE_CHECK_MSG(os::IsExists(m_extension_path_), "The apple extension path is not exists, please check.");
|
||||
INSPIREFACE_CHECK_MSG(os::IsDir(m_extension_path_), "The apple extension path is not a directory, please check.");
|
||||
}
|
||||
|
||||
void Launch::SetCudaDeviceId(int32_t device_id) {
|
||||
m_cuda_device_id_ = device_id;
|
||||
}
|
||||
|
||||
int32_t Launch::GetCudaDeviceId() const {
|
||||
return m_cuda_device_id_;
|
||||
}
|
||||
|
||||
} // namespace inspire
|
||||
@@ -7,14 +7,17 @@
|
||||
#include "intypedef.h"
|
||||
#include "inspireface_internal.h"
|
||||
#include "information.h"
|
||||
#include "feature_hub/feature_hub_db.h"
|
||||
#include "initialization_module/launch.h"
|
||||
#include "initialization_module/resource_manage.h"
|
||||
#include "recognition_module/similarity_converter.h"
|
||||
#include "feature_hub_db.h"
|
||||
#include <launch.h>
|
||||
#include "runtime_module/resource_manage.h"
|
||||
#include "similarity_converter.h"
|
||||
#include "middleware/inference_wrapper/inference_wrapper.h"
|
||||
#if defined(ISF_ENABLE_TENSORRT)
|
||||
#include "middleware/cuda_toolkit.h"
|
||||
#include "cuda_toolkit.h"
|
||||
#endif
|
||||
#include <cstdarg>
|
||||
|
||||
#define FACE_FEATURE_SIZE 512 ///< Temporary setup
|
||||
|
||||
using namespace inspire;
|
||||
|
||||
@@ -345,6 +348,31 @@ HResult HFReleaseInspireFaceSession(HFSession handle) {
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFSwitchLandmarkEngine(HFSessionLandmarkEngine engine) {
|
||||
inspire::Launch::LandmarkEngine type;
|
||||
if (engine == HF_LANDMARK_HYPLMV2_0_25) {
|
||||
type = inspire::Launch::LANDMARK_HYPLMV2_0_25;
|
||||
} else if (engine == HF_LANDMARK_HYPLMV2_0_50) {
|
||||
type = inspire::Launch::LANDMARK_HYPLMV2_0_50;
|
||||
} else if (engine == HF_LANDMARK_INSIGHTFACE_2D106_TRACK) {
|
||||
type = inspire::Launch::LANDMARK_INSIGHTFACE_2D106_TRACK;
|
||||
} else {
|
||||
INSPIRE_LOGE("Unsupported Landmark engine.");
|
||||
return HERR_INVALID_PARAM;
|
||||
}
|
||||
INSPIREFACE_CONTEXT->SwitchLandmarkEngine(type);
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFQuerySupportedPixelLevelsForFaceDetection(PHFFaceDetectPixelList pixel_levels) {
|
||||
auto ret = INSPIREFACE_CONTEXT->GetFaceDetectPixelList();
|
||||
pixel_levels->size = ret.size();
|
||||
for (int i = 0; i < ret.size(); i++) {
|
||||
pixel_levels->pixel_level[i] = ret[i];
|
||||
}
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFCreateInspireFaceSession(HFSessionCustomParameter parameter, HFDetectMode detectMode, HInt32 maxDetectFaceNum, HInt32 detectPixelLevel,
|
||||
HInt32 trackByDetectModeFPS, HFSession *handle) {
|
||||
inspire::ContextCustomParameter param;
|
||||
@@ -355,7 +383,7 @@ HResult HFCreateInspireFaceSession(HFSessionCustomParameter parameter, HFDetectM
|
||||
param.enable_ir_liveness = parameter.enable_ir_liveness;
|
||||
param.enable_recognition = parameter.enable_recognition;
|
||||
param.enable_face_attribute = parameter.enable_face_attribute;
|
||||
param.enable_detect_mode_landmark = parameter.enable_detect_mode_landmark;
|
||||
param.enable_face_pose = parameter.enable_face_pose;
|
||||
inspire::DetectModuleMode detMode = inspire::DETECT_MODE_ALWAYS_DETECT;
|
||||
if (detectMode == HF_DETECT_MODE_LIGHT_TRACK) {
|
||||
detMode = inspire::DETECT_MODE_LIGHT_TRACK;
|
||||
@@ -401,8 +429,8 @@ HResult HFCreateInspireFaceSessionOptional(HOption customOption, HFDetectMode de
|
||||
if (customOption & HF_ENABLE_INTERACTION) {
|
||||
param.enable_interaction_liveness = true;
|
||||
}
|
||||
if (customOption & HF_ENABLE_DETECT_MODE_LANDMARK) {
|
||||
param.enable_detect_mode_landmark = true;
|
||||
if (customOption & HF_ENABLE_FACE_POSE) {
|
||||
param.enable_face_pose = true;
|
||||
}
|
||||
inspire::DetectModuleMode detMode = inspire::DETECT_MODE_ALWAYS_DETECT;
|
||||
if (detectMode == HF_DETECT_MODE_LIGHT_TRACK) {
|
||||
@@ -427,56 +455,59 @@ HResult HFCreateInspireFaceSessionOptional(HOption customOption, HFDetectMode de
|
||||
|
||||
HResult HFLaunchInspireFace(HPath resourcePath) {
|
||||
std::string path(resourcePath);
|
||||
return INSPIRE_LAUNCH->Load(resourcePath);
|
||||
return INSPIREFACE_CONTEXT->Load(resourcePath);
|
||||
}
|
||||
|
||||
HResult HFReloadInspireFace(HPath resourcePath) {
|
||||
std::string path(resourcePath);
|
||||
return INSPIRE_LAUNCH->Reload(resourcePath);
|
||||
return INSPIREFACE_CONTEXT->Reload(resourcePath);
|
||||
}
|
||||
|
||||
HResult HFTerminateInspireFace() {
|
||||
INSPIRE_LAUNCH->Unload();
|
||||
INSPIREFACE_CONTEXT->Unload();
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFQueryInspireFaceLaunchStatus(HInt32 *status) {
|
||||
*status = INSPIRE_LAUNCH->isMLoad();
|
||||
*status = INSPIREFACE_CONTEXT->isMLoad();
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFFeatureHubDataDisable() {
|
||||
return FEATURE_HUB_DB->DisableHub();
|
||||
return INSPIREFACE_FEATURE_HUB->DisableHub();
|
||||
}
|
||||
|
||||
HResult HFSetExpansiveHardwareRockchipDmaHeapPath(HPath path) {
|
||||
INSPIRE_LAUNCH->SetRockchipDmaHeapPath(path);
|
||||
INSPIREFACE_CONTEXT->SetRockchipDmaHeapPath(path);
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFQueryExpansiveHardwareRockchipDmaHeapPath(HString path) {
|
||||
strcpy(path, INSPIRE_LAUNCH->GetRockchipDmaHeapPath().c_str());
|
||||
strcpy(path, INSPIREFACE_CONTEXT->GetRockchipDmaHeapPath().c_str());
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFSetAppleCoreMLInferenceMode(HFAppleCoreMLInferenceMode mode) {
|
||||
if (mode == HF_APPLE_COREML_INFERENCE_MODE_CPU) {
|
||||
INSPIRE_LAUNCH->SetGlobalCoreMLInferenceMode(InferenceWrapper::COREML_CPU);
|
||||
INSPIREFACE_CONTEXT->SetGlobalCoreMLInferenceMode(inspire::Launch::NN_INFERENCE_CPU);
|
||||
} else if (mode == HF_APPLE_COREML_INFERENCE_MODE_GPU) {
|
||||
INSPIRE_LAUNCH->SetGlobalCoreMLInferenceMode(InferenceWrapper::COREML_GPU);
|
||||
INSPIREFACE_CONTEXT->SetGlobalCoreMLInferenceMode(inspire::Launch::NN_INFERENCE_COREML_GPU);
|
||||
} else if (mode == HF_APPLE_COREML_INFERENCE_MODE_ANE) {
|
||||
INSPIRE_LAUNCH->SetGlobalCoreMLInferenceMode(InferenceWrapper::COREML_ANE);
|
||||
INSPIREFACE_CONTEXT->SetGlobalCoreMLInferenceMode(inspire::Launch::NN_INFERENCE_COREML_ANE);
|
||||
} else {
|
||||
INSPIRE_LOGE("Unsupported Apple CoreML inference mode.");
|
||||
return HERR_INVALID_PARAM;
|
||||
}
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFSetCudaDeviceId(int32_t device_id) {
|
||||
INSPIRE_LAUNCH->SetCudaDeviceId(device_id);
|
||||
INSPIREFACE_CONTEXT->SetCudaDeviceId(device_id);
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFGetCudaDeviceId(int32_t *device_id) {
|
||||
*device_id = INSPIRE_LAUNCH->GetCudaDeviceId();
|
||||
*device_id = INSPIREFACE_CONTEXT->GetCudaDeviceId();
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
@@ -530,7 +561,7 @@ HResult HFFeatureHubDataEnable(HFFeatureHubConfiguration configuration) {
|
||||
param.enable_persistence = configuration.enablePersistence;
|
||||
param.recognition_threshold = configuration.searchThreshold;
|
||||
param.search_mode = (inspire::SearchMode)configuration.searchMode;
|
||||
auto ret = FEATURE_HUB_DB->EnableHub(param);
|
||||
auto ret = INSPIREFACE_FEATURE_HUB->EnableHub(param);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -545,6 +576,20 @@ HResult HFSessionSetTrackPreviewSize(HFSession session, HInt32 previewSize) {
|
||||
return ctx->impl.SetTrackPreviewSize(previewSize);
|
||||
}
|
||||
|
||||
HResult HFSessionGetTrackPreviewSize(HFSession session, HInt32 *previewSize) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession *)session;
|
||||
if (ctx == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
*previewSize = ctx->impl.GetTrackPreviewSize();
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HResult HFSessionSetFilterMinimumFacePixelSize(HFSession session, HInt32 minSize) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
@@ -615,6 +660,8 @@ HResult HFSessionSetTrackModeDetectInterval(HFSession session, HInt32 num) {
|
||||
return ctx->impl.SetTrackModeDetectInterval(num);
|
||||
}
|
||||
|
||||
|
||||
|
||||
HResult HFExecuteFaceTrack(HFSession session, HFImageStream streamHandle, PHFMultipleFaceData results) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
@@ -643,16 +690,28 @@ HResult HFExecuteFaceTrack(HFSession session, HFImageStream streamHandle, PHFMul
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFSessionLastFaceDetectionGetDebugPreviewImageSize(HFSession session, HInt32 *size) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession *)session;
|
||||
if (ctx == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
*size = ctx->impl.GetDebugPreviewImageSize();
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFCopyFaceBasicToken(HFFaceBasicToken token, HPBuffer buffer, HInt32 bufferSize) {
|
||||
if (bufferSize < sizeof(inspire::HyperFaceData)) {
|
||||
if (bufferSize < sizeof(inspire::FaceTrackWrap)) {
|
||||
return HERR_INVALID_BUFFER_SIZE;
|
||||
}
|
||||
std::memcpy(buffer, token.data, sizeof(inspire::HyperFaceData));
|
||||
std::memcpy(buffer, token.data, sizeof(inspire::FaceTrackWrap));
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFGetFaceBasicTokenSize(HPInt32 bufferSize) {
|
||||
*bufferSize = sizeof(inspire::HyperFaceData);
|
||||
*bufferSize = sizeof(inspire::FaceTrackWrap);
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
@@ -668,7 +727,7 @@ HResult HFGetFaceDenseLandmarkFromFaceToken(HFFaceBasicToken singleFace, HPoint2
|
||||
inspire::FaceBasicData data;
|
||||
data.dataSize = singleFace.size;
|
||||
data.data = singleFace.data;
|
||||
HyperFaceData face = {0};
|
||||
FaceTrackWrap face = {0};
|
||||
HInt32 ret;
|
||||
ret = RunDeserializeHyperFaceData((char *)data.data, data.dataSize, face);
|
||||
if (ret != HSUCCEED) {
|
||||
@@ -692,7 +751,7 @@ HResult HFGetFaceFiveKeyPointsFromFaceToken(HFFaceBasicToken singleFace, HPoint2
|
||||
inspire::FaceBasicData data;
|
||||
data.dataSize = singleFace.size;
|
||||
data.data = singleFace.data;
|
||||
HyperFaceData face = {0};
|
||||
FaceTrackWrap face = {0};
|
||||
HInt32 ret;
|
||||
ret = RunDeserializeHyperFaceData((char *)data.data, data.dataSize, face);
|
||||
if (ret != HSUCCEED) {
|
||||
@@ -730,7 +789,7 @@ HResult HFSessionPrintTrackCostSpend(HFSession session) {
|
||||
}
|
||||
|
||||
HResult HFFeatureHubFaceSearchThresholdSetting(float threshold) {
|
||||
FEATURE_HUB_DB->SetRecognitionThreshold(threshold);
|
||||
INSPIREFACE_FEATURE_HUB->SetRecognitionThreshold(threshold);
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
@@ -762,6 +821,35 @@ HResult HFFaceFeatureExtract(HFSession session, HFImageStream streamHandle, HFFa
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFFaceFeatureExtractTo(HFSession session, HFImageStream streamHandle, HFFaceBasicToken singleFace, HFFaceFeature feature) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
if (streamHandle == nullptr) {
|
||||
return HERR_INVALID_IMAGE_STREAM_HANDLE;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession *)session;
|
||||
if (ctx == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
HF_CameraStream *stream = (HF_CameraStream *)streamHandle;
|
||||
if (stream == nullptr) {
|
||||
return HERR_INVALID_IMAGE_STREAM_HANDLE;
|
||||
}
|
||||
if (singleFace.data == nullptr || singleFace.size <= 0) {
|
||||
return HERR_INVALID_FACE_TOKEN;
|
||||
}
|
||||
inspire::FaceBasicData data;
|
||||
data.dataSize = singleFace.size;
|
||||
data.data = singleFace.data;
|
||||
auto ret = ctx->impl.FaceFeatureExtract(stream->impl, data);
|
||||
for (int i = 0; i < ctx->impl.GetFaceFeatureCache().size(); ++i) {
|
||||
feature.data[i] = ctx->impl.GetFaceFeatureCache()[i];
|
||||
}
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFFaceFeatureExtractCpy(HFSession session, HFImageStream streamHandle, HFFaceBasicToken singleFace, HPFloat feature) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
@@ -791,6 +879,25 @@ HResult HFFaceFeatureExtractCpy(HFSession session, HFImageStream streamHandle, H
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFCreateFaceFeature(PHFFaceFeature feature) {
|
||||
if (feature == nullptr) {
|
||||
return HERR_INVALID_FACE_FEATURE;
|
||||
}
|
||||
feature->size = FACE_FEATURE_SIZE;
|
||||
feature->data = new HFloat[FACE_FEATURE_SIZE];
|
||||
RESOURCE_MANAGE->createFaceFeature((long)feature);
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFReleaseFaceFeature(PHFFaceFeature feature) {
|
||||
if (feature == nullptr) {
|
||||
return HERR_INVALID_FACE_FEATURE;
|
||||
}
|
||||
delete[] feature->data;
|
||||
RESOURCE_MANAGE->releaseFaceFeature((long)feature);
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFFaceGetFaceAlignmentImage(HFSession session, HFImageStream streamHandle, HFFaceBasicToken singleFace, HFImageBitmap *handle) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
@@ -824,6 +931,30 @@ HResult HFFaceGetFaceAlignmentImage(HFSession session, HFImageStream streamHandl
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFFaceFeatureExtractWithAlignmentImage(HFSession session, HFImageStream streamHandle, HFFaceFeature feature) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
if (streamHandle == nullptr) {
|
||||
return HERR_INVALID_IMAGE_STREAM_HANDLE;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession *)session;
|
||||
if (ctx == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
HF_CameraStream *stream = (HF_CameraStream *)streamHandle;
|
||||
if (stream == nullptr) {
|
||||
return HERR_INVALID_IMAGE_STREAM_HANDLE;
|
||||
}
|
||||
Embedded embedded;
|
||||
float norm;
|
||||
auto ret = ctx->impl.FaceRecognitionModule()->FaceExtractWithAlignmentImage(stream->impl, embedded, norm);
|
||||
for (int i = 0; i < embedded.size(); ++i) {
|
||||
feature.data[i] = embedded[i];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFFaceComparison(HFFaceFeature feature1, HFFaceFeature feature2, HPFloat result) {
|
||||
if (feature1.data == nullptr || feature2.data == nullptr) {
|
||||
return HERR_INVALID_FACE_FEATURE;
|
||||
@@ -834,14 +965,14 @@ HResult HFFaceComparison(HFFaceFeature feature1, HFFaceFeature feature2, HPFloat
|
||||
}
|
||||
*result = 0.0f;
|
||||
float res = -1.0f;
|
||||
auto ret = FEATURE_HUB_DB->CosineSimilarity(feature1.data, feature2.data, feature1.size, res);
|
||||
auto ret = INSPIREFACE_FEATURE_HUB->CosineSimilarity(feature1.data, feature2.data, feature1.size, res);
|
||||
*result = res;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFGetRecommendedCosineThreshold(HPFloat threshold) {
|
||||
if (!INSPIRE_LAUNCH->isMLoad()) {
|
||||
if (!INSPIREFACE_CONTEXT->isMLoad()) {
|
||||
INSPIRE_LOGW("Inspireface is not launched, using default threshold 0.48");
|
||||
}
|
||||
*threshold = SIMILARITY_CONVERTER_GET_RECOMMENDED_COSINE_THRESHOLD();
|
||||
@@ -849,7 +980,7 @@ HResult HFGetRecommendedCosineThreshold(HPFloat threshold) {
|
||||
}
|
||||
|
||||
HResult HFCosineSimilarityConvertToPercentage(HFloat similarity, HPFloat result) {
|
||||
if (!INSPIRE_LAUNCH->isMLoad()) {
|
||||
if (!INSPIREFACE_CONTEXT->isMLoad()) {
|
||||
INSPIRE_LOGW("Inspireface is not launched.");
|
||||
}
|
||||
*result = SIMILARITY_CONVERTER_RUN(similarity);
|
||||
@@ -857,7 +988,7 @@ HResult HFCosineSimilarityConvertToPercentage(HFloat similarity, HPFloat result)
|
||||
}
|
||||
|
||||
HResult HFUpdateCosineSimilarityConverter(HFSimilarityConverterConfig config) {
|
||||
if (!INSPIRE_LAUNCH->isMLoad()) {
|
||||
if (!INSPIREFACE_CONTEXT->isMLoad()) {
|
||||
INSPIRE_LOGW("Inspireface is not launched.");
|
||||
}
|
||||
inspire::SimilarityConverterConfig cfg;
|
||||
@@ -871,7 +1002,7 @@ HResult HFUpdateCosineSimilarityConverter(HFSimilarityConverterConfig config) {
|
||||
}
|
||||
|
||||
HResult HFGetCosineSimilarityConverter(PHFSimilarityConverterConfig config) {
|
||||
if (!INSPIRE_LAUNCH->isMLoad()) {
|
||||
if (!INSPIREFACE_CONTEXT->isMLoad()) {
|
||||
INSPIRE_LOGW("Inspireface is not launched.");
|
||||
}
|
||||
inspire::SimilarityConverterConfig cfg = SIMILARITY_CONVERTER_GET_CONFIG();
|
||||
@@ -884,7 +1015,7 @@ HResult HFGetCosineSimilarityConverter(PHFSimilarityConverterConfig config) {
|
||||
}
|
||||
|
||||
HResult HFGetFeatureLength(HPInt32 num) {
|
||||
*num = 512;
|
||||
*num = FACE_FEATURE_SIZE;
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
@@ -898,7 +1029,7 @@ HResult HFFeatureHubInsertFeature(HFFaceFeatureIdentity featureIdentity, HPFaceI
|
||||
for (int i = 0; i < featureIdentity.feature->size; ++i) {
|
||||
feat.push_back(featureIdentity.feature->data[i]);
|
||||
}
|
||||
HInt32 ret = FEATURE_HUB_DB->FaceFeatureInsert(feat, featureIdentity.id, *allocId);
|
||||
HInt32 ret = INSPIREFACE_FEATURE_HUB->FaceFeatureInsert(feat, featureIdentity.id, *allocId);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -914,10 +1045,10 @@ HResult HFFeatureHubFaceSearch(HFFaceFeature searchFeature, HPFloat confidence,
|
||||
}
|
||||
*confidence = -1.0f;
|
||||
inspire::FaceSearchResult result;
|
||||
HInt32 ret = FEATURE_HUB_DB->SearchFaceFeature(feat, result);
|
||||
mostSimilar->feature = (HFFaceFeature *)FEATURE_HUB_DB->GetFaceFeaturePtrCache().get();
|
||||
mostSimilar->feature->data = (HFloat *)FEATURE_HUB_DB->GetSearchFaceFeatureCache().data();
|
||||
mostSimilar->feature->size = FEATURE_HUB_DB->GetSearchFaceFeatureCache().size();
|
||||
HInt32 ret = INSPIREFACE_FEATURE_HUB->SearchFaceFeature(feat, result);
|
||||
mostSimilar->feature = (HFFaceFeature *)INSPIREFACE_FEATURE_HUB->GetFaceFeaturePtrCache().get();
|
||||
mostSimilar->feature->data = (HFloat *)INSPIREFACE_FEATURE_HUB->GetSearchFaceFeatureCache().data();
|
||||
mostSimilar->feature->size = INSPIREFACE_FEATURE_HUB->GetSearchFaceFeatureCache().size();
|
||||
mostSimilar->id = result.id;
|
||||
if (mostSimilar->id != -1) {
|
||||
*confidence = result.similarity;
|
||||
@@ -935,18 +1066,18 @@ HResult HFFeatureHubFaceSearchTopK(HFFaceFeature searchFeature, HInt32 topK, PHF
|
||||
for (int i = 0; i < searchFeature.size; ++i) {
|
||||
feat.push_back(searchFeature.data[i]);
|
||||
}
|
||||
HInt32 ret = FEATURE_HUB_DB->SearchFaceFeatureTopKCache(feat, topK);
|
||||
HInt32 ret = INSPIREFACE_FEATURE_HUB->SearchFaceFeatureTopKCache(feat, topK);
|
||||
if (ret == HSUCCEED) {
|
||||
results->size = FEATURE_HUB_DB->GetTopKConfidence().size();
|
||||
results->confidence = FEATURE_HUB_DB->GetTopKConfidence().data();
|
||||
results->ids = FEATURE_HUB_DB->GetTopKCustomIdsCache().data();
|
||||
results->size = INSPIREFACE_FEATURE_HUB->GetTopKConfidence().size();
|
||||
results->confidence = INSPIREFACE_FEATURE_HUB->GetTopKConfidence().data();
|
||||
results->ids = INSPIREFACE_FEATURE_HUB->GetTopKCustomIdsCache().data();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFFeatureHubFaceRemove(HFaceId id) {
|
||||
auto ret = FEATURE_HUB_DB->FaceFeatureRemove(id);
|
||||
auto ret = INSPIREFACE_FEATURE_HUB->FaceFeatureRemove(id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -960,18 +1091,18 @@ HResult HFFeatureHubFaceUpdate(HFFaceFeatureIdentity featureIdentity) {
|
||||
feat.push_back(featureIdentity.feature->data[i]);
|
||||
}
|
||||
|
||||
auto ret = FEATURE_HUB_DB->FaceFeatureUpdate(feat, featureIdentity.id);
|
||||
auto ret = INSPIREFACE_FEATURE_HUB->FaceFeatureUpdate(feat, featureIdentity.id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFFeatureHubGetFaceIdentity(HFaceId id, PHFFaceFeatureIdentity identity) {
|
||||
auto ret = FEATURE_HUB_DB->GetFaceFeature(id);
|
||||
auto ret = INSPIREFACE_FEATURE_HUB->GetFaceFeature(id);
|
||||
if (ret == HSUCCEED) {
|
||||
identity->id = id;
|
||||
identity->feature = (HFFaceFeature *)FEATURE_HUB_DB->GetFaceFeaturePtrCache().get();
|
||||
identity->feature->data = (HFloat *)FEATURE_HUB_DB->GetFaceFeaturePtrCache()->data;
|
||||
identity->feature->size = FEATURE_HUB_DB->GetFaceFeaturePtrCache()->dataSize;
|
||||
identity->feature = (HFFaceFeature *)INSPIREFACE_FEATURE_HUB->GetFaceFeaturePtrCache().get();
|
||||
identity->feature->data = (HFloat *)INSPIREFACE_FEATURE_HUB->GetFaceFeaturePtrCache()->data;
|
||||
identity->feature->size = INSPIREFACE_FEATURE_HUB->GetFaceFeaturePtrCache()->dataSize;
|
||||
} else {
|
||||
identity->id = -1;
|
||||
}
|
||||
@@ -1010,10 +1141,9 @@ HResult HFMultipleFacePipelineProcess(HFSession session, HFImageStream streamHan
|
||||
param.enable_ir_liveness = parameter.enable_ir_liveness;
|
||||
param.enable_recognition = parameter.enable_recognition;
|
||||
param.enable_face_attribute = parameter.enable_face_attribute;
|
||||
param.enable_detect_mode_landmark = parameter.enable_detect_mode_landmark;
|
||||
|
||||
HResult ret;
|
||||
std::vector<inspire::HyperFaceData> data;
|
||||
std::vector<inspire::FaceTrackWrap> data;
|
||||
data.resize(faces->detectedNum);
|
||||
for (int i = 0; i < faces->detectedNum; ++i) {
|
||||
auto &face = data[i];
|
||||
@@ -1072,12 +1202,12 @@ HResult HFMultipleFacePipelineProcessOptional(HFSession session, HFImageStream s
|
||||
if (customOption & HF_ENABLE_INTERACTION) {
|
||||
param.enable_interaction_liveness = true;
|
||||
}
|
||||
if (customOption & HF_ENABLE_DETECT_MODE_LANDMARK) {
|
||||
param.enable_detect_mode_landmark = true;
|
||||
if (customOption & HF_ENABLE_FACE_POSE) {
|
||||
param.enable_face_pose = true;
|
||||
}
|
||||
|
||||
HResult ret;
|
||||
std::vector<inspire::HyperFaceData> data;
|
||||
std::vector<inspire::FaceTrackWrap> data;
|
||||
data.resize(faces->detectedNum);
|
||||
for (int i = 0; i < faces->detectedNum; ++i) {
|
||||
auto &face = data[i];
|
||||
@@ -1206,20 +1336,20 @@ HResult HFGetFaceAttributeResult(HFSession session, PHFFaceAttributeResult resul
|
||||
}
|
||||
|
||||
HResult HFFeatureHubGetFaceCount(HInt32 *count) {
|
||||
*count = FEATURE_HUB_DB->GetFaceFeatureCount();
|
||||
*count = INSPIREFACE_FEATURE_HUB->GetFaceFeatureCount();
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFFeatureHubViewDBTable() {
|
||||
FEATURE_HUB_DB->ViewDBTable();
|
||||
INSPIREFACE_FEATURE_HUB->ViewDBTable();
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFFeatureHubGetExistingIds(PHFFeatureHubExistingIds ids) {
|
||||
auto ret = FEATURE_HUB_DB->GetAllIds();
|
||||
auto ret = INSPIREFACE_FEATURE_HUB->GetAllIds();
|
||||
if (ret == HSUCCEED) {
|
||||
ids->size = FEATURE_HUB_DB->GetExistingIds().size();
|
||||
ids->ids = FEATURE_HUB_DB->GetExistingIds().data();
|
||||
ids->size = INSPIREFACE_FEATURE_HUB->GetExistingIds().size();
|
||||
ids->ids = INSPIREFACE_FEATURE_HUB->GetExistingIds().data();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -24,16 +24,19 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HF_ENABLE_NONE 0x00000000 ///< Flag to enable no features.
|
||||
#define HF_ENABLE_FACE_RECOGNITION 0x00000002 ///< Flag to enable face recognition feature.
|
||||
#define HF_ENABLE_LIVENESS 0x00000004 ///< Flag to enable RGB liveness detection feature.
|
||||
#define HF_ENABLE_IR_LIVENESS 0x00000008 ///< Flag to enable IR (Infrared) liveness detection feature.
|
||||
#define HF_ENABLE_MASK_DETECT 0x00000010 ///< Flag to enable mask detection feature.
|
||||
#define HF_ENABLE_FACE_ATTRIBUTE 0x00000020 ///< Flag to enable face attribute prediction feature.
|
||||
#define HF_ENABLE_PLACEHOLDER_ 0x00000040 ///< -
|
||||
#define HF_ENABLE_QUALITY 0x00000080 ///< Flag to enable face quality assessment feature.
|
||||
#define HF_ENABLE_INTERACTION 0x00000100 ///< Flag to enable interaction feature.
|
||||
#define HF_ENABLE_DETECT_MODE_LANDMARK 0x00000200 ///< Flag to enable landmark detection in detection mode
|
||||
#define HF_STATUS_ENABLE 1 ///< The status of the feature is enabled.
|
||||
#define HF_STATUS_DISABLE 0 ///< The status of the feature is disabled.
|
||||
|
||||
#define HF_ENABLE_NONE 0x00000000 ///< Flag to enable no features.
|
||||
#define HF_ENABLE_FACE_RECOGNITION 0x00000002 ///< Flag to enable face recognition feature.
|
||||
#define HF_ENABLE_LIVENESS 0x00000004 ///< Flag to enable RGB liveness detection feature.
|
||||
#define HF_ENABLE_IR_LIVENESS 0x00000008 ///< Flag to enable IR (Infrared) liveness detection feature.
|
||||
#define HF_ENABLE_MASK_DETECT 0x00000010 ///< Flag to enable mask detection feature.
|
||||
#define HF_ENABLE_FACE_ATTRIBUTE 0x00000020 ///< Flag to enable face attribute prediction feature.
|
||||
#define HF_ENABLE_PLACEHOLDER_ 0x00000040 ///< -
|
||||
#define HF_ENABLE_QUALITY 0x00000080 ///< Flag to enable face quality assessment feature.
|
||||
#define HF_ENABLE_INTERACTION 0x00000100 ///< Flag to enable interaction feature.
|
||||
#define HF_ENABLE_FACE_POSE 0x00000200 ///< Flag to enable face pose estimation feature.
|
||||
|
||||
/**
|
||||
* Camera stream format.
|
||||
@@ -385,6 +388,7 @@ typedef struct HFSessionCustomParameter {
|
||||
HInt32 enable_face_attribute; ///< Enable face attribute prediction feature.
|
||||
HInt32 enable_interaction_liveness; ///< Enable interaction for liveness detection feature.
|
||||
HInt32 enable_detect_mode_landmark; ///< Enable landmark detection in detection mode
|
||||
HInt32 enable_face_pose; ///< Enable face pose estimation feature.
|
||||
} HFSessionCustomParameter, *PHFSessionCustomParameter;
|
||||
|
||||
/**
|
||||
@@ -400,6 +404,38 @@ typedef enum HFDetectMode {
|
||||
// to use it).
|
||||
} HFDetectMode;
|
||||
|
||||
/**
|
||||
* @brief Enum for landmark engine.
|
||||
*/
|
||||
typedef enum HFSessionLandmarkEngine {
|
||||
HF_LANDMARK_HYPLMV2_0_25 = 0, ///< Hyplmkv2 0.25, default
|
||||
HF_LANDMARK_HYPLMV2_0_50 = 1, ///< Hyplmkv2 0.50
|
||||
HF_LANDMARK_INSIGHTFACE_2D106_TRACK = 2, ///< InsightFace 2d106 track
|
||||
} HFSessionLandmarkEngine;
|
||||
|
||||
/**
|
||||
* @brief Global switch the landmark engine. Set it globally before creating a session.
|
||||
* If it is changed, a new session needs to be created for it to be effective.
|
||||
* @param engine The landmark engine to be set.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
* */
|
||||
HYPER_CAPI_EXPORT extern HResult HFSwitchLandmarkEngine(HFSessionLandmarkEngine engine);
|
||||
|
||||
/**
|
||||
* @brief Enum for supported pixel levels for face detection.
|
||||
*/
|
||||
typedef struct HFFaceDetectPixelList {
|
||||
HInt32 pixel_level[20];
|
||||
HInt32 size;
|
||||
} HFFaceDetectPixelList, *PHFFaceDetectPixelList;
|
||||
|
||||
/**
|
||||
* @brief Query the supported pixel levels for face detection. It must be used before starting.
|
||||
* @param pixel_levels Pointer to the array of supported pixel levels.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
* */
|
||||
HYPER_CAPI_EXPORT extern HResult HFQuerySupportedPixelLevelsForFaceDetection(PHFFaceDetectPixelList pixel_levels);
|
||||
|
||||
/**
|
||||
* @brief Create a session from a resource file.
|
||||
*
|
||||
@@ -488,6 +524,14 @@ typedef struct HFMultipleFaceData {
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFSessionSetTrackPreviewSize(HFSession session, HInt32 previewSize);
|
||||
|
||||
/**
|
||||
* @brief Get the track preview size in the session.
|
||||
* @param session Handle to the session.
|
||||
* @param previewSize The size of the preview for tracking.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFSessionGetTrackPreviewSize(HFSession session, HInt32 *previewSize);
|
||||
|
||||
/**
|
||||
* @brief Set the minimum number of face pixels that the face detector can capture, and people below
|
||||
* this number will be filtered.
|
||||
@@ -534,6 +578,7 @@ HYPER_CAPI_EXPORT extern HResult HFSessionSetTrackModeNumSmoothCacheFrame(HFSess
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFSessionSetTrackModeDetectInterval(HFSession session, HInt32 num);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Run face tracking in the session.
|
||||
*
|
||||
@@ -544,6 +589,14 @@ HYPER_CAPI_EXPORT extern HResult HFSessionSetTrackModeDetectInterval(HFSession s
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFExecuteFaceTrack(HFSession session, HFImageStream streamHandle, PHFMultipleFaceData results);
|
||||
|
||||
/**
|
||||
* @brief Gets the size of the debug preview image for the last face detection in the session.
|
||||
* @param session Handle to the session.
|
||||
* @param size The size of the preview for tracking.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFSessionLastFaceDetectionGetDebugPreviewImageSize(HFSession session, HInt32 *size);
|
||||
|
||||
/**
|
||||
* @brief Copies the data from a HF_FaceBasicToken to a specified buffer.
|
||||
*
|
||||
@@ -641,6 +694,17 @@ typedef struct HFFaceFeature {
|
||||
HYPER_CAPI_EXPORT extern HResult HFFaceFeatureExtract(HFSession session, HFImageStream streamHandle, HFFaceBasicToken singleFace,
|
||||
PHFFaceFeature feature);
|
||||
|
||||
/**
|
||||
* @brief Extract face features to the HFFaceFeature that has applied for memory in advance.
|
||||
* @param session Handle to the session.
|
||||
* @param streamHandle Handle to the data buffer representing the camera stream component.
|
||||
* @param singleFace Basic token representing a single face.
|
||||
* @param feature Pointer to the buffer where the extracted feature will be copied.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFFaceFeatureExtractTo(HFSession session, HFImageStream streamHandle, HFFaceBasicToken singleFace,
|
||||
HFFaceFeature feature);
|
||||
|
||||
/**
|
||||
* @brief Extract a face feature from a given face and copy it to the provided feature buffer.
|
||||
*
|
||||
@@ -652,6 +716,20 @@ HYPER_CAPI_EXPORT extern HResult HFFaceFeatureExtract(HFSession session, HFImage
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFFaceFeatureExtractCpy(HFSession session, HFImageStream streamHandle, HFFaceBasicToken singleFace, HPFloat feature);
|
||||
|
||||
/**
|
||||
* @brief Create a face feature. Will allocate memory.
|
||||
* @param feature Pointer to the face feature.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFCreateFaceFeature(PHFFaceFeature feature);
|
||||
|
||||
/**
|
||||
* @brief Release a face feature. Only the features created through the HFCreateFaceFeature need to be processed.
|
||||
* @param feature Pointer to the face feature.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFReleaseFaceFeature(PHFFaceFeature feature);
|
||||
|
||||
/**
|
||||
* @brief Get the face alignment image.
|
||||
* @param session Handle to the session.
|
||||
@@ -663,6 +741,15 @@ HYPER_CAPI_EXPORT extern HResult HFFaceFeatureExtractCpy(HFSession session, HFIm
|
||||
HYPER_CAPI_EXPORT extern HResult HFFaceGetFaceAlignmentImage(HFSession session, HFImageStream streamHandle, HFFaceBasicToken singleFace,
|
||||
HFImageBitmap *handle);
|
||||
|
||||
/**
|
||||
* @brief Use the aligned face image to extract face features to the HFFaceFeature that has applied memory in advance.
|
||||
* @param session Handle to the session.
|
||||
* @param streamHandle Handle to the data buffer representing the camera stream component.
|
||||
* @param feature Pointer to the buffer where the extracted feature will be copied.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFFaceFeatureExtractWithAlignmentImage(HFSession session, HFImageStream streamHandle, HFFaceFeature feature);
|
||||
|
||||
/************************************************************************
|
||||
* Feature Hub
|
||||
************************************************************************/
|
||||
@@ -851,7 +938,7 @@ HYPER_CAPI_EXPORT extern HResult HFFeatureHubFaceSearchTopK(HFFaceFeature search
|
||||
/**
|
||||
* @brief Remove a face feature from the features group based on custom ID.
|
||||
*
|
||||
* @param customId The custom ID of the feature to be removed.
|
||||
* @param ID The custom ID of the feature to be removed.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFFeatureHubFaceRemove(HFaceId id);
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
#ifndef INSPIREFACE_INTERNAL_H
|
||||
#define INSPIREFACE_INTERNAL_H
|
||||
|
||||
#include "face_session.h"
|
||||
#include "engine/face_session.h"
|
||||
|
||||
typedef struct HF_FaceAlgorithmSession {
|
||||
inspire::FaceSession impl; ///< Implementation of the face context.
|
||||
} HF_FaceAlgorithmSession; ///< Handle for managing face context.
|
||||
|
||||
typedef struct HF_CameraStream {
|
||||
inspirecv::InspireImageProcess impl; ///< Implementation of the camera stream.
|
||||
} HF_CameraStream; ///< Handle for managing camera stream.
|
||||
inspirecv::FrameProcess impl; ///< Implementation of the camera stream.
|
||||
} HF_CameraStream; ///< Handle for managing camera stream.
|
||||
|
||||
typedef struct HF_ImageBitmap {
|
||||
inspirecv::Image impl; ///< Implementation of the image bitmap.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef INSPIRE_FACE_SERIALIZE_TOOLS_H
|
||||
#define INSPIRE_FACE_SERIALIZE_TOOLS_H
|
||||
|
||||
#include "face_data_type.h"
|
||||
#include "face_warpper.h"
|
||||
#include "../face_info/face_object_internal.h"
|
||||
#include "herror.h"
|
||||
#include "data_type.h"
|
||||
@@ -27,10 +27,10 @@ inline void PrintTransformMatrix(const TransMatrix& matrix) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print HyperFaceData structure.
|
||||
* @param data The HyperFaceData structure to print.
|
||||
* @brief Print FaceTrackWrap structure.
|
||||
* @param data The FaceTrackWrap structure to print.
|
||||
*/
|
||||
inline void INSPIRE_API PrintHyperFaceDataDetail(const HyperFaceData& data) {
|
||||
inline void INSPIRE_API PrintHyperFaceDataDetail(const FaceTrackWrap& data) {
|
||||
INSPIRE_LOGI("Track State: %d", data.trackState);
|
||||
INSPIRE_LOGI("In Group Index: %d", data.inGroupIndex);
|
||||
INSPIRE_LOGI("Track ID: %d", data.trackId);
|
||||
@@ -43,13 +43,13 @@ inline void INSPIRE_API PrintHyperFaceDataDetail(const HyperFaceData& data) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a FaceObject to HyperFaceData.
|
||||
* @brief Convert a FaceObject to FaceTrackWrap.
|
||||
* @param obj The FaceObject to convert.
|
||||
* @param group_index The group index.
|
||||
* @return The converted HyperFaceData structure.
|
||||
* @return The converted FaceTrackWrap structure.
|
||||
*/
|
||||
inline HyperFaceData INSPIRE_API FaceObjectInternalToHyperFaceData(const FaceObjectInternal& obj, int group_index = -1) {
|
||||
HyperFaceData data;
|
||||
inline FaceTrackWrap INSPIRE_API FaceObjectInternalToHyperFaceData(const FaceObjectInternal& obj, int group_index = -1) {
|
||||
FaceTrackWrap data;
|
||||
// Face rect
|
||||
data.rect.x = obj.bbox_.GetX();
|
||||
data.rect.y = obj.bbox_.GetY();
|
||||
@@ -134,15 +134,15 @@ inline inspirecv::Point2f INSPIRE_API HPointToInternalPoint2f(const Point2F& poi
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize HyperFaceData to a byte stream.
|
||||
* @param data The HyperFaceData to serialize.
|
||||
* @brief Serialize FaceTrackWrap to a byte stream.
|
||||
* @param data The FaceTrackWrap to serialize.
|
||||
* @param byteArray The output byte stream.
|
||||
* @return The result code.
|
||||
*/
|
||||
inline int32_t INSPIRE_API RunSerializeHyperFaceData(const HyperFaceData& data, ByteArray& byteArray) {
|
||||
inline int32_t INSPIRE_API RunSerializeHyperFaceData(const FaceTrackWrap& data, ByteArray& byteArray) {
|
||||
byteArray.reserve(sizeof(data));
|
||||
|
||||
// Serialize the HyperFaceData structure itself
|
||||
// Serialize the FaceTrackWrap structure itself
|
||||
const char* dataBytes = reinterpret_cast<const char*>(&data);
|
||||
byteArray.insert(byteArray.end(), dataBytes, dataBytes + sizeof(data));
|
||||
|
||||
@@ -150,18 +150,18 @@ inline int32_t INSPIRE_API RunSerializeHyperFaceData(const HyperFaceData& data,
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deserialize a byte stream to HyperFaceData.
|
||||
* @brief Deserialize a byte stream to FaceTrackWrap.
|
||||
* @param byteArray The input byte stream.
|
||||
* @param data The output HyperFaceData structure.
|
||||
* @param data The output FaceTrackWrap structure.
|
||||
* @return The result code.
|
||||
*/
|
||||
inline int32_t INSPIRE_API RunDeserializeHyperFaceData(const ByteArray& byteArray, HyperFaceData& data) {
|
||||
inline int32_t INSPIRE_API RunDeserializeHyperFaceData(const ByteArray& byteArray, FaceTrackWrap& data) {
|
||||
// Check if the byte stream size is sufficient
|
||||
if (byteArray.size() >= sizeof(data)) {
|
||||
// Copy data from the byte stream to the HyperFaceData structure
|
||||
// Copy data from the byte stream to the FaceTrackWrap structure
|
||||
std::memcpy(&data, byteArray.data(), sizeof(data));
|
||||
} else {
|
||||
INSPIRE_LOGE("The byte stream size is insufficient to restore HyperFaceData");
|
||||
INSPIRE_LOGE("The byte stream size is insufficient to restore FaceTrackWrap");
|
||||
return HERR_SESS_FACE_DATA_ERROR;
|
||||
}
|
||||
|
||||
@@ -169,19 +169,19 @@ inline int32_t INSPIRE_API RunDeserializeHyperFaceData(const ByteArray& byteArra
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deserialize a byte stream to HyperFaceData.
|
||||
* @brief Deserialize a byte stream to FaceTrackWrap.
|
||||
* @param byteArray The input byte stream as a character array.
|
||||
* @param byteCount The size of the byte stream.
|
||||
* @param data The output HyperFaceData structure.
|
||||
* @param data The output FaceTrackWrap structure.
|
||||
* @return The result code.
|
||||
*/
|
||||
inline int32_t INSPIRE_API RunDeserializeHyperFaceData(const char* byteArray, size_t byteCount, HyperFaceData& data) {
|
||||
inline int32_t INSPIRE_API RunDeserializeHyperFaceData(const char* byteArray, size_t byteCount, FaceTrackWrap& data) {
|
||||
// Check if the byte stream size is sufficient
|
||||
if (byteCount >= sizeof(data)) {
|
||||
// Copy data from the byte stream to the HyperFaceData structure
|
||||
// Copy data from the byte stream to the FaceTrackWrap structure
|
||||
std::memcpy(&data, byteArray, sizeof(data));
|
||||
} else {
|
||||
INSPIRE_LOGE("The byte stream size is insufficient to restore HyperFaceData");
|
||||
INSPIRE_LOGE("The byte stream size is insufficient to restore FaceTrackWrap");
|
||||
return HERR_SESS_FACE_DATA_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
index = 0;
|
||||
}
|
||||
|
||||
FaceActionList AnalysisFaceAction() {
|
||||
FaceActionList AnalysisFaceAction(const SemanticIndex& semantic_index) {
|
||||
FaceActionList actionRecord;
|
||||
actions.clear();
|
||||
eye_state_list.clear();
|
||||
@@ -64,8 +64,8 @@ public:
|
||||
|
||||
// count mouth aspect ratio
|
||||
|
||||
float mouth_widthwise_d = record_list[0][FaceLandmarkAdapt::MOUTH_LEFT_CORNER].Distance(record_list[0][FaceLandmarkAdapt::MOUTH_RIGHT_CORNER]);
|
||||
float mouth_heightwise_d = record_list[0][FaceLandmarkAdapt::MOUTH_UPPER].Distance(record_list[0][FaceLandmarkAdapt::MOUTH_LOWER]);
|
||||
float mouth_widthwise_d = record_list[0][semantic_index.mouth_left_corner].Distance(record_list[0][semantic_index.mouth_right_corner]);
|
||||
float mouth_heightwise_d = record_list[0][semantic_index.mouth_upper].Distance(record_list[0][semantic_index.mouth_lower]);
|
||||
float mouth_aspect_ratio = mouth_heightwise_d / mouth_widthwise_d;
|
||||
if (mouth_aspect_ratio > 0.3) {
|
||||
actions.push_back(ACT_JAW_OPEN);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "face_process.h"
|
||||
#include "face_action_data.h"
|
||||
#include "track_module/quality/face_pose_quality_adapt.h"
|
||||
#include "track_module/landmark/landmark_param.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
@@ -109,11 +110,11 @@ public:
|
||||
return box_square;
|
||||
}
|
||||
|
||||
FaceActionList UpdateFaceAction() {
|
||||
FaceActionList UpdateFaceAction(const SemanticIndex& semantic_index) {
|
||||
inspirecv::Vec3f euler{high_result.pitch, high_result.yaw, high_result.roll};
|
||||
inspirecv::Vec2f eyes{left_eye_status_.back(), right_eye_status_.back()};
|
||||
face_action_->RecordActionFrame(landmark_, euler, eyes);
|
||||
return face_action_->AnalysisFaceAction();
|
||||
return face_action_->AnalysisFaceAction(semantic_index);
|
||||
}
|
||||
|
||||
void DisableTracking() {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
#include "face_session.h"
|
||||
#include "initialization_module/launch.h"
|
||||
#include <launch.h>
|
||||
#include <utility>
|
||||
#include "log.h"
|
||||
#include "herror.h"
|
||||
@@ -20,35 +20,30 @@ int32_t FaceSession::Configuration(DetectModuleMode detect_mode, int32_t max_det
|
||||
m_detect_mode_ = detect_mode;
|
||||
m_max_detect_face_ = max_detect_face;
|
||||
m_parameter_ = param;
|
||||
if (!INSPIRE_LAUNCH->isMLoad()) {
|
||||
if (!INSPIREFACE_CONTEXT->isMLoad()) {
|
||||
return HERR_ARCHIVE_NOT_LOAD;
|
||||
}
|
||||
if (INSPIRE_LAUNCH->getMArchive().QueryStatus() != SARC_SUCCESS) {
|
||||
if (INSPIREFACE_CONTEXT->getMArchive().QueryStatus() != SARC_SUCCESS) {
|
||||
return HERR_ARCHIVE_LOAD_FAILURE;
|
||||
}
|
||||
|
||||
if (m_parameter_.enable_interaction_liveness) {
|
||||
m_parameter_.enable_detect_mode_landmark = true;
|
||||
}
|
||||
|
||||
m_face_track_ = std::make_shared<FaceTrackModule>(m_detect_mode_, m_max_detect_face_, 20, 192, detect_level_px, track_by_detect_mode_fps,
|
||||
m_parameter_.enable_detect_mode_landmark);
|
||||
m_face_track_->Configuration(INSPIRE_LAUNCH->getMArchive());
|
||||
m_face_track_ = std::make_shared<FaceTrackModule>(m_detect_mode_, m_max_detect_face_, 20, 192, detect_level_px, track_by_detect_mode_fps, true);
|
||||
m_face_track_->Configuration(INSPIREFACE_CONTEXT->getMArchive(), "", m_parameter_.enable_face_pose || m_parameter_.enable_face_quality);
|
||||
// SetDetectMode(m_detect_mode_);
|
||||
|
||||
m_face_recognition_ = std::make_shared<FeatureExtractionModule>(INSPIRE_LAUNCH->getMArchive(), m_parameter_.enable_recognition);
|
||||
m_face_recognition_ = std::make_shared<FeatureExtractionModule>(INSPIREFACE_CONTEXT->getMArchive(), m_parameter_.enable_recognition);
|
||||
if (m_face_recognition_->QueryStatus() != HSUCCEED) {
|
||||
return m_face_recognition_->QueryStatus();
|
||||
}
|
||||
|
||||
m_face_pipeline_ = std::make_shared<FacePipelineModule>(INSPIRE_LAUNCH->getMArchive(), param.enable_liveness, param.enable_mask_detect,
|
||||
m_face_pipeline_ = std::make_shared<FacePipelineModule>(INSPIREFACE_CONTEXT->getMArchive(), param.enable_liveness, param.enable_mask_detect,
|
||||
param.enable_face_attribute, param.enable_interaction_liveness);
|
||||
m_face_track_cost_ = std::make_shared<inspirecv::TimeSpend>("FaceTrack");
|
||||
m_face_track_cost_ = std::make_shared<inspire::SpendTimer>("FaceTrack");
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FaceSession::FaceDetectAndTrack(inspirecv::InspireImageProcess& process) {
|
||||
int32_t FaceSession::FaceDetectAndTrack(inspirecv::FrameProcess& process) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_);
|
||||
if (m_enable_track_cost_spend_) {
|
||||
m_face_track_cost_->Start();
|
||||
@@ -81,7 +76,7 @@ int32_t FaceSession::FaceDetectAndTrack(inspirecv::InspireImageProcess& process)
|
||||
m_face_track_->UpdateStream(process);
|
||||
for (int i = 0; i < m_face_track_->trackingFace.size(); ++i) {
|
||||
auto& face = m_face_track_->trackingFace[i];
|
||||
HyperFaceData data = FaceObjectInternalToHyperFaceData(face, i);
|
||||
FaceTrackWrap data = FaceObjectInternalToHyperFaceData(face, i);
|
||||
ByteArray byteArray;
|
||||
auto ret = RunSerializeHyperFaceData(data, byteArray);
|
||||
if (ret != HSUCCEED) {
|
||||
@@ -118,6 +113,11 @@ int32_t FaceSession::FaceDetectAndTrack(inspirecv::InspireImageProcess& process)
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FaceSession::SetLandmarkLoop(int32_t value) {
|
||||
// TODO: implement this function
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FaceSession::SetFaceDetectThreshold(float value) {
|
||||
m_face_track_->SetDetectThreshold(value);
|
||||
return HSUCCEED;
|
||||
@@ -139,8 +139,7 @@ const int32_t FaceSession::GetNumberOfFacesCurrentlyDetected() const {
|
||||
return m_face_track_->trackingFace.size();
|
||||
}
|
||||
|
||||
int32_t FaceSession::FacesProcess(inspirecv::InspireImageProcess& process, const std::vector<HyperFaceData>& faces,
|
||||
const CustomPipelineParameter& param) {
|
||||
int32_t FaceSession::FacesProcess(inspirecv::FrameProcess& process, const std::vector<FaceTrackWrap>& faces, const CustomPipelineParameter& param) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_);
|
||||
m_mask_results_cache_.resize(faces.size(), -1.0f);
|
||||
m_rgb_liveness_results_cache_.resize(faces.size(), -1.0f);
|
||||
@@ -205,7 +204,7 @@ int32_t FaceSession::FacesProcess(inspirecv::InspireImageProcess& process, const
|
||||
m_react_left_eye_results_cache_[i] = new_eye_left;
|
||||
m_react_right_eye_results_cache_[i] = new_eye_right;
|
||||
}
|
||||
const auto actions = target.UpdateFaceAction();
|
||||
const auto actions = target.UpdateFaceAction(INSPIREFACE_CONTEXT->getMArchive().GetLandmarkParam()->semantic_index);
|
||||
m_action_normal_results_cache_[i] = actions.normal;
|
||||
m_action_jaw_open_results_cache_[i] = actions.jawOpen;
|
||||
m_action_blink_results_cache_[i] = actions.blink;
|
||||
@@ -324,24 +323,52 @@ const std::vector<int>& FaceSession::GetFaceRaiseHeadAactionsResultCache() const
|
||||
return m_action_raise_head_results_cache_;
|
||||
}
|
||||
|
||||
int32_t FaceSession::FaceFeatureExtract(inspirecv::InspireImageProcess& process, FaceBasicData& data) {
|
||||
int32_t FaceSession::FaceFeatureExtract(inspirecv::FrameProcess& process, FaceBasicData& data, bool normalize) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_);
|
||||
int32_t ret;
|
||||
HyperFaceData face = {0};
|
||||
FaceTrackWrap face = {0};
|
||||
ret = RunDeserializeHyperFaceData((char*)data.data, data.dataSize, face);
|
||||
if (ret != HSUCCEED) {
|
||||
return ret;
|
||||
}
|
||||
m_face_feature_cache_.clear();
|
||||
ret = m_face_recognition_->FaceExtract(process, face, m_face_feature_cache_, m_face_feature_norm_);
|
||||
ret = m_face_recognition_->FaceExtract(process, face, m_face_feature_cache_, m_face_feature_norm_, normalize);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t FaceSession::FaceGetFaceAlignmentImage(inspirecv::InspireImageProcess& process, FaceBasicData& data, inspirecv::Image& image) {
|
||||
int32_t FaceSession::FaceFeatureExtract(inspirecv::FrameProcess& process, FaceTrackWrap& data, bool normalize) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_);
|
||||
int32_t ret;
|
||||
HyperFaceData face = {0};
|
||||
m_face_feature_cache_.clear();
|
||||
ret = m_face_recognition_->FaceExtract(process, data, m_face_feature_cache_, m_face_feature_norm_, normalize);
|
||||
if (ret != HSUCCEED) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t FaceSession::FaceFeatureExtractWithAlignmentImage(inspirecv::FrameProcess& process, Embedded& embedding, float& norm, bool normalize) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_);
|
||||
int32_t ret;
|
||||
m_face_feature_cache_.clear();
|
||||
ret = m_face_recognition_->FaceExtractWithAlignmentImage(process, embedding, norm, normalize);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t FaceSession::FaceFeatureExtractWithAlignmentImage(const inspirecv::Image& wrapped, FaceEmbedding& embedding, float& norm, bool normalize) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_);
|
||||
int32_t ret;
|
||||
ret = m_face_recognition_->FaceExtractWithAlignmentImage(wrapped, embedding.embedding, norm, normalize);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t FaceSession::FaceGetFaceAlignmentImage(inspirecv::FrameProcess& process, FaceBasicData& data, inspirecv::Image& image) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_);
|
||||
int32_t ret;
|
||||
FaceTrackWrap face = {0};
|
||||
ret = RunDeserializeHyperFaceData((char*)data.data, data.dataSize, face);
|
||||
if (ret != HSUCCEED) {
|
||||
return ret;
|
||||
@@ -361,7 +388,7 @@ const CustomPipelineParameter& FaceSession::getMParameter() const {
|
||||
|
||||
int32_t FaceSession::FaceQualityDetect(FaceBasicData& data, float& result) {
|
||||
int32_t ret;
|
||||
HyperFaceData face = {0};
|
||||
FaceTrackWrap face = {0};
|
||||
ret = RunDeserializeHyperFaceData((char*)data.data, data.dataSize, face);
|
||||
// PrintHyperFaceData(face);
|
||||
if (ret != HSUCCEED) {
|
||||
@@ -396,6 +423,10 @@ int32_t FaceSession::SetTrackPreviewSize(const int32_t preview_size) {
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FaceSession::GetTrackPreviewSize() const {
|
||||
return m_face_track_->GetTrackPreviewSize();
|
||||
}
|
||||
|
||||
int32_t FaceSession::SetTrackFaceMinimumSize(int32_t minSize) {
|
||||
m_face_track_->SetMinimumFacePxSize(minSize);
|
||||
return HSUCCEED;
|
||||
@@ -428,4 +459,8 @@ void FaceSession::PrintTrackCostSpend() {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t FaceSession::GetDebugPreviewImageSize() const {
|
||||
return m_face_track_->GetDebugPreviewImageSize();
|
||||
}
|
||||
|
||||
} // namespace inspire
|
||||
@@ -14,29 +14,12 @@
|
||||
#include "pipeline_module/face_pipeline_module.h"
|
||||
#include "middleware/model_archive/inspire_archive.h"
|
||||
#include "recognition_module/face_feature_extraction_module.h"
|
||||
#include "middleware/inspirecv_image_process.h"
|
||||
#include "frame_process.h"
|
||||
#include "common/face_data/face_serialize_tools.h"
|
||||
#include "spend_timer.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
/**
|
||||
* @struct CustomPipelineParameter
|
||||
* @brief Structure to hold custom parameters for the face detection and processing pipeline.
|
||||
*
|
||||
* Includes options for enabling various features such as recognition, liveness detection, and quality assessment.
|
||||
*/
|
||||
typedef struct CustomPipelineParameter {
|
||||
bool enable_recognition = false; ///< Enable face recognition feature
|
||||
bool enable_liveness = false; ///< Enable RGB liveness detection feature
|
||||
bool enable_ir_liveness = false; ///< Enable IR (Infrared) liveness detection feature
|
||||
bool enable_mask_detect = false; ///< Enable mask detection feature
|
||||
bool enable_face_attribute = false; ///< Enable face attribute prediction feature
|
||||
bool enable_face_quality = false; ///< Enable face quality assessment feature
|
||||
bool enable_interaction_liveness = false; ///< Enable interactive liveness detection feature
|
||||
bool enable_detect_mode_landmark = false; ///< Enable landmark detection in detection mode
|
||||
|
||||
} ContextCustomParameter;
|
||||
|
||||
/**
|
||||
* @class FaceContext
|
||||
* @brief Manages the context for face detection, tracking, and feature extraction in the HyperFaceRepo project.
|
||||
@@ -68,7 +51,14 @@ public:
|
||||
* @param image The camera stream to process for face detection and tracking.
|
||||
* @return int32_t Returns the number of faces detected and tracked.
|
||||
*/// Method for face detection and tracking
|
||||
int32_t FaceDetectAndTrack(inspirecv::InspireImageProcess& process);
|
||||
int32_t FaceDetectAndTrack(inspirecv::FrameProcess& process);
|
||||
|
||||
/**
|
||||
* @brief Set the face landmark loop
|
||||
* @param value The landmark loop value
|
||||
* @return int32_t Status code of the operation.
|
||||
* */
|
||||
int32_t SetLandmarkLoop(int32_t value);
|
||||
|
||||
/**
|
||||
* @brief Set the threshold of face detection function, which only acts on the detection model
|
||||
@@ -86,11 +76,11 @@ public:
|
||||
/**
|
||||
* @brief Processes faces using the provided pipeline parameters.
|
||||
* @param image Camera stream containing faces.
|
||||
* @param faces Vector of HyperFaceData for detected faces.
|
||||
* @param faces Vector of FaceTrackWrap for detected faces.
|
||||
* @param param Custom pipeline parameters.
|
||||
* @return int32_t Status code of the processing.
|
||||
*/
|
||||
int32_t FacesProcess(inspirecv::InspireImageProcess& process, const std::vector<HyperFaceData>& faces, const CustomPipelineParameter& param);
|
||||
int32_t FacesProcess(inspirecv::FrameProcess& process, const std::vector<FaceTrackWrap>& faces, const CustomPipelineParameter& param);
|
||||
|
||||
/**
|
||||
* @brief Retrieves the face recognition module.
|
||||
@@ -116,7 +106,31 @@ public:
|
||||
* @param data FaceBasicData to store extracted features.
|
||||
* @return int32_t Status code of the feature extraction.
|
||||
*/
|
||||
int32_t FaceFeatureExtract(inspirecv::InspireImageProcess& process, FaceBasicData& data);
|
||||
int32_t FaceFeatureExtract(inspirecv::FrameProcess& process, FaceBasicData& data, bool normalize = true);
|
||||
|
||||
/**
|
||||
* @brief Extracts features of a face from an image.
|
||||
* @param image Camera stream containing the face.
|
||||
* @param data FaceTrackWrap to store extracted features.
|
||||
* @return int32_t Status code of the feature extraction.
|
||||
*/
|
||||
int32_t FaceFeatureExtract(inspirecv::FrameProcess& process, FaceTrackWrap& data, bool normalize = true);
|
||||
|
||||
/**
|
||||
* @brief Extracts features of a face from an image.
|
||||
* @param image Camera stream containing the face.
|
||||
* @param data FaceTrackWrap to store extracted features.
|
||||
* @return int32_t Status code of the feature extraction.
|
||||
*/
|
||||
int32_t FaceFeatureExtractWithAlignmentImage(inspirecv::FrameProcess& process, Embedded& embedding, float& norm, bool normalize = true);
|
||||
|
||||
/**
|
||||
* @brief Extracts features of a face from an image.
|
||||
* @param image Camera stream containing the face.
|
||||
* @param data FaceTrackWrap to store extracted features.
|
||||
* @return int32_t Status code of the feature extraction.
|
||||
*/
|
||||
int32_t FaceFeatureExtractWithAlignmentImage(const inspirecv::Image& wrapped, FaceEmbedding& embedding, float& norm, bool normalize = true);
|
||||
|
||||
/**
|
||||
* @brief Gets the face alignment image.
|
||||
@@ -125,7 +139,7 @@ public:
|
||||
* @param image The output image.
|
||||
* @return int32_t The status code of the operation.
|
||||
*/
|
||||
int32_t FaceGetFaceAlignmentImage(inspirecv::InspireImageProcess& process, FaceBasicData& data, inspirecv::Image& image);
|
||||
int32_t FaceGetFaceAlignmentImage(inspirecv::FrameProcess& process, FaceBasicData& data, inspirecv::Image& image);
|
||||
|
||||
/**
|
||||
* @brief Retrieves the custom pipeline parameters.
|
||||
@@ -148,6 +162,12 @@ public:
|
||||
*/
|
||||
int32_t SetTrackPreviewSize(int32_t preview_size);
|
||||
|
||||
/**
|
||||
* @brief Gets the preview size for face tracking.
|
||||
* @return int32_t The preview size.
|
||||
*/
|
||||
int32_t GetTrackPreviewSize() const;
|
||||
|
||||
/**
|
||||
* @brief Filter the minimum face pixel size.
|
||||
* @param minSize The minimum pixel value.
|
||||
@@ -347,6 +367,12 @@ public:
|
||||
* */
|
||||
void PrintTrackCostSpend();
|
||||
|
||||
/**
|
||||
* @brief Get the debug preview image size
|
||||
* @return int32_t The debug preview image size
|
||||
* */
|
||||
int32_t GetDebugPreviewImageSize() const;
|
||||
|
||||
private:
|
||||
// Private member variables
|
||||
CustomPipelineParameter m_parameter_; ///< Stores custom parameters for the pipeline
|
||||
@@ -390,7 +416,7 @@ private:
|
||||
std::mutex m_mtx_; ///< Mutex for thread safety.
|
||||
|
||||
// cost spend
|
||||
std::shared_ptr<inspirecv::TimeSpend> m_face_track_cost_;
|
||||
std::shared_ptr<inspire::SpendTimer> m_face_track_cost_;
|
||||
|
||||
int m_enable_track_cost_spend_ = 0;
|
||||
};
|
||||
@@ -2,6 +2,9 @@
|
||||
#include "sqlite-vec.h"
|
||||
#include "isf_check.h"
|
||||
#include <algorithm>
|
||||
#if defined(__ANDROID__)
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
namespace inspire {
|
||||
|
||||
@@ -118,20 +121,13 @@ std::vector<int64_t> EmbeddingDB::BatchInsertVectors(const std::vector<VectorDat
|
||||
std::vector<int64_t> insertedIds;
|
||||
insertedIds.reserve(vectors.size());
|
||||
|
||||
try {
|
||||
for (const auto &data : vectors) {
|
||||
int64_t id = 0;
|
||||
bool ret = InsertVector(data.id, data.vector, id);
|
||||
if (!ret) {
|
||||
throw std::runtime_error("Failed to insert vector");
|
||||
}
|
||||
insertedIds.push_back(id);
|
||||
}
|
||||
ExecuteSQL("COMMIT");
|
||||
} catch (...) {
|
||||
ExecuteSQL("ROLLBACK");
|
||||
throw;
|
||||
for (const auto &data : vectors) {
|
||||
int64_t id = 0;
|
||||
bool ret = InsertVector(data.id, data.vector, id);
|
||||
INSPIREFACE_CHECK_MSG(ret, "Failed to insert vector");
|
||||
insertedIds.push_back(id);
|
||||
}
|
||||
ExecuteSQL("COMMIT");
|
||||
|
||||
return insertedIds;
|
||||
}
|
||||
@@ -141,20 +137,13 @@ std::vector<int64_t> EmbeddingDB::BatchInsertVectors(const std::vector<std::vect
|
||||
std::vector<int64_t> insertedIds;
|
||||
insertedIds.reserve(vectors.size());
|
||||
|
||||
try {
|
||||
for (const auto &vector : vectors) {
|
||||
int64_t id = 0;
|
||||
bool ret = InsertVector(0, vector, id);
|
||||
if (!ret) {
|
||||
throw std::runtime_error("Failed to insert vector");
|
||||
}
|
||||
insertedIds.push_back(id);
|
||||
}
|
||||
ExecuteSQL("COMMIT");
|
||||
} catch (...) {
|
||||
ExecuteSQL("ROLLBACK");
|
||||
throw;
|
||||
for (const auto &vector : vectors) {
|
||||
int64_t id = 0;
|
||||
bool ret = InsertVector(0, vector, id);
|
||||
INSPIREFACE_CHECK_MSG(ret, "Failed to insert vector");
|
||||
insertedIds.push_back(id);
|
||||
}
|
||||
ExecuteSQL("COMMIT");
|
||||
|
||||
return insertedIds;
|
||||
}
|
||||
|
||||
@@ -19,18 +19,12 @@
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <mutex>
|
||||
#include "data_type.h"
|
||||
|
||||
#define EMBEDDING_DB inspire::EmbeddingDB
|
||||
|
||||
namespace inspire {
|
||||
|
||||
// Search for most similar vectors
|
||||
struct FaceSearchResult {
|
||||
int64_t id;
|
||||
double similarity;
|
||||
std::vector<float> feature;
|
||||
};
|
||||
|
||||
// Vector data structure
|
||||
struct VectorData {
|
||||
int64_t id; // This field is ignored in auto-increment mode
|
||||
|
||||
@@ -9,13 +9,42 @@
|
||||
#include <thread>
|
||||
#include "middleware/utils.h"
|
||||
#include "middleware/system.h"
|
||||
#include "log.h"
|
||||
#include "feature_hub/embedding_db/embedding_db.h"
|
||||
|
||||
#define DB_FILE_NAME ".feature_hub_db_v0"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
class FeatureHubDB::Impl {
|
||||
public:
|
||||
Impl() : m_enable_(false), m_recognition_threshold_(0.48f), m_search_mode_(SEARCH_MODE_EAGER) {}
|
||||
|
||||
Embedded m_search_face_feature_cache_;
|
||||
Embedded m_getter_face_feature_cache_;
|
||||
std::shared_ptr<FaceFeaturePtr> m_face_feature_ptr_cache_;
|
||||
|
||||
std::vector<FaceSearchResult> m_search_top_k_cache_;
|
||||
std::vector<float> m_top_k_confidence_;
|
||||
std::vector<int64_t> m_top_k_custom_ids_cache_;
|
||||
|
||||
std::vector<int64_t> m_all_ids_;
|
||||
|
||||
DatabaseConfiguration m_db_configuration_;
|
||||
float m_recognition_threshold_;
|
||||
SearchMode m_search_mode_;
|
||||
|
||||
bool m_enable_;
|
||||
|
||||
std::mutex m_res_mtx_;
|
||||
};
|
||||
|
||||
std::mutex FeatureHubDB::mutex_;
|
||||
std::shared_ptr<FeatureHubDB> FeatureHubDB::instance_ = nullptr;
|
||||
|
||||
FeatureHubDB::FeatureHubDB() {}
|
||||
FeatureHubDB::FeatureHubDB() : pImpl(new Impl()) {}
|
||||
|
||||
FeatureHubDB::~FeatureHubDB() = default;
|
||||
|
||||
std::shared_ptr<FeatureHubDB> FeatureHubDB::GetInstance() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
@@ -26,79 +55,76 @@ std::shared_ptr<FeatureHubDB> FeatureHubDB::GetInstance() {
|
||||
}
|
||||
|
||||
int32_t FeatureHubDB::DisableHub() {
|
||||
if (!m_enable_) {
|
||||
if (!pImpl->m_enable_) {
|
||||
INSPIRE_LOGW("FeatureHub is already disabled.");
|
||||
return HSUCCEED;
|
||||
}
|
||||
// Close the database if it starts
|
||||
|
||||
if (EMBEDDING_DB::GetInstance().IsInitialized()) {
|
||||
EMBEDDING_DB::Deinit();
|
||||
// if (ret != HSUCCEED) {
|
||||
// INSPIRE_LOGE("Failed to close the database: %d", ret);
|
||||
// return ret;
|
||||
// }
|
||||
// m_db_.reset();
|
||||
}
|
||||
|
||||
m_search_face_feature_cache_.clear();
|
||||
pImpl->m_search_face_feature_cache_.clear();
|
||||
|
||||
m_db_configuration_ = DatabaseConfiguration(); // Reset using the default constructor
|
||||
m_recognition_threshold_ = 0.0f;
|
||||
m_search_mode_ = SEARCH_MODE_EAGER;
|
||||
pImpl->m_db_configuration_ = DatabaseConfiguration();
|
||||
pImpl->m_recognition_threshold_ = 0.0f;
|
||||
pImpl->m_search_mode_ = SEARCH_MODE_EAGER;
|
||||
|
||||
m_face_feature_ptr_cache_.reset();
|
||||
m_enable_ = false;
|
||||
pImpl->m_face_feature_ptr_cache_.reset();
|
||||
pImpl->m_enable_ = false;
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FeatureHubDB::GetAllIds() {
|
||||
if (!m_enable_) {
|
||||
if (!pImpl->m_enable_) {
|
||||
INSPIRE_LOGE("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HERR_FT_HUB_DISABLE;
|
||||
}
|
||||
m_all_ids_ = EMBEDDING_DB::GetInstance().GetAllIds();
|
||||
pImpl->m_all_ids_ = EMBEDDING_DB::GetInstance().GetAllIds();
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FeatureHubDB::EnableHub(const DatabaseConfiguration &configuration) {
|
||||
int32_t ret;
|
||||
if (m_enable_) {
|
||||
if (pImpl->m_enable_) {
|
||||
INSPIRE_LOGW("You have enabled the FeatureHub feature. It is not valid to do so again");
|
||||
return HSUCCEED;
|
||||
}
|
||||
// Config
|
||||
m_db_configuration_ = configuration;
|
||||
m_recognition_threshold_ = m_db_configuration_.recognition_threshold;
|
||||
if (m_recognition_threshold_ < -1.0f || m_recognition_threshold_ > 1.0f) {
|
||||
|
||||
pImpl->m_db_configuration_ = configuration;
|
||||
pImpl->m_recognition_threshold_ = pImpl->m_db_configuration_.recognition_threshold;
|
||||
if (pImpl->m_recognition_threshold_ < -1.0f || pImpl->m_recognition_threshold_ > 1.0f) {
|
||||
INSPIRE_LOGW("The search threshold entered does not fit the required range (-1.0f, 1.0f) and has been set to 0.5 by default");
|
||||
m_recognition_threshold_ = 0.5f;
|
||||
pImpl->m_recognition_threshold_ = 0.5f;
|
||||
}
|
||||
|
||||
std::string dbFile = ":memory:";
|
||||
if (m_db_configuration_.enable_persistence) {
|
||||
if (IsDirectory(m_db_configuration_.persistence_db_path)) {
|
||||
dbFile = os::PathJoin(m_db_configuration_.persistence_db_path, DB_FILE_NAME);
|
||||
if (pImpl->m_db_configuration_.enable_persistence) {
|
||||
if (IsDirectory(pImpl->m_db_configuration_.persistence_db_path)) {
|
||||
dbFile = os::PathJoin(pImpl->m_db_configuration_.persistence_db_path, DB_FILE_NAME);
|
||||
} else {
|
||||
dbFile = m_db_configuration_.persistence_db_path;
|
||||
dbFile = pImpl->m_db_configuration_.persistence_db_path;
|
||||
}
|
||||
}
|
||||
|
||||
EMBEDDING_DB::Init(dbFile, 512, IdMode(configuration.primary_key_mode));
|
||||
m_enable_ = true;
|
||||
m_face_feature_ptr_cache_ = std::make_shared<FaceFeatureEntity>();
|
||||
pImpl->m_enable_ = true;
|
||||
pImpl->m_face_feature_ptr_cache_ = std::make_shared<FaceFeatureEntity>();
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FeatureHubDB::CosineSimilarity(const std::vector<float> &v1, const std::vector<float> &v2, float &res, bool normalize) {
|
||||
if (v1.size() != v2.size() || v1.empty()) {
|
||||
return HERR_SESS_REC_CONTRAST_FEAT_ERR; // The similarity cannot be calculated if the vector lengths are not equal
|
||||
return HERR_SESS_REC_CONTRAST_FEAT_ERR;
|
||||
}
|
||||
|
||||
if (normalize) {
|
||||
std::vector<float> v1_norm = v1;
|
||||
std::vector<float> v2_norm = v2;
|
||||
float mse1 = 0.0f;
|
||||
float mse2 = 0.0f;
|
||||
|
||||
for (const auto &one : v1_norm) {
|
||||
mse1 += one * one;
|
||||
}
|
||||
@@ -114,9 +140,9 @@ int32_t FeatureHubDB::CosineSimilarity(const std::vector<float> &v1, const std::
|
||||
for (float &one : v2_norm) {
|
||||
one /= mse2;
|
||||
}
|
||||
|
||||
res = simd_dot(v1_norm.data(), v2_norm.data(), v1_norm.size());
|
||||
} else {
|
||||
// Calculate the cosine similarity
|
||||
res = simd_dot(v1.data(), v2.data(), v1.size());
|
||||
}
|
||||
|
||||
@@ -129,6 +155,7 @@ int32_t FeatureHubDB::CosineSimilarity(const float *v1, const float *v2, int32_t
|
||||
std::vector<float> v2_norm(v2, v2 + size);
|
||||
float mse1 = 0.0f;
|
||||
float mse2 = 0.0f;
|
||||
|
||||
for (const auto &one : v1_norm) {
|
||||
mse1 += one * one;
|
||||
}
|
||||
@@ -136,6 +163,7 @@ int32_t FeatureHubDB::CosineSimilarity(const float *v1, const float *v2, int32_t
|
||||
for (float &one : v1_norm) {
|
||||
one /= mse1;
|
||||
}
|
||||
|
||||
for (const auto &one : v2_norm) {
|
||||
mse2 += one * one;
|
||||
}
|
||||
@@ -143,6 +171,7 @@ int32_t FeatureHubDB::CosineSimilarity(const float *v1, const float *v2, int32_t
|
||||
for (float &one : v2_norm) {
|
||||
one /= mse2;
|
||||
}
|
||||
|
||||
res = simd_dot(v1_norm.data(), v2_norm.data(), v1_norm.size());
|
||||
} else {
|
||||
res = simd_dot(v1, v2, size);
|
||||
@@ -152,37 +181,34 @@ int32_t FeatureHubDB::CosineSimilarity(const float *v1, const float *v2, int32_t
|
||||
}
|
||||
|
||||
int32_t FeatureHubDB::GetFaceFeatureCount() {
|
||||
if (!m_enable_) {
|
||||
if (!pImpl->m_enable_) {
|
||||
INSPIRE_LOGW("FeatureHub is disabled, please enable it before it can be served");
|
||||
return 0;
|
||||
}
|
||||
int totalFeatureCount = 0;
|
||||
|
||||
// Iterate over all FeatureBlocks and add up the number of feature vectors used
|
||||
totalFeatureCount = EMBEDDING_DB::GetInstance().GetVectorCount();
|
||||
|
||||
return totalFeatureCount;
|
||||
return EMBEDDING_DB::GetInstance().GetVectorCount();
|
||||
}
|
||||
|
||||
int32_t FeatureHubDB::SearchFaceFeature(const Embedded &queryFeature, FaceSearchResult &searchResult, bool returnFeature) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!m_enable_) {
|
||||
if (!pImpl->m_enable_) {
|
||||
INSPIRE_LOGE("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HSUCCEED;
|
||||
}
|
||||
m_search_face_feature_cache_.clear();
|
||||
auto results = EMBEDDING_DB::GetInstance().SearchSimilarVectors(queryFeature, 1, m_recognition_threshold_, returnFeature);
|
||||
|
||||
pImpl->m_search_face_feature_cache_.clear();
|
||||
auto results = EMBEDDING_DB::GetInstance().SearchSimilarVectors(queryFeature, 1, pImpl->m_recognition_threshold_, returnFeature);
|
||||
searchResult.id = -1;
|
||||
|
||||
if (!results.empty()) {
|
||||
auto &searched = results[0];
|
||||
searchResult.similarity = searched.similarity;
|
||||
searchResult.id = searched.id;
|
||||
if (returnFeature) {
|
||||
searchResult.feature = searched.feature;
|
||||
// copy feature to cache
|
||||
m_search_face_feature_cache_ = searched.feature;
|
||||
m_face_feature_ptr_cache_->data = m_search_face_feature_cache_.data();
|
||||
m_face_feature_ptr_cache_->dataSize = m_search_face_feature_cache_.size();
|
||||
pImpl->m_search_face_feature_cache_ = searched.feature;
|
||||
pImpl->m_face_feature_ptr_cache_->data = pImpl->m_search_face_feature_cache_.data();
|
||||
pImpl->m_face_feature_ptr_cache_->dataSize = pImpl->m_search_face_feature_cache_.size();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,16 +217,18 @@ int32_t FeatureHubDB::SearchFaceFeature(const Embedded &queryFeature, FaceSearch
|
||||
|
||||
int32_t FeatureHubDB::SearchFaceFeatureTopKCache(const Embedded &queryFeature, size_t topK) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!m_enable_) {
|
||||
if (!pImpl->m_enable_) {
|
||||
INSPIRE_LOGE("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HERR_FT_HUB_DISABLE;
|
||||
}
|
||||
m_top_k_confidence_.clear();
|
||||
m_top_k_custom_ids_cache_.clear();
|
||||
auto results = EMBEDDING_DB::GetInstance().SearchSimilarVectors(queryFeature, topK, m_recognition_threshold_, false);
|
||||
|
||||
pImpl->m_top_k_confidence_.clear();
|
||||
pImpl->m_top_k_custom_ids_cache_.clear();
|
||||
auto results = EMBEDDING_DB::GetInstance().SearchSimilarVectors(queryFeature, topK, pImpl->m_recognition_threshold_, false);
|
||||
|
||||
for (size_t i = 0; i < results.size(); i++) {
|
||||
m_top_k_custom_ids_cache_.push_back(results[i].id);
|
||||
m_top_k_confidence_.push_back(results[i].similarity);
|
||||
pImpl->m_top_k_custom_ids_cache_.push_back(results[i].id);
|
||||
pImpl->m_top_k_confidence_.push_back(results[i].similarity);
|
||||
}
|
||||
|
||||
return HSUCCEED;
|
||||
@@ -209,17 +237,18 @@ int32_t FeatureHubDB::SearchFaceFeatureTopKCache(const Embedded &queryFeature, s
|
||||
int32_t FeatureHubDB::SearchFaceFeatureTopK(const Embedded &queryFeature, std::vector<FaceSearchResult> &searchResult, size_t topK,
|
||||
bool returnFeature) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!m_enable_) {
|
||||
if (!pImpl->m_enable_) {
|
||||
INSPIRE_LOGW("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HERR_FT_HUB_DISABLE;
|
||||
}
|
||||
searchResult = EMBEDDING_DB::GetInstance().SearchSimilarVectors(queryFeature, topK, m_recognition_threshold_, returnFeature);
|
||||
|
||||
searchResult = EMBEDDING_DB::GetInstance().SearchSimilarVectors(queryFeature, topK, pImpl->m_recognition_threshold_, returnFeature);
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FeatureHubDB::FaceFeatureInsert(const std::vector<float> &feature, int32_t id, int64_t &result_id) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!m_enable_) {
|
||||
if (!pImpl->m_enable_) {
|
||||
INSPIRE_LOGE("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HERR_FT_HUB_DISABLE;
|
||||
}
|
||||
@@ -235,65 +264,62 @@ int32_t FeatureHubDB::FaceFeatureInsert(const std::vector<float> &feature, int32
|
||||
|
||||
int32_t FeatureHubDB::FaceFeatureRemove(int32_t id) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!m_enable_) {
|
||||
if (!pImpl->m_enable_) {
|
||||
INSPIRE_LOGE("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HERR_FT_HUB_DISABLE;
|
||||
}
|
||||
EMBEDDING_DB::GetInstance().DeleteVector(id);
|
||||
|
||||
EMBEDDING_DB::GetInstance().DeleteVector(id);
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FeatureHubDB::FaceFeatureUpdate(const std::vector<float> &feature, int32_t customId) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!m_enable_) {
|
||||
if (!pImpl->m_enable_) {
|
||||
INSPIRE_LOGE("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HERR_FT_HUB_DISABLE;
|
||||
}
|
||||
try {
|
||||
EMBEDDING_DB::GetInstance().UpdateVector(customId, feature);
|
||||
} catch (const std::exception &e) {
|
||||
INSPIRE_LOGW("Failed to update face feature, id: %d", customId);
|
||||
return HERR_FT_HUB_NOT_FOUND_FEATURE;
|
||||
}
|
||||
|
||||
EMBEDDING_DB::GetInstance().UpdateVector(customId, feature);
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FeatureHubDB::GetFaceFeature(int32_t id) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!m_enable_) {
|
||||
if (!pImpl->m_enable_) {
|
||||
INSPIRE_LOGE("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HERR_FT_HUB_DISABLE;
|
||||
}
|
||||
|
||||
auto vec = EMBEDDING_DB::GetInstance().GetVector(id);
|
||||
if (vec.empty()) {
|
||||
return HERR_FT_HUB_NOT_FOUND_FEATURE;
|
||||
}
|
||||
m_getter_face_feature_cache_ = vec;
|
||||
m_face_feature_ptr_cache_->data = m_getter_face_feature_cache_.data();
|
||||
m_face_feature_ptr_cache_->dataSize = m_getter_face_feature_cache_.size();
|
||||
|
||||
pImpl->m_getter_face_feature_cache_ = vec;
|
||||
pImpl->m_face_feature_ptr_cache_->data = pImpl->m_getter_face_feature_cache_.data();
|
||||
pImpl->m_face_feature_ptr_cache_->dataSize = pImpl->m_getter_face_feature_cache_.size();
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FeatureHubDB::GetFaceFeature(int32_t id, std::vector<float> &feature) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!m_enable_) {
|
||||
if (!pImpl->m_enable_) {
|
||||
INSPIRE_LOGW("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HERR_FT_HUB_DISABLE;
|
||||
}
|
||||
try {
|
||||
feature = EMBEDDING_DB::GetInstance().GetVector(id);
|
||||
} catch (const std::exception &e) {
|
||||
INSPIRE_LOGW("Failed to get face feature, id: %d", id);
|
||||
|
||||
feature = EMBEDDING_DB::GetInstance().GetVector(id);
|
||||
if (feature.empty()) {
|
||||
return HERR_FT_HUB_NOT_FOUND_FEATURE;
|
||||
}
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FeatureHubDB::ViewDBTable() {
|
||||
if (!m_enable_) {
|
||||
if (!pImpl->m_enable_) {
|
||||
INSPIRE_LOGE("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HERR_FT_HUB_DISABLE;
|
||||
}
|
||||
@@ -302,33 +328,33 @@ int32_t FeatureHubDB::ViewDBTable() {
|
||||
}
|
||||
|
||||
void FeatureHubDB::SetRecognitionThreshold(float threshold) {
|
||||
m_recognition_threshold_ = threshold;
|
||||
pImpl->m_recognition_threshold_ = threshold;
|
||||
}
|
||||
|
||||
void FeatureHubDB::SetRecognitionSearchMode(SearchMode mode) {
|
||||
m_search_mode_ = mode;
|
||||
pImpl->m_search_mode_ = mode;
|
||||
}
|
||||
|
||||
// =========== Getter ===========
|
||||
|
||||
const Embedded &FeatureHubDB::GetSearchFaceFeatureCache() const {
|
||||
return m_search_face_feature_cache_;
|
||||
return pImpl->m_search_face_feature_cache_;
|
||||
}
|
||||
|
||||
const std::shared_ptr<FaceFeaturePtr> &FeatureHubDB::GetFaceFeaturePtrCache() const {
|
||||
return m_face_feature_ptr_cache_;
|
||||
return pImpl->m_face_feature_ptr_cache_;
|
||||
}
|
||||
|
||||
std::vector<float> &FeatureHubDB::GetTopKConfidence() {
|
||||
return m_top_k_confidence_;
|
||||
return pImpl->m_top_k_confidence_;
|
||||
}
|
||||
|
||||
std::vector<int64_t> &FeatureHubDB::GetTopKCustomIdsCache() {
|
||||
return m_top_k_custom_ids_cache_;
|
||||
return pImpl->m_top_k_custom_ids_cache_;
|
||||
}
|
||||
|
||||
std::vector<int64_t> &FeatureHubDB::GetExistingIds() {
|
||||
return m_all_ids_;
|
||||
return pImpl->m_all_ids_;
|
||||
}
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
@@ -0,0 +1,395 @@
|
||||
#include "frame_process.h"
|
||||
#include <vector>
|
||||
#include <MNN/ImageProcess.hpp>
|
||||
#include "isf_check.h"
|
||||
|
||||
namespace inspirecv {
|
||||
|
||||
class FrameProcess::Impl {
|
||||
public:
|
||||
Impl() : buffer_(nullptr), height_(0), width_(0), preview_scale_(0), preview_size_(192), rotation_mode_(ROTATION_0) {
|
||||
SetDataFormat(NV21);
|
||||
SetDestFormat(BGR);
|
||||
config_.filterType = MNN::CV::BILINEAR;
|
||||
config_.wrap = MNN::CV::ZERO;
|
||||
}
|
||||
|
||||
void SetDataFormat(DATA_FORMAT data_format) {
|
||||
if (data_format == NV21) {
|
||||
config_.sourceFormat = MNN::CV::YUV_NV21;
|
||||
}
|
||||
if (data_format == NV12) {
|
||||
config_.sourceFormat = MNN::CV::YUV_NV12;
|
||||
}
|
||||
if (data_format == RGBA) {
|
||||
config_.sourceFormat = MNN::CV::RGBA;
|
||||
}
|
||||
if (data_format == RGB) {
|
||||
config_.sourceFormat = MNN::CV::RGB;
|
||||
}
|
||||
if (data_format == BGR) {
|
||||
config_.sourceFormat = MNN::CV::BGR;
|
||||
}
|
||||
if (data_format == BGRA) {
|
||||
config_.sourceFormat = MNN::CV::BGRA;
|
||||
}
|
||||
}
|
||||
|
||||
void SetDestFormat(DATA_FORMAT data_format) {
|
||||
if (data_format == NV21) {
|
||||
config_.destFormat = MNN::CV::YUV_NV21;
|
||||
}
|
||||
if (data_format == NV12) {
|
||||
config_.destFormat = MNN::CV::YUV_NV12;
|
||||
}
|
||||
if (data_format == RGBA) {
|
||||
config_.destFormat = MNN::CV::RGBA;
|
||||
}
|
||||
if (data_format == RGB) {
|
||||
config_.destFormat = MNN::CV::RGB;
|
||||
}
|
||||
if (data_format == BGR) {
|
||||
config_.destFormat = MNN::CV::BGR;
|
||||
}
|
||||
if (data_format == BGRA) {
|
||||
config_.destFormat = MNN::CV::BGRA;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateTransformMatrix() {
|
||||
float srcPoints[] = {0.0f, 0.0f, 0.0f, (float)(height_ - 1), (float)(width_ - 1), 0.0f, (float)(width_ - 1), (float)(height_ - 1)};
|
||||
|
||||
float dstPoints[8];
|
||||
if (rotation_mode_ == ROTATION_270) {
|
||||
float points[] = {(float)(height_ * preview_scale_ - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ * preview_scale_ - 1),
|
||||
(float)(width_ * preview_scale_ - 1),
|
||||
0.0f,
|
||||
(float)(width_ * preview_scale_ - 1)};
|
||||
memcpy(dstPoints, points, sizeof(points));
|
||||
} else if (rotation_mode_ == ROTATION_90) {
|
||||
float points[] = {0.0f,
|
||||
(float)(width_ * preview_scale_ - 1),
|
||||
(float)(height_ * preview_scale_ - 1),
|
||||
(float)(width_ * preview_scale_ - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ * preview_scale_ - 1),
|
||||
0.0f};
|
||||
memcpy(dstPoints, points, sizeof(points));
|
||||
} else if (rotation_mode_ == ROTATION_180) {
|
||||
float points[] = {(float)(width_ * preview_scale_ - 1),
|
||||
(float)(height_ * preview_scale_ - 1),
|
||||
(float)(width_ * preview_scale_ - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ * preview_scale_ - 1),
|
||||
0.0f,
|
||||
0.0f};
|
||||
memcpy(dstPoints, points, sizeof(points));
|
||||
} else { // ROTATION_0
|
||||
float points[] = {0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ * preview_scale_ - 1),
|
||||
(float)(width_ * preview_scale_ - 1),
|
||||
0.0f,
|
||||
(float)(width_ * preview_scale_ - 1),
|
||||
(float)(height_ * preview_scale_ - 1)};
|
||||
memcpy(dstPoints, points, sizeof(points));
|
||||
}
|
||||
|
||||
tr_.setPolyToPoly((MNN::CV::Point *)dstPoints, (MNN::CV::Point *)srcPoints, 4);
|
||||
}
|
||||
|
||||
const uint8_t *buffer_; // Pointer to the data buffer.
|
||||
int height_; // Height of the camera stream image.
|
||||
int width_; // Width of the camera stream image.
|
||||
float preview_scale_; // Scaling factor for the preview image.
|
||||
int preview_size_; // Size of the preview image.
|
||||
MNN::CV::Matrix tr_; // Affine transformation matrix.
|
||||
ROTATION_MODE rotation_mode_; // Current rotation mode.
|
||||
MNN::CV::ImageProcess::Config config_; // Image processing configuration.
|
||||
};
|
||||
|
||||
FrameProcess FrameProcess::Create(const uint8_t *data_buffer, int height, int width, DATA_FORMAT data_format, ROTATION_MODE rotation_mode) {
|
||||
FrameProcess process;
|
||||
process.SetDataBuffer(data_buffer, height, width);
|
||||
process.SetDataFormat(data_format);
|
||||
process.SetRotationMode(rotation_mode);
|
||||
return process;
|
||||
}
|
||||
|
||||
FrameProcess FrameProcess::Create(const inspirecv::Image &image, DATA_FORMAT data_format, ROTATION_MODE rotation_mode) {
|
||||
return Create(image.Data(), image.Height(), image.Width(), data_format, rotation_mode);
|
||||
}
|
||||
|
||||
FrameProcess::FrameProcess() : pImpl(std::make_unique<Impl>()) {
|
||||
pImpl->UpdateTransformMatrix();
|
||||
}
|
||||
|
||||
FrameProcess::~FrameProcess() = default;
|
||||
|
||||
FrameProcess::FrameProcess(const FrameProcess &other) : pImpl(std::make_unique<Impl>(*other.pImpl)) {}
|
||||
|
||||
FrameProcess::FrameProcess(FrameProcess &&other) noexcept = default;
|
||||
|
||||
FrameProcess &FrameProcess::operator=(const FrameProcess &other) {
|
||||
if (this != &other) {
|
||||
*pImpl = *other.pImpl;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
FrameProcess &FrameProcess::operator=(FrameProcess &&other) noexcept = default;
|
||||
|
||||
void FrameProcess::SetDataBuffer(const uint8_t *data_buffer, int height, int width) {
|
||||
pImpl->buffer_ = data_buffer;
|
||||
pImpl->height_ = height;
|
||||
pImpl->width_ = width;
|
||||
pImpl->preview_scale_ = pImpl->preview_size_ / static_cast<float>(std::max(height, width));
|
||||
pImpl->UpdateTransformMatrix();
|
||||
}
|
||||
|
||||
void FrameProcess::SetPreviewSize(const int size) {
|
||||
pImpl->preview_size_ = size;
|
||||
pImpl->preview_scale_ = pImpl->preview_size_ / static_cast<float>(std::max(pImpl->height_, pImpl->width_));
|
||||
pImpl->UpdateTransformMatrix();
|
||||
}
|
||||
|
||||
void FrameProcess::SetPreviewScale(const float scale) {
|
||||
pImpl->preview_scale_ = scale;
|
||||
pImpl->preview_size_ = static_cast<int>(pImpl->preview_scale_ * std::max(pImpl->height_, pImpl->width_));
|
||||
pImpl->UpdateTransformMatrix();
|
||||
}
|
||||
|
||||
void FrameProcess::SetRotationMode(ROTATION_MODE mode) {
|
||||
pImpl->rotation_mode_ = mode;
|
||||
pImpl->UpdateTransformMatrix();
|
||||
}
|
||||
|
||||
void FrameProcess::SetDataFormat(DATA_FORMAT data_format) {
|
||||
pImpl->SetDataFormat(data_format);
|
||||
}
|
||||
|
||||
void FrameProcess::SetDestFormat(DATA_FORMAT data_format) {
|
||||
pImpl->SetDestFormat(data_format);
|
||||
}
|
||||
|
||||
float FrameProcess::GetPreviewScale() {
|
||||
return pImpl->preview_scale_;
|
||||
}
|
||||
|
||||
inspirecv::TransformMatrix FrameProcess::GetAffineMatrix() const {
|
||||
auto affine_matrix = inspirecv::TransformMatrix::Create();
|
||||
affine_matrix[0] = pImpl->tr_[0];
|
||||
affine_matrix[1] = pImpl->tr_[1];
|
||||
affine_matrix[2] = pImpl->tr_[2];
|
||||
affine_matrix[3] = pImpl->tr_[3];
|
||||
affine_matrix[4] = pImpl->tr_[4];
|
||||
affine_matrix[5] = pImpl->tr_[5];
|
||||
return affine_matrix;
|
||||
}
|
||||
|
||||
int FrameProcess::GetHeight() const {
|
||||
return pImpl->height_;
|
||||
}
|
||||
|
||||
int FrameProcess::GetWidth() const {
|
||||
return pImpl->width_;
|
||||
}
|
||||
|
||||
ROTATION_MODE FrameProcess::getRotationMode() const {
|
||||
return pImpl->rotation_mode_;
|
||||
}
|
||||
|
||||
inspirecv::Image FrameProcess::ExecuteImageAffineProcessing(inspirecv::TransformMatrix &affine_matrix, const int width_out,
|
||||
const int height_out) const {
|
||||
int sw = pImpl->width_;
|
||||
int sh = pImpl->height_;
|
||||
int rot_sw = sw;
|
||||
int rot_sh = sh;
|
||||
MNN::CV::Matrix tr;
|
||||
std::vector<float> tr_cv({1, 0, 0, 0, 1, 0, 0, 0, 1});
|
||||
memcpy(tr_cv.data(), affine_matrix.Squeeze().data(), sizeof(float) * 6);
|
||||
tr.set9(tr_cv.data());
|
||||
MNN::CV::Matrix tr_inv;
|
||||
tr.invert(&tr_inv);
|
||||
std::shared_ptr<MNN::CV::ImageProcess> process(MNN::CV::ImageProcess::create(pImpl->config_));
|
||||
process->setMatrix(tr_inv);
|
||||
auto img_out = inspirecv::Image::Create(width_out, height_out, 3);
|
||||
std::shared_ptr<MNN::Tensor> tensor(MNN::Tensor::create<uint8_t>(std::vector<int>{1, height_out, width_out, 3}, (uint8_t *)img_out.Data()));
|
||||
auto ret = process->convert(pImpl->buffer_, sw, sh, 0, tensor.get());
|
||||
INSPIREFACE_CHECK_MSG(ret == MNN::ErrorCode::NO_ERROR, "ImageProcess::convert failed");
|
||||
return img_out;
|
||||
}
|
||||
|
||||
inspirecv::Image FrameProcess::ExecutePreviewImageProcessing(bool with_rotation) {
|
||||
return ExecuteImageScaleProcessing(pImpl->preview_scale_, with_rotation);
|
||||
}
|
||||
|
||||
inspirecv::Image FrameProcess::ExecuteImageScaleProcessing(const float scale, bool with_rotation) {
|
||||
int sw = pImpl->width_;
|
||||
int sh = pImpl->height_;
|
||||
int rot_sw = sw;
|
||||
int rot_sh = sh;
|
||||
// MNN::CV::Matrix tr;
|
||||
std::shared_ptr<MNN::CV::ImageProcess> process(MNN::CV::ImageProcess::create(pImpl->config_));
|
||||
if (pImpl->rotation_mode_ == ROTATION_270 && with_rotation) {
|
||||
float srcPoints[] = {
|
||||
0.0f, 0.0f, 0.0f, (float)(pImpl->height_ - 1), (float)(pImpl->width_ - 1), 0.0f, (float)(pImpl->width_ - 1), (float)(pImpl->height_ - 1),
|
||||
};
|
||||
float dstPoints[] = {
|
||||
(float)(pImpl->height_ * scale - 1), 0.0f, 0.0f, 0.0f, (float)(pImpl->height_ * scale - 1), (float)(pImpl->width_ * scale - 1), 0.0f,
|
||||
(float)(pImpl->width_ * scale - 1)};
|
||||
|
||||
pImpl->tr_.setPolyToPoly((MNN::CV::Point *)dstPoints, (MNN::CV::Point *)srcPoints, 4);
|
||||
process->setMatrix(pImpl->tr_);
|
||||
int scaled_height = static_cast<int>(pImpl->width_ * scale);
|
||||
int scaled_width = static_cast<int>(pImpl->height_ * scale);
|
||||
inspirecv::Image img_out(scaled_width, scaled_height, 3);
|
||||
std::shared_ptr<MNN::Tensor> tensor(
|
||||
MNN::Tensor::create<uint8_t>(std::vector<int>{1, scaled_height, scaled_width, 3}, (uint8_t *)img_out.Data()));
|
||||
auto ret = process->convert(pImpl->buffer_, sw, sh, 0, tensor.get());
|
||||
INSPIREFACE_CHECK_MSG(ret == MNN::ErrorCode::NO_ERROR, "ImageProcess::convert failed");
|
||||
return img_out;
|
||||
} else if (pImpl->rotation_mode_ == ROTATION_90 && with_rotation) {
|
||||
float srcPoints[] = {
|
||||
0.0f, 0.0f, 0.0f, (float)(pImpl->height_ - 1), (float)(pImpl->width_ - 1), 0.0f, (float)(pImpl->width_ - 1), (float)(pImpl->height_ - 1),
|
||||
};
|
||||
float dstPoints[] = {
|
||||
0.0f,
|
||||
(float)(pImpl->width_ * scale - 1),
|
||||
(float)(pImpl->height_ * scale - 1),
|
||||
(float)(pImpl->width_ * scale - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(pImpl->height_ * scale - 1),
|
||||
0.0f,
|
||||
};
|
||||
pImpl->tr_.setPolyToPoly((MNN::CV::Point *)dstPoints, (MNN::CV::Point *)srcPoints, 4);
|
||||
process->setMatrix(pImpl->tr_);
|
||||
int scaled_height = static_cast<int>(pImpl->width_ * scale);
|
||||
int scaled_width = static_cast<int>(pImpl->height_ * scale);
|
||||
inspirecv::Image img_out(scaled_width, scaled_height, 3);
|
||||
std::shared_ptr<MNN::Tensor> tensor(
|
||||
MNN::Tensor::create<uint8_t>(std::vector<int>{1, scaled_height, scaled_width, 3}, (uint8_t *)img_out.Data()));
|
||||
auto ret = process->convert(pImpl->buffer_, sw, sh, 0, tensor.get());
|
||||
INSPIREFACE_CHECK_MSG(ret == MNN::ErrorCode::NO_ERROR, "ImageProcess::convert failed");
|
||||
return img_out;
|
||||
} else if (pImpl->rotation_mode_ == ROTATION_180 && with_rotation) {
|
||||
float srcPoints[] = {
|
||||
0.0f, 0.0f, 0.0f, (float)(pImpl->height_ - 1), (float)(pImpl->width_ - 1), 0.0f, (float)(pImpl->width_ - 1), (float)(pImpl->height_ - 1),
|
||||
};
|
||||
float dstPoints[] = {
|
||||
(float)(pImpl->width_ * scale - 1),
|
||||
(float)(pImpl->height_ * scale - 1),
|
||||
(float)(pImpl->width_ * scale - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(pImpl->height_ * scale - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
};
|
||||
pImpl->tr_.setPolyToPoly((MNN::CV::Point *)dstPoints, (MNN::CV::Point *)srcPoints, 4);
|
||||
process->setMatrix(pImpl->tr_);
|
||||
int scaled_height = static_cast<int>(pImpl->height_ * scale);
|
||||
int scaled_width = static_cast<int>(pImpl->width_ * scale);
|
||||
inspirecv::Image img_out(scaled_width, scaled_height, 3);
|
||||
std::shared_ptr<MNN::Tensor> tensor(
|
||||
MNN::Tensor::create<uint8_t>(std::vector<int>{1, scaled_height, scaled_width, 3}, (uint8_t *)img_out.Data()));
|
||||
auto ret = process->convert(pImpl->buffer_, sw, sh, 0, tensor.get());
|
||||
INSPIREFACE_CHECK_MSG(ret == MNN::ErrorCode::NO_ERROR, "ImageProcess::convert failed");
|
||||
return img_out;
|
||||
} else {
|
||||
float srcPoints[] = {
|
||||
0.0f, 0.0f, 0.0f, (float)(pImpl->height_ - 1), (float)(pImpl->width_ - 1), 0.0f, (float)(pImpl->width_ - 1), (float)(pImpl->height_ - 1),
|
||||
};
|
||||
float dstPoints[] = {
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(pImpl->height_ * scale - 1),
|
||||
(float)(pImpl->width_ * scale - 1),
|
||||
0.0f,
|
||||
(float)(pImpl->width_ * scale - 1),
|
||||
(float)(pImpl->height_ * scale - 1),
|
||||
};
|
||||
pImpl->tr_.setPolyToPoly((MNN::CV::Point *)dstPoints, (MNN::CV::Point *)srcPoints, 4);
|
||||
process->setMatrix(pImpl->tr_);
|
||||
int scaled_height = static_cast<int>(pImpl->height_ * scale);
|
||||
int scaled_width = static_cast<int>(pImpl->width_ * scale);
|
||||
|
||||
inspirecv::Image img_out(scaled_width, scaled_height, 3);
|
||||
std::shared_ptr<MNN::Tensor> tensor(
|
||||
MNN::Tensor::create<uint8_t>(std::vector<int>{1, scaled_height, scaled_width, 3}, (uint8_t *)img_out.Data()));
|
||||
auto ret = process->convert(pImpl->buffer_, sw, sh, 0, tensor.get());
|
||||
INSPIREFACE_CHECK_MSG(ret == MNN::ErrorCode::NO_ERROR, "ImageProcess::convert failed");
|
||||
return img_out;
|
||||
}
|
||||
}
|
||||
|
||||
inspirecv::TransformMatrix FrameProcess::GetRotationModeAffineMatrix() const {
|
||||
float srcPoints[] = {0.0f, 0.0f, 0.0f, (float)(pImpl->height_ - 1), (float)(pImpl->width_ - 1), 0.0f, (float)(pImpl->width_ - 1), (float)(pImpl->height_ - 1)};
|
||||
float dstPoints[8];
|
||||
|
||||
if (pImpl->rotation_mode_ == ROTATION_270) {
|
||||
float points[] = {(float)(pImpl->height_ - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(pImpl->height_ - 1),
|
||||
(float)(pImpl->width_ - 1),
|
||||
0.0f,
|
||||
(float)(pImpl->width_ - 1)};
|
||||
memcpy(dstPoints, points, sizeof(points));
|
||||
} else if (pImpl->rotation_mode_ == ROTATION_90) {
|
||||
float points[] = {0.0f,
|
||||
(float)(pImpl->width_ - 1),
|
||||
(float)(pImpl->height_ - 1),
|
||||
(float)(pImpl->width_ - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(pImpl->height_ - 1),
|
||||
0.0f};
|
||||
memcpy(dstPoints, points, sizeof(points));
|
||||
} else if (pImpl->rotation_mode_ == ROTATION_180) {
|
||||
float points[] = {(float)(pImpl->width_ - 1),
|
||||
(float)(pImpl->height_ - 1),
|
||||
(float)(pImpl->width_ - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(pImpl->height_ - 1),
|
||||
0.0f,
|
||||
0.0f};
|
||||
memcpy(dstPoints, points, sizeof(points));
|
||||
} else { // ROTATION_0
|
||||
float points[] = {0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(pImpl->height_ - 1),
|
||||
(float)(pImpl->width_ - 1),
|
||||
0.0f,
|
||||
(float)(pImpl->width_ - 1),
|
||||
(float)(pImpl->height_ - 1)};
|
||||
memcpy(dstPoints, points, sizeof(points));
|
||||
}
|
||||
|
||||
MNN::CV::Matrix tr;
|
||||
tr.setPolyToPoly((MNN::CV::Point *)dstPoints, (MNN::CV::Point *)srcPoints, 4);
|
||||
|
||||
auto affine_matrix = inspirecv::TransformMatrix::Create();
|
||||
affine_matrix[0] = tr[0];
|
||||
affine_matrix[1] = tr[1];
|
||||
affine_matrix[2] = tr[2];
|
||||
affine_matrix[3] = tr[3];
|
||||
affine_matrix[4] = tr[4];
|
||||
affine_matrix[5] = tr[5];
|
||||
|
||||
return affine_matrix;
|
||||
}
|
||||
|
||||
} // namespace inspirecv
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "RgaUtils.h"
|
||||
#include "rga/utils.h"
|
||||
#include "rga/dma_alloc.h"
|
||||
#include "initialization_module/launch.h"
|
||||
#include <launch.h>
|
||||
|
||||
namespace inspire {
|
||||
|
||||
@@ -109,7 +109,7 @@ private:
|
||||
channels = c;
|
||||
buffer_size = width * height * channels;
|
||||
|
||||
int ret = dma_buf_alloc(INSPIRE_LAUNCH->GetRockchipDmaHeapPath().c_str(), buffer_size, &dma_fd, &virtual_addr);
|
||||
int ret = dma_buf_alloc(INSPIREFACE_CONTEXT->GetRockchipDmaHeapPath().c_str(), buffer_size, &dma_fd, &virtual_addr);
|
||||
if (ret < 0) {
|
||||
INSPIRECV_LOG(ERROR) << "Failed to allocate DMA buffer: " << ret;
|
||||
return false;
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef INSPIRE_CUDA_TOOLKIT_H
|
||||
#define INSPIRE_CUDA_TOOLKIT_H
|
||||
|
||||
#include "data_type.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
// Get the number of CUDA devices
|
||||
int32_t INSPIRE_API_EXPORT GetCudaDeviceCount(int32_t *device_count);
|
||||
|
||||
// Check the availability of CUDA
|
||||
int32_t INSPIRE_API_EXPORT CheckCudaUsability(int32_t *is_support);
|
||||
|
||||
// Internal function, print detailed information of CUDA devices
|
||||
int32_t INSPIRE_API_EXPORT _PrintCudaDeviceInfo();
|
||||
|
||||
// Wrapper function to print CUDA device information
|
||||
int32_t INSPIRE_API_EXPORT PrintCudaDeviceInfo();
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
#endif // INSPIRE_CUDA_TOOLKIT_H
|
||||
@@ -6,6 +6,8 @@
|
||||
#ifndef INSPIRE_FACE_DATATYPE_H
|
||||
#define INSPIRE_FACE_DATATYPE_H
|
||||
|
||||
#include <inspirecv/inspirecv.h>
|
||||
|
||||
#include <cstdint>
|
||||
#if defined(_WIN32) && (defined(_DEBUG) || defined(DEBUG))
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
@@ -16,7 +18,15 @@
|
||||
#define INSPIRE_API
|
||||
#endif
|
||||
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#if defined(_WIN32)
|
||||
#ifdef ISF_BUILD_SHARED_LIBS
|
||||
#define INSPIRE_API_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define INSPIRE_API_EXPORT
|
||||
#endif
|
||||
#else
|
||||
#define INSPIRE_API_EXPORT __attribute__((visibility("default")))
|
||||
#endif // _WIN32
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846264338327950288
|
||||
@@ -152,6 +162,33 @@ typedef std::string String;
|
||||
*/
|
||||
typedef std::vector<int> IndexList;
|
||||
|
||||
/**
|
||||
* @enum DetectMode
|
||||
* @brief Enumeration for different detection modes.
|
||||
*/
|
||||
enum DetectModuleMode {
|
||||
DETECT_MODE_ALWAYS_DETECT = 0, ///< Detection mode: Always detect
|
||||
DETECT_MODE_LIGHT_TRACK, ///< Detection mode: Light face track
|
||||
DETECT_MODE_TRACK_BY_DETECT, ///< Detection mode: Tracking by detection
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct CustomPipelineParameter
|
||||
* @brief Structure to hold custom parameters for the face detection and processing pipeline.
|
||||
*
|
||||
* Includes options for enabling various features such as recognition, liveness detection, and quality assessment.
|
||||
*/
|
||||
typedef struct CustomPipelineParameter {
|
||||
bool enable_recognition = false; ///< Enable face recognition feature
|
||||
bool enable_liveness = false; ///< Enable RGB liveness detection feature
|
||||
bool enable_ir_liveness = false; ///< Enable IR (Infrared) liveness detection feature
|
||||
bool enable_mask_detect = false; ///< Enable mask detection feature
|
||||
bool enable_face_attribute = false; ///< Enable face attribute prediction feature
|
||||
bool enable_face_quality = false; ///< Enable face quality assessment feature
|
||||
bool enable_interaction_liveness = false; ///< Enable interactive liveness detection feature
|
||||
bool enable_face_pose = false; ///< Enable face pose estimation feature
|
||||
} ContextCustomParameter;
|
||||
|
||||
/** @struct FaceLoc
|
||||
* @brief Struct representing standardized face landmarks for detection.
|
||||
*
|
||||
@@ -191,6 +228,74 @@ typedef struct FaceFeatureEntity {
|
||||
float* data;
|
||||
} FaceFeaturePtr;
|
||||
|
||||
// Search for most similar vectors
|
||||
struct FaceSearchResult {
|
||||
int64_t id;
|
||||
double similarity;
|
||||
std::vector<float> feature;
|
||||
};
|
||||
|
||||
/** @struct FaceEmbedding
|
||||
* @brief Struct for face embedding data.
|
||||
*
|
||||
* Contains the isNormal flag and the embedding vector.
|
||||
*/
|
||||
struct FaceEmbedding {
|
||||
int32_t isNormal;
|
||||
float norm;
|
||||
Embedded embedding;
|
||||
};
|
||||
|
||||
/** @struct FaceInteractionState
|
||||
* @brief Struct for face interaction state data.
|
||||
*
|
||||
* Contains the confidence scores for face interaction.
|
||||
*/
|
||||
struct FaceInteractionState {
|
||||
float left_eye_status_confidence;
|
||||
float right_eye_status_confidence;
|
||||
};
|
||||
|
||||
/** @struct FaceInteractionAction
|
||||
* @brief Struct for face interaction action data.
|
||||
*
|
||||
* Contains the actions for face interaction.
|
||||
*/
|
||||
struct FaceInteractionAction {
|
||||
int32_t normal; ///< Normal action.
|
||||
int32_t shake; ///< Shake action.
|
||||
int32_t jawOpen; ///< Jaw open action.
|
||||
int32_t headRaise; ///< Head raise action.
|
||||
int32_t blink; ///< Blink action.
|
||||
};
|
||||
|
||||
/** @struct FaceAttributeResult
|
||||
* @brief Struct for face attribute result data.
|
||||
*
|
||||
* Contains the results for face attribute.
|
||||
*/
|
||||
struct FaceAttributeResult {
|
||||
int32_t race; ///< Race of the detected face.
|
||||
///< 0: Black;
|
||||
///< 1: Asian;
|
||||
///< 2: Latino/Hispanic;
|
||||
///< 3: Middle Eastern;
|
||||
///< 4: White;
|
||||
int32_t gender; ///< Gender of the detected face.
|
||||
///< 0: Female;
|
||||
///< 1: Male;
|
||||
int32_t ageBracket; ///< Age bracket of the detected face.
|
||||
///< 0: 0-2 years old;
|
||||
///< 1: 3-9 years old;
|
||||
///< 2: 10-19 years old;
|
||||
///< 3: 20-29 years old;
|
||||
///< 4: 30-39 years old;
|
||||
///< 5: 40-49 years old;
|
||||
///< 6: 50-59 years old;
|
||||
///< 7: 60-69 years old;
|
||||
///< 8: more than 70 years old;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
} // namespace inspire
|
||||
@@ -8,11 +8,8 @@
|
||||
#ifndef INSPIRE_FACE_FACEDATATYPE_H
|
||||
#define INSPIRE_FACE_FACEDATATYPE_H
|
||||
|
||||
// Include the necessary header files
|
||||
#include "../../data_type.h"
|
||||
#include "../face_info/face_object_internal.h"
|
||||
#include "data_type.h"
|
||||
|
||||
// Define the namespace "inspire" for encapsulation
|
||||
namespace inspire {
|
||||
|
||||
/**
|
||||
@@ -55,9 +52,9 @@ typedef struct TransMatrix {
|
||||
} TransMatrix;
|
||||
|
||||
/**
|
||||
* Struct to represent hyper face data.
|
||||
* Struct to represent basic face data.
|
||||
*/
|
||||
typedef struct HyperFaceData {
|
||||
typedef struct FaceTrackWrap {
|
||||
int trackState; ///< Track state
|
||||
int inGroupIndex; ///< Index within a group
|
||||
int trackId; ///< Track ID
|
||||
@@ -69,7 +66,7 @@ typedef struct HyperFaceData {
|
||||
float quality[5]; ///< Quality values for key points
|
||||
Point2F densityLandmark[106]; ///< Face density landmark
|
||||
int densityLandmarkEnable; ///< Density landmark enable
|
||||
} HyperFaceData;
|
||||
} FaceTrackWrap;
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
@@ -6,28 +6,17 @@
|
||||
#ifndef INSPIRE_FEATURE_HUB_DB_H
|
||||
#define INSPIRE_FEATURE_HUB_DB_H
|
||||
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "data_type.h"
|
||||
#include "feature_hub/embedding_db/embedding_db.h"
|
||||
#include "log.h"
|
||||
#include <mutex>
|
||||
|
||||
// Default database file name used in the FaceContext.
|
||||
#define DB_FILE_NAME ".feature_hub_db_v0"
|
||||
|
||||
#define FEATURE_HUB_DB FeatureHubDB::GetInstance()
|
||||
#define INSPIREFACE_FEATURE_HUB inspire::FeatureHubDB::GetInstance()
|
||||
#define INSPIRE_INVALID_ID -1
|
||||
|
||||
namespace inspire {
|
||||
|
||||
// Comparator function object to sort SearchResult by score (descending order)
|
||||
struct CompareByScore {
|
||||
bool operator()(const FaceSearchResult& a, const FaceSearchResult& b) const {
|
||||
return a.similarity > b.similarity;
|
||||
}
|
||||
};
|
||||
|
||||
typedef enum SearchMode {
|
||||
SEARCH_MODE_EAGER = 0, // Eager mode: Stops when a vector meets the threshold.
|
||||
SEARCH_MODE_EXHAUSTIVE, // Exhaustive mode: Searches until the best match is found.
|
||||
@@ -43,7 +32,7 @@ typedef enum PrimaryKeyMode {
|
||||
* @brief Structure to configure database settings for FaceRecognition.
|
||||
*/
|
||||
using DatabaseConfiguration = struct DatabaseConfiguration {
|
||||
PrimaryKeyMode primary_key_mode = PrimaryKeyMode::AUTO_INCREMENT; ///<
|
||||
PrimaryKeyMode primary_key_mode = PrimaryKeyMode::AUTO_INCREMENT; ///< Primary key mode
|
||||
bool enable_persistence = false; ///< Whether to enable data persistence.
|
||||
std::string persistence_db_path; ///< Path to the database file.
|
||||
float recognition_threshold = 0.48f; ///< Face search threshold
|
||||
@@ -51,72 +40,75 @@ using DatabaseConfiguration = struct DatabaseConfiguration {
|
||||
};
|
||||
|
||||
/**
|
||||
* @class FeatureHub
|
||||
* @class FeatureHubDB
|
||||
* @brief Service for internal feature vector storage.
|
||||
*
|
||||
* This class provides methods for face feature extraction, registration, update, search, and more.
|
||||
* It uses the PIMPL (Pointer to Implementation) pattern to hide implementation details.
|
||||
*/
|
||||
class INSPIRE_API FeatureHubDB {
|
||||
private:
|
||||
static std::mutex mutex_; ///< Mutex lock
|
||||
static std::shared_ptr<FeatureHubDB> instance_; ///< FeatureHub Instance
|
||||
class INSPIRE_API_EXPORT FeatureHubDB {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for FeatureHubDB class.
|
||||
*/
|
||||
FeatureHubDB();
|
||||
|
||||
/**
|
||||
* @brief Destructor for FeatureHubDB class.
|
||||
*/
|
||||
~FeatureHubDB();
|
||||
|
||||
FeatureHubDB(const FeatureHubDB&) = delete;
|
||||
FeatureHubDB& operator=(const FeatureHubDB&) = delete;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Enables the feature hub with the specified configuration and matrix core.
|
||||
*
|
||||
* This function initializes and configures the feature hub based on the provided database
|
||||
* configuration and the specified matrix processing core. It prepares the hub for operation,
|
||||
* setting up necessary resources such as database connections and data processing pipelines.
|
||||
*
|
||||
* @param configuration The database configuration settings used to configure the hub.
|
||||
* @param core The matrix core used for processing, defaulting to OpenCV if not specified.
|
||||
* @brief Gets the singleton instance of FeatureHubDB.
|
||||
* @return Shared pointer to the FeatureHubDB instance.
|
||||
*/
|
||||
static std::shared_ptr<FeatureHubDB> GetInstance();
|
||||
|
||||
/**
|
||||
* @brief Enables the feature hub with the specified configuration.
|
||||
* @param configuration The database configuration settings.
|
||||
* @return int32_t Returns a status code indicating success (0) or failure (non-zero).
|
||||
*/
|
||||
int32_t EnableHub(const DatabaseConfiguration& configuration);
|
||||
|
||||
/**
|
||||
* @brief Disables the feature hub, freeing all associated resources.
|
||||
*
|
||||
* This function stops all operations within the hub, releases all occupied resources,
|
||||
* such as database connections and internal data structures. It is used to safely
|
||||
* shutdown the hub when it is no longer needed or before the application exits, ensuring
|
||||
* that all resources are properly cleaned up.
|
||||
*
|
||||
* @return int32_t Returns a status code indicating success (0) or failure (non-zero).
|
||||
*/
|
||||
int32_t DisableHub();
|
||||
|
||||
/**
|
||||
* @brief Get all ids in the database.
|
||||
* @param ids Output parameter to store the ids.
|
||||
* @return int32_t Status code of the operation.
|
||||
*/
|
||||
int32_t GetAllIds();
|
||||
|
||||
static std::shared_ptr<FeatureHubDB> GetInstance();
|
||||
|
||||
/**
|
||||
* @brief Searches for a face feature within stored data.
|
||||
* @param queryFeature Embedded feature to search for.
|
||||
* @param searchResult SearchResult object to store search results.
|
||||
* @param returnFeature Whether to return the feature data.
|
||||
* @return int32_t Status code of the search operation.
|
||||
*/
|
||||
int32_t SearchFaceFeature(const Embedded& queryFeature, FaceSearchResult& searchResult, bool returnFeature = true);
|
||||
|
||||
/**
|
||||
* @brief Search the stored data for the top k facial features that are most similar.
|
||||
* @param topK Maximum search
|
||||
* @param queryFeature Embedded feature to search for.
|
||||
* @param topK Maximum number of results to return.
|
||||
* @return int32_t Status code of the search operation.
|
||||
*/
|
||||
int32_t SearchFaceFeatureTopKCache(const Embedded& queryFeature, size_t topK);
|
||||
|
||||
/**
|
||||
* @brief Search the stored data for the top k facial features that are most similar.
|
||||
* @param topK Maximum search
|
||||
* @param queryFeature Embedded feature to search for.
|
||||
* @param searchResult Vector to store search results.
|
||||
* @param topK Maximum number of results to return.
|
||||
* @param returnFeature Whether to return the feature data.
|
||||
* @return int32_t Status code of the search operation.
|
||||
*/
|
||||
int32_t SearchFaceFeatureTopK(const Embedded& queryFeature, std::vector<FaceSearchResult>& searchResult, size_t topK, bool returnFeature = false);
|
||||
@@ -124,39 +116,38 @@ public:
|
||||
/**
|
||||
* @brief Inserts a face feature with a custom ID.
|
||||
* @param feature Vector of floats representing the face feature.
|
||||
* @param tag String tag associated with the feature.
|
||||
* @param customId Custom ID for the feature.
|
||||
* @param id ID for the feature.
|
||||
* @param result_id Output parameter to store the resulting ID.
|
||||
* @return int32_t Status code of the insertion operation.
|
||||
*/
|
||||
int32_t FaceFeatureInsert(const std::vector<float>& feature, int32_t id, int64_t& result_id);
|
||||
|
||||
/**
|
||||
* @brief Removes a face feature by its custom ID.
|
||||
* @param customId Custom ID of the feature to remove.
|
||||
* @brief Removes a face feature by its ID.
|
||||
* @param id ID of the feature to remove.
|
||||
* @return int32_t Status code of the removal operation.
|
||||
*/
|
||||
int32_t FaceFeatureRemove(int32_t id);
|
||||
|
||||
/**
|
||||
* @brief Updates a face feature by its custom ID.
|
||||
* @brief Updates a face feature by its ID.
|
||||
* @param feature Vector of floats representing the new face feature.
|
||||
* @param tag String tag associated with the feature.
|
||||
* @param customId Custom ID of the feature to update.
|
||||
* @param customId ID of the feature to update.
|
||||
* @return int32_t Status code of the update operation.
|
||||
*/
|
||||
int32_t FaceFeatureUpdate(const std::vector<float>& feature, int32_t customId);
|
||||
|
||||
/**
|
||||
* @brief Retrieves a face feature by its custom ID.
|
||||
* @param customId Custom ID of the feature to retrieve.
|
||||
* @brief Retrieves a face feature by its ID.
|
||||
* @param id ID of the feature to retrieve.
|
||||
* @return int32_t Status code of the retrieval operation.
|
||||
*/
|
||||
int32_t GetFaceFeature(int32_t id);
|
||||
|
||||
/**
|
||||
* @brief Retrieves a face feature by its custom ID.
|
||||
* @param customId Custom ID of the feature to retrieve.
|
||||
* @param feature Vector of floats representing the face feature.
|
||||
* @brief Retrieves a face feature by its ID.
|
||||
* @param id ID of the feature to retrieve.
|
||||
* @param feature Vector to store the retrieved feature.
|
||||
* @return int32_t Status code of the retrieval operation.
|
||||
*/
|
||||
int32_t GetFaceFeature(int32_t id, std::vector<float>& feature);
|
||||
@@ -181,27 +172,26 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Computes the cosine similarity between two feature vectors.
|
||||
*
|
||||
* @param v1 First feature vector.
|
||||
* @param v2 Second feature vector.
|
||||
* @param res Output parameter to store the cosine similarity result.
|
||||
* @param normalize Whether to normalize the vectors before computing similarity.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
static int32_t CosineSimilarity(const std::vector<float>& v1, const std::vector<float>& v2, float& res, bool normalize = false);
|
||||
|
||||
/**
|
||||
* @brief Computes the cosine similarity between two feature vectors.
|
||||
*
|
||||
* @param v1 Pointer to the first feature vector.
|
||||
* @param v2 Pointer to the second feature vector.
|
||||
* @param size Size of the feature vectors.
|
||||
* @param res Output parameter to store the cosine similarity result.
|
||||
* @param normalize Whether to normalize the vectors before computing similarity.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
static int32_t CosineSimilarity(const float* v1, const float* v2, int32_t size, float& res, bool normalize = true);
|
||||
|
||||
public:
|
||||
// Getter Function
|
||||
// Getter methods
|
||||
|
||||
/**
|
||||
* @brief Gets the cache used for search operations in face feature data.
|
||||
@@ -216,8 +206,7 @@ public:
|
||||
const std::shared_ptr<FaceFeaturePtr>& GetFaceFeaturePtrCache() const;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the total number of facial features stored in the feature block.
|
||||
*
|
||||
* @brief Retrieves the total number of facial features stored.
|
||||
* @return int32_t Total number of facial features.
|
||||
*/
|
||||
int32_t GetFaceFeatureCount();
|
||||
@@ -240,37 +229,15 @@ public:
|
||||
*/
|
||||
std::vector<int64_t>& GetExistingIds();
|
||||
|
||||
/**
|
||||
* @brief Constructor for FeatureHub class.
|
||||
*/
|
||||
FeatureHubDB();
|
||||
|
||||
/**
|
||||
* @brief Prints information about the feature matrix.
|
||||
*/
|
||||
void PrintFeatureMatrixInfo();
|
||||
|
||||
private:
|
||||
Embedded m_search_face_feature_cache_; ///< Cache for face feature data used in search operations
|
||||
Embedded m_getter_face_feature_cache_; ///< Cache for face feature data used in search operations
|
||||
std::shared_ptr<FaceFeaturePtr> m_face_feature_ptr_cache_; ///< Shared pointer to cache of face feature pointers
|
||||
class Impl;
|
||||
|
||||
std::vector<FaceSearchResult> m_search_top_k_cache_; ///< Cache for top k search results
|
||||
std::vector<float> m_top_k_confidence_; ///< Cache for top k confidence scores
|
||||
std::vector<int64_t> m_top_k_custom_ids_cache_; ///< Cache for top k custom ids
|
||||
std::unique_ptr<Impl> pImpl;
|
||||
|
||||
std::vector<int64_t> m_all_ids_; ///< Cache for all ids
|
||||
|
||||
private:
|
||||
DatabaseConfiguration m_db_configuration_; ///< Configuration settings for the database
|
||||
float m_recognition_threshold_{0.48f}; ///< Threshold value for face recognition
|
||||
SearchMode m_search_mode_{SEARCH_MODE_EAGER}; ///< Flag to determine if the search should find the most similar feature
|
||||
|
||||
bool m_enable_{false}; ///< Running status
|
||||
|
||||
std::mutex m_res_mtx_; ///< Mutex for thread safety.
|
||||
static std::mutex mutex_;
|
||||
static std::shared_ptr<FeatureHubDB> instance_;
|
||||
};
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
#endif // INSPIRE_FEATURE_HUB_DB_H
|
||||
#endif // INSPIRE_FEATURE_HUB_DB_H
|
||||
@@ -0,0 +1,198 @@
|
||||
#ifndef INSPIREFACE_FRAME_PROCESS_H
|
||||
#define INSPIREFACE_FRAME_PROCESS_H
|
||||
|
||||
#include <memory>
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include "data_type.h"
|
||||
|
||||
namespace inspirecv {
|
||||
|
||||
/**
|
||||
* @brief Enum to represent rotation modes.
|
||||
*/
|
||||
enum ROTATION_MODE { ROTATION_0 = 0, ROTATION_90 = 1, ROTATION_180 = 2, ROTATION_270 = 3 };
|
||||
|
||||
/**
|
||||
* @brief Enum to represent data formats.
|
||||
*/
|
||||
enum DATA_FORMAT { NV21 = 0, NV12 = 1, RGBA = 2, RGB = 3, BGR = 4, BGRA = 5 };
|
||||
|
||||
/**
|
||||
* @brief A class to handle camera stream and image processing.
|
||||
*/
|
||||
class INSPIRE_API_EXPORT FrameProcess {
|
||||
public:
|
||||
/**
|
||||
* @brief Create a FrameProcess instance.
|
||||
*
|
||||
* @param data_buffer Pointer to the data buffer.
|
||||
* @param height Height of the image.
|
||||
* @param width Width of the image.
|
||||
* @param data_format Data format (e.g., NV21, RGBA).
|
||||
* @param rotation_mode Rotation mode (e.g., ROTATION_0, ROTATION_90).
|
||||
* @return FrameProcess instance.
|
||||
*/
|
||||
static FrameProcess Create(const uint8_t* data_buffer, int height, int width, DATA_FORMAT data_format = BGR,
|
||||
ROTATION_MODE rotation_mode = ROTATION_0);
|
||||
|
||||
/**
|
||||
* @brief Create a FrameProcess instance from an inspirecv::Image.
|
||||
*
|
||||
* @param image The image to process.
|
||||
* @param data_format Data format (e.g., NV21, RGBA).
|
||||
* @param rotation_mode Rotation mode (e.g., ROTATION_0, ROTATION_90).
|
||||
* @return FrameProcess instance.
|
||||
*/
|
||||
static FrameProcess Create(const inspirecv::Image& image, DATA_FORMAT data_format = BGR, ROTATION_MODE rotation_mode = ROTATION_0);
|
||||
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
*/
|
||||
FrameProcess();
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
~FrameProcess();
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
*/
|
||||
FrameProcess(const FrameProcess& other);
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
*/
|
||||
FrameProcess(FrameProcess&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
*/
|
||||
FrameProcess& operator=(const FrameProcess& other);
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
*/
|
||||
FrameProcess& operator=(FrameProcess&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Set the data buffer, height, and width of the camera stream.
|
||||
*
|
||||
* @param data_buffer Pointer to the data buffer.
|
||||
* @param height Height of the image.
|
||||
* @param width Width of the image.
|
||||
*/
|
||||
void SetDataBuffer(const uint8_t* data_buffer, int height, int width);
|
||||
|
||||
/**
|
||||
* @brief Set the preview size.
|
||||
*
|
||||
* @param size Preview size.
|
||||
*/
|
||||
void SetPreviewSize(const int size);
|
||||
|
||||
/**
|
||||
* @brief Set the preview scale.
|
||||
*
|
||||
* @param scale Preview scale.
|
||||
*/
|
||||
void SetPreviewScale(const float scale);
|
||||
|
||||
/**
|
||||
* @brief Set the rotation mode.
|
||||
*
|
||||
* @param mode Rotation mode (e.g., ROTATION_0, ROTATION_90).
|
||||
*/
|
||||
void SetRotationMode(ROTATION_MODE mode);
|
||||
|
||||
/**
|
||||
* @brief Set the data format.
|
||||
*
|
||||
* @param data_format Data format (e.g., NV21, RGBA).
|
||||
*/
|
||||
void SetDataFormat(DATA_FORMAT data_format);
|
||||
|
||||
/**
|
||||
* @brief Set the destination format.
|
||||
*
|
||||
* @param data_format Data format (e.g., NV21, RGBA).
|
||||
*/
|
||||
void SetDestFormat(DATA_FORMAT data_format);
|
||||
|
||||
/**
|
||||
* @brief Get an affine-transformed image.
|
||||
*
|
||||
* @param affine_matrix Affine transformation matrix.
|
||||
* @param width_out Width of the output image.
|
||||
* @param height_out Height of the output image.
|
||||
* @return inspirecv::Image Affine-transformed image.
|
||||
*/
|
||||
inspirecv::Image ExecuteImageAffineProcessing(inspirecv::TransformMatrix& affine_matrix, const int width_out, const int height_out) const;
|
||||
|
||||
/**
|
||||
* @brief Get a preview image with optional rotation.
|
||||
*
|
||||
* @param with_rotation True if rotation is applied, false otherwise.
|
||||
* @return inspirecv::Image Preview image.
|
||||
*/
|
||||
inspirecv::Image ExecutePreviewImageProcessing(bool with_rotation);
|
||||
|
||||
/**
|
||||
* @brief Get the preview scale.
|
||||
*
|
||||
* @return float Preview scale.
|
||||
*/
|
||||
float GetPreviewScale();
|
||||
|
||||
/**
|
||||
* @brief Execute image scale processing.
|
||||
*
|
||||
* @param scale Scale factor.
|
||||
* @param with_rotation True if rotation is applied, false otherwise.
|
||||
* @return inspirecv::Image Scaled image.
|
||||
*/
|
||||
inspirecv::Image ExecuteImageScaleProcessing(const float scale, bool with_rotation);
|
||||
|
||||
/**
|
||||
* @brief Get the affine transformation matrix.
|
||||
*
|
||||
* @return inspirecv::TransformMatrix Affine transformation matrix.
|
||||
*/
|
||||
inspirecv::TransformMatrix GetAffineMatrix() const;
|
||||
|
||||
/**
|
||||
* @brief Get the rotation mode affine transformation matrix, scale coefficient is not included.
|
||||
*
|
||||
* @return inspirecv::TransformMatrix Rotation mode affine transformation matrix.
|
||||
*/
|
||||
inspirecv::TransformMatrix GetRotationModeAffineMatrix() const;
|
||||
|
||||
/**
|
||||
* @brief Get the height of the camera stream image.
|
||||
*
|
||||
* @return int Height.
|
||||
*/
|
||||
int GetHeight() const;
|
||||
|
||||
/**
|
||||
* @brief Get the width of the camera stream image.
|
||||
*
|
||||
* @return int Width.
|
||||
*/
|
||||
int GetWidth() const;
|
||||
|
||||
/**
|
||||
* @brief Get the current rotation mode.
|
||||
*
|
||||
* @return ROTATION_MODE Current rotation mode.
|
||||
*/
|
||||
ROTATION_MODE getRotationMode() const;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pImpl;
|
||||
};
|
||||
|
||||
} // namespace inspirecv
|
||||
|
||||
#endif // INSPIREFACE_FRAME_PROCESS_H
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "session.h"
|
||||
#include "cuda_toolkit.h"
|
||||
#include "data_type.h"
|
||||
#include "log.h"
|
||||
#include "herror.h"
|
||||
#include "feature_hub_db.h"
|
||||
#include "frame_process.h"
|
||||
#include "isf_check.h"
|
||||
#include "launch.h"
|
||||
#include "log.h"
|
||||
#include "similarity_converter.h"
|
||||
#include "spend_timer.h"
|
||||
#include "information.h"
|
||||
#include "face_warpper.h"
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef INSPIRE_FACE_CHECK_H
|
||||
#define INSPIRE_FACE_CHECK_H
|
||||
#include "log.h"
|
||||
#include "herror.h"
|
||||
|
||||
#define INSPIREFACE_RETURN_IF_ERROR(...) \
|
||||
do { \
|
||||
const int32_t _status = (__VA_ARGS__); \
|
||||
if (_status != HSUCCEED) { \
|
||||
INSPIRE_LOGE("Error code: %d", _status); \
|
||||
return _status; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define INSPIREFACE_LOG_IF(severity, condition) \
|
||||
if (condition) \
|
||||
INSPIRE_LOG##severity
|
||||
|
||||
#define INSPIREFACE_CHECK(condition) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
INSPIRE_LOGF("Check failed: (%s)", #condition); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define INSPIREFACE_CHECK_MSG(condition, message) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
INSPIRE_LOGF("Check failed: (%s) %s", #condition, message); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif // INSPIRE_FACE_CHECK_H
|
||||
@@ -5,28 +5,42 @@
|
||||
#pragma once
|
||||
#ifndef INSPIREFACE_LAUNCH_H
|
||||
#define INSPIREFACE_LAUNCH_H
|
||||
#include "middleware/model_archive/inspire_archive.h"
|
||||
#if defined(ISF_ENABLE_RGA)
|
||||
#include "middleware/nexus_processor/rga/dma_alloc.h"
|
||||
#endif
|
||||
#include <mutex>
|
||||
#include "middleware/inference_wrapper/inference_wrapper.h"
|
||||
#include "middleware/system.h"
|
||||
|
||||
#ifndef INSPIRE_API
|
||||
#define INSPIRE_API
|
||||
#endif
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include "data_type.h"
|
||||
|
||||
#define INSPIRE_LAUNCH inspire::Launch::GetInstance()
|
||||
#define INSPIREFACE_CONTEXT inspire::Launch::GetInstance()
|
||||
|
||||
namespace inspire {
|
||||
|
||||
// Forward declarations
|
||||
class InspireArchive;
|
||||
|
||||
// The Launch class acts as the main entry point for the InspireFace system.
|
||||
// It is responsible for loading static resources such as models, configurations, and parameters.
|
||||
class INSPIRE_API Launch {
|
||||
class INSPIRE_API_EXPORT Launch {
|
||||
public:
|
||||
// Special Backend enum for CoreML
|
||||
enum NNInferenceBackend {
|
||||
NN_INFERENCE_CPU = 0,
|
||||
NN_INFERENCE_MMM_CUDA,
|
||||
NN_INFERENCE_COREML_CPU,
|
||||
NN_INFERENCE_COREML_GPU,
|
||||
NN_INFERENCE_COREML_ANE,
|
||||
NN_INFERENCE_TENSORRT_CUDA,
|
||||
};
|
||||
|
||||
enum LandmarkEngine {
|
||||
LANDMARK_HYPLMV2_0_25 = 0,
|
||||
LANDMARK_HYPLMV2_0_50,
|
||||
LANDMARK_INSIGHTFACE_2D106_TRACK,
|
||||
};
|
||||
|
||||
Launch(const Launch&) = delete; // Delete the copy constructor to prevent copying.
|
||||
Launch& operator=(const Launch&) = delete; // Delete the assignment operator to prevent assignment.
|
||||
~Launch(); // Destructor needs to be defined where the implementation is complete
|
||||
|
||||
// Retrieves the singleton instance of Launch, ensuring that only one instance exists.
|
||||
static std::shared_ptr<Launch> GetInstance();
|
||||
@@ -61,10 +75,10 @@ public:
|
||||
std::string GetExtensionPath() const;
|
||||
|
||||
// Set the global coreml inference mode
|
||||
void SetGlobalCoreMLInferenceMode(InferenceWrapper::SpecialBackend mode);
|
||||
void SetGlobalCoreMLInferenceMode(NNInferenceBackend mode);
|
||||
|
||||
// Get the global coreml inference mode
|
||||
InferenceWrapper::SpecialBackend GetGlobalCoreMLInferenceMode() const;
|
||||
NNInferenceBackend GetGlobalCoreMLInferenceMode() const;
|
||||
|
||||
// Build the extension path
|
||||
void BuildAppleExtensionPath(const std::string& resource_path);
|
||||
@@ -75,35 +89,30 @@ public:
|
||||
// Get the cuda device id
|
||||
int32_t GetCudaDeviceId() const;
|
||||
|
||||
// Set the face detect pixel list
|
||||
void SetFaceDetectPixelList(const std::vector<int32_t>& pixel_list);
|
||||
|
||||
// Get the face detect pixel list
|
||||
std::vector<int32_t> GetFaceDetectPixelList() const;
|
||||
|
||||
// Set the face detect model list
|
||||
void SetFaceDetectModelList(const std::vector<std::string>& model_list);
|
||||
|
||||
// Get the face detect model list
|
||||
std::vector<std::string> GetFaceDetectModelList() const;
|
||||
|
||||
// Switch the landmark engine
|
||||
void SwitchLandmarkEngine(LandmarkEngine engine);
|
||||
|
||||
private:
|
||||
// Parameters
|
||||
std::string m_rockchip_dma_heap_path_;
|
||||
// Private constructor for the singleton pattern
|
||||
Launch();
|
||||
|
||||
// Constructor
|
||||
Launch() : m_load_(false), m_archive_(nullptr) {
|
||||
#if defined(ISF_ENABLE_RGA)
|
||||
#if defined(ISF_RKNPU_RV1106)
|
||||
m_rockchip_dma_heap_path_ = RV1106_CMA_HEAP_PATH;
|
||||
#else
|
||||
m_rockchip_dma_heap_path_ = DMA_HEAP_DMA32_UNCACHE_PATCH;
|
||||
#endif
|
||||
INSPIRE_LOGW("Rockchip dma heap configured path: %s", m_rockchip_dma_heap_path_.c_str());
|
||||
#endif
|
||||
} ///< Private constructor for the singleton pattern.
|
||||
|
||||
static std::mutex mutex_; ///< Mutex for synchronizing access to the singleton instance.
|
||||
static std::shared_ptr<Launch> instance_; ///< The singleton instance of Launch.
|
||||
|
||||
std::string m_extension_path_;
|
||||
|
||||
std::unique_ptr<InspireArchive> m_archive_; ///< The archive containing all necessary resources.
|
||||
bool m_load_; ///< Flag indicating whether the resources have been successfully loaded.
|
||||
|
||||
int32_t m_cuda_device_id_{0};
|
||||
|
||||
InferenceWrapper::SpecialBackend m_global_coreml_inference_mode_{InferenceWrapper::COREML_ANE}; ///< The global coreml inference mode
|
||||
// Private implementation class
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pImpl;
|
||||
};
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
#endif // INSPIREFACE_LAUNCH_H
|
||||
#endif // INSPIREFACE_LAUNCH_H
|
||||
89
cpp-package/inspireface/cpp/inspireface/include/inspireface/log.h
Executable file
89
cpp-package/inspireface/cpp/inspireface/include/inspireface/log.h
Executable file
@@ -0,0 +1,89 @@
|
||||
#ifndef INSPIRE_FACE_LOG_H
|
||||
#define INSPIRE_FACE_LOG_H
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include "data_type.h"
|
||||
|
||||
// Macro to extract the filename from the full path
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||
|
||||
#ifdef ANDROID
|
||||
// Android platform log macros
|
||||
#define INSPIRE_ANDROID_LOG_TAG "InspireFace"
|
||||
#define INSPIRE_LOGD(...) inspire::LogManager::getInstance()->logAndroid(inspire::LogLevel::ISF_LOG_DEBUG, INSPIRE_ANDROID_LOG_TAG, __VA_ARGS__)
|
||||
#define INSPIRE_LOGI(...) inspire::LogManager::getInstance()->logAndroid(inspire::LogLevel::ISF_LOG_INFO, INSPIRE_ANDROID_LOG_TAG, __VA_ARGS__)
|
||||
#define INSPIRE_LOGW(...) inspire::LogManager::getInstance()->logAndroid(inspire::LogLevel::ISF_LOG_WARN, INSPIRE_ANDROID_LOG_TAG, __VA_ARGS__)
|
||||
#define INSPIRE_LOGE(...) inspire::LogManager::getInstance()->logAndroid(inspire::LogLevel::ISF_LOG_ERROR, INSPIRE_ANDROID_LOG_TAG, __VA_ARGS__)
|
||||
#define INSPIRE_LOGF(...) inspire::LogManager::getInstance()->logAndroid(inspire::LogLevel::ISF_LOG_FATAL, INSPIRE_ANDROID_LOG_TAG, __VA_ARGS__)
|
||||
#else
|
||||
// Standard platform log macros
|
||||
#define INSPIRE_LOGD(...) \
|
||||
inspire::LogManager::getInstance()->logStandard(inspire::LogLevel::ISF_LOG_DEBUG, __FILENAME__, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define INSPIRE_LOGI(...) inspire::LogManager::getInstance()->logStandard(inspire::LogLevel::ISF_LOG_INFO, "", "", -1, __VA_ARGS__)
|
||||
#define INSPIRE_LOGW(...) inspire::LogManager::getInstance()->logStandard(inspire::LogLevel::ISF_LOG_WARN, "", "", -1, __VA_ARGS__)
|
||||
#define INSPIRE_LOGE(...) inspire::LogManager::getInstance()->logStandard(inspire::LogLevel::ISF_LOG_ERROR, "", "", -1, __VA_ARGS__)
|
||||
#define INSPIRE_LOGF(...) inspire::LogManager::getInstance()->logStandard(inspire::LogLevel::ISF_LOG_FATAL, "", "", -1, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
// Macro to set the global log level
|
||||
#define INSPIRE_SET_LOG_LEVEL(level) inspire::LogManager::getInstance()->setLogLevel(level)
|
||||
|
||||
namespace inspire {
|
||||
|
||||
// Log levels
|
||||
enum LogLevel { ISF_LOG_NONE = 0, ISF_LOG_DEBUG, ISF_LOG_INFO, ISF_LOG_WARN, ISF_LOG_ERROR, ISF_LOG_FATAL };
|
||||
|
||||
/**
|
||||
* @class LogManager
|
||||
* @brief A singleton class for logging messages to the console or Android logcat.
|
||||
*
|
||||
* This class provides methods to log messages of different severity levels (DEBUG, INFO, WARN, ERROR, FATAL)
|
||||
* to the console or Android logcat based on the current log level setting.
|
||||
*
|
||||
* Implementation details are hidden using the PIMPL (Pointer to Implementation) pattern.
|
||||
*/
|
||||
class INSPIRE_API_EXPORT LogManager {
|
||||
public:
|
||||
// Get the singleton instance
|
||||
static LogManager* getInstance();
|
||||
|
||||
// Destructor
|
||||
~LogManager();
|
||||
|
||||
// Set the log level
|
||||
void setLogLevel(LogLevel level);
|
||||
|
||||
// Get the current log level
|
||||
LogLevel getLogLevel() const;
|
||||
|
||||
#ifdef ANDROID
|
||||
// Method for logging on the Android platform
|
||||
void logAndroid(LogLevel level, const char* tag, const char* format, ...) const;
|
||||
#else
|
||||
// Method for standard platform logging
|
||||
void logStandard(LogLevel level, const char* filename, const char* function, int line, const char* format, ...) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Private constructor for singleton pattern
|
||||
LogManager();
|
||||
|
||||
// Disable copy construction and assignment
|
||||
LogManager(const LogManager&) = delete;
|
||||
LogManager& operator=(const LogManager&) = delete;
|
||||
|
||||
// Forward declaration of the implementation class
|
||||
class Impl;
|
||||
|
||||
// Pointer to implementation
|
||||
std::unique_ptr<Impl> pImpl;
|
||||
|
||||
// Static instance for singleton pattern
|
||||
static LogManager* instance;
|
||||
};
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
#endif // INSPIRE_FACE_LOG_H
|
||||
@@ -0,0 +1,199 @@
|
||||
#ifndef INSPIRE_FACE_SESSION_H
|
||||
#define INSPIRE_FACE_SESSION_H
|
||||
#include <memory>
|
||||
#include "data_type.h"
|
||||
#include "frame_process.h"
|
||||
#include "face_warpper.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
/**
|
||||
* @brief The face algorithm session class.
|
||||
*/
|
||||
class INSPIRE_API_EXPORT Session {
|
||||
public:
|
||||
Session();
|
||||
~Session();
|
||||
|
||||
Session(Session&&) noexcept;
|
||||
Session& operator=(Session&&) noexcept;
|
||||
|
||||
Session(const Session&) = delete;
|
||||
Session& operator=(const Session&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Create a new session with the given parameters.
|
||||
* @param detect_mode The mode of face detection.
|
||||
* @param max_detect_face The maximum number of faces to detect.
|
||||
* @param param The custom pipeline parameter.
|
||||
* @param detect_level_px The detection level in pixels.
|
||||
* @param track_by_detect_mode_fps The tracking frame rate.
|
||||
* @return A new session.
|
||||
*/
|
||||
static Session Create(DetectModuleMode detect_mode, int32_t max_detect_face, const CustomPipelineParameter& param, int32_t detect_level_px = -1,
|
||||
int32_t track_by_detect_mode_fps = -1);
|
||||
|
||||
/**
|
||||
* @brief Create a new session pointer with the given parameters.
|
||||
* @param detect_mode The mode of face detection.
|
||||
* @param max_detect_face The maximum number of faces to detect.
|
||||
* @param param The custom pipeline parameter.
|
||||
* @param detect_level_px The detection level in pixels.
|
||||
* @param track_by_detect_mode_fps The tracking frame rate.
|
||||
* @return A raw pointer to new session. The caller is responsible for memory management.
|
||||
*/
|
||||
static Session* CreatePtr(DetectModuleMode detect_mode, int32_t max_detect_face, const CustomPipelineParameter& param,
|
||||
int32_t detect_level_px = -1, int32_t track_by_detect_mode_fps = -1) {
|
||||
return new Session(Create(detect_mode, max_detect_face, param, detect_level_px, track_by_detect_mode_fps));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the track preview size.
|
||||
* @param preview_size The preview size.
|
||||
*/
|
||||
void SetTrackPreviewSize(int32_t preview_size);
|
||||
|
||||
/**
|
||||
* @brief Set the minimum face pixel size.
|
||||
* @param min_face_pixel_size The minimum face pixel size.
|
||||
*/
|
||||
void SetFilterMinimumFacePixelSize(int32_t min_face_pixel_size);
|
||||
|
||||
/**
|
||||
* @brief Set the face detect threshold.
|
||||
* @param threshold The face detect threshold.
|
||||
*/
|
||||
void SetFaceDetectThreshold(float threshold);
|
||||
|
||||
/**
|
||||
* @brief Set the track mode smooth ratio.
|
||||
* @param smooth_ratio The track mode smooth ratio.
|
||||
*/
|
||||
void SetTrackModeSmoothRatio(int32_t smooth_ratio);
|
||||
|
||||
/**
|
||||
* @brief Set the track mode num smooth cache frame.
|
||||
* @param num_smooth_cache_frame The track mode num smooth cache frame.
|
||||
*/
|
||||
void SetTrackModeNumSmoothCacheFrame(int32_t num_smooth_cache_frame);
|
||||
|
||||
/**
|
||||
* @brief Set the track mode detect interval.
|
||||
* @param detect_interval The track mode detect interval.
|
||||
*/
|
||||
void SetTrackModeDetectInterval(int32_t detect_interval);
|
||||
|
||||
/**
|
||||
* @brief Detect and track the faces in the frame.
|
||||
* @param process The frame process.
|
||||
* @param results The detected faces.
|
||||
*/
|
||||
int32_t FaceDetectAndTrack(inspirecv::FrameProcess& process, std::vector<FaceTrackWrap>& results);
|
||||
|
||||
/**
|
||||
* @brief Get the face bounding box.
|
||||
* @param face_data The face data.
|
||||
* @return The face bounding box.
|
||||
*/
|
||||
inspirecv::Rect2i GetFaceBoundingBox(const FaceTrackWrap& face_data);
|
||||
|
||||
/**
|
||||
* @brief Get the face dense landmark.
|
||||
* @param face_data The face data.
|
||||
* @return The face dense landmark.
|
||||
*/
|
||||
std::vector<inspirecv::Point2f> GetFaceDenseLandmark(const FaceTrackWrap& face_data);
|
||||
|
||||
/**
|
||||
* @brief Get the face five key points.
|
||||
* @param face_data The face data.
|
||||
* @return The face five key points.
|
||||
*/
|
||||
std::vector<inspirecv::Point2f> GetFaceFiveKeyPoints(const FaceTrackWrap& face_data);
|
||||
|
||||
/**
|
||||
* @brief Extract the face feature.
|
||||
* @param process The frame process.
|
||||
* @param data The face data.
|
||||
* @param embedding The face embedding.
|
||||
* @param normalize The normalize flag.
|
||||
*/
|
||||
int32_t FaceFeatureExtract(inspirecv::FrameProcess& process, FaceTrackWrap& data, FaceEmbedding& embedding, bool normalize = true);
|
||||
|
||||
/**
|
||||
* @brief Get the face alignment image.
|
||||
* @param process The frame process.
|
||||
* @param data The face data.
|
||||
* @param wrapped The wrapped image.
|
||||
*/
|
||||
void GetFaceAlignmentImage(inspirecv::FrameProcess& process, FaceTrackWrap& data, inspirecv::Image& wrapped);
|
||||
|
||||
/**
|
||||
* @brief Extract the face feature with alignment image.
|
||||
* @param process The frame process.
|
||||
* @param embedding The face embedding.
|
||||
* @param normalize The normalize flag.
|
||||
*/
|
||||
int32_t FaceFeatureExtractWithAlignmentImage(inspirecv::FrameProcess& process, FaceEmbedding& embedding, bool normalize = true);
|
||||
|
||||
/**
|
||||
* @brief Extract the face feature with alignment image.
|
||||
* @param wrapped The wrapped image.
|
||||
* @param embedding The face embedding.
|
||||
* @param normalize The normalize flag.
|
||||
*/
|
||||
int32_t FaceFeatureExtractWithAlignmentImage(const inspirecv::Image& wrapped, FaceEmbedding& embedding, bool normalize = true);
|
||||
|
||||
/**
|
||||
* @brief Multiple face pipeline process.
|
||||
* @param process The frame process.
|
||||
* @param param The custom pipeline parameter.
|
||||
* @param face_data_list The face data list.
|
||||
*/
|
||||
int32_t MultipleFacePipelineProcess(inspirecv::FrameProcess& process, const CustomPipelineParameter& param,
|
||||
const std::vector<FaceTrackWrap>& face_data_list);
|
||||
|
||||
/**
|
||||
* @brief Get the RGB liveness confidence.
|
||||
* @return The RGB liveness confidence.
|
||||
*/
|
||||
std::vector<float> GetRGBLivenessConfidence();
|
||||
|
||||
/**
|
||||
* @brief Get the face mask confidence.
|
||||
* @return The face mask confidence.
|
||||
*/
|
||||
std::vector<float> GetFaceMaskConfidence();
|
||||
|
||||
/**
|
||||
* @brief Get the face quality confidence.
|
||||
* @return The face quality confidence.
|
||||
*/
|
||||
std::vector<float> GetFaceQualityConfidence();
|
||||
|
||||
/**
|
||||
* @brief Get the face interaction state.
|
||||
* @return The face interaction state.
|
||||
*/
|
||||
std::vector<FaceInteractionState> GetFaceInteractionState();
|
||||
|
||||
/**
|
||||
* @brief Get the face interaction action.
|
||||
* @return The face interaction action.
|
||||
*/
|
||||
std::vector<FaceInteractionAction> GetFaceInteractionAction();
|
||||
|
||||
/**
|
||||
* @brief Get the face attribute result.
|
||||
* @return The face attribute result.
|
||||
*/
|
||||
std::vector<FaceAttributeResult> GetFaceAttributeResult();
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pImpl;
|
||||
};
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
#endif // INSPIRE_FACE_SESSION_H
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <mutex>
|
||||
#include "data_type.h"
|
||||
|
||||
#define SIMILARITY_CONVERTER_UPDATE_CONFIG(config) inspire::SimilarityConverter::getInstance().updateConfig(config)
|
||||
#define SIMILARITY_CONVERTER_RUN(cosine) inspire::SimilarityConverter::getInstance().convert(cosine)
|
||||
@@ -22,7 +23,7 @@ struct SimilarityConverterConfig {
|
||||
double outputMax = 1.0; // Maximum value of output range
|
||||
};
|
||||
|
||||
class SimilarityConverter {
|
||||
class INSPIRE_API_EXPORT SimilarityConverter {
|
||||
private:
|
||||
SimilarityConverterConfig config;
|
||||
double outputScale; // Scale of output range
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef INSPIRE_FACE_TIMER_H
|
||||
#define INSPIRE_FACE_TIMER_H
|
||||
|
||||
#include "data_type.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
// Get the current time in microseconds.
|
||||
uint64_t INSPIRE_API_EXPORT _now();
|
||||
|
||||
/**
|
||||
* @brief A class to measure the cost of a block of code.
|
||||
*/
|
||||
class INSPIRE_API_EXPORT SpendTimer {
|
||||
public:
|
||||
SpendTimer();
|
||||
explicit SpendTimer(const std::string &name);
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
void Reset();
|
||||
|
||||
uint64_t Get() const;
|
||||
uint64_t Average() const;
|
||||
uint64_t Total() const;
|
||||
uint64_t Count() const;
|
||||
uint64_t Min() const;
|
||||
uint64_t Max() const;
|
||||
const std::string &name() const;
|
||||
std::string Report() const;
|
||||
|
||||
static void Disable();
|
||||
|
||||
protected:
|
||||
uint64_t start_;
|
||||
uint64_t stop_;
|
||||
uint64_t total_;
|
||||
uint64_t count_;
|
||||
uint64_t min_;
|
||||
uint64_t max_;
|
||||
std::string name_;
|
||||
|
||||
static int is_enable;
|
||||
};
|
||||
|
||||
INSPIRE_API_EXPORT std::ostream &operator<<(std::ostream &os, const SpendTimer &timer);
|
||||
|
||||
#define TIME_NOW inspirecv::_now()
|
||||
|
||||
} // namespace inspire
|
||||
#endif // INSPIRE_FACE_TIMER_H
|
||||
@@ -1,15 +0,0 @@
|
||||
/**
|
||||
* Created by Jingyu Yan
|
||||
* @date 2024-10-01
|
||||
*/
|
||||
|
||||
#ifndef INSPIRE_FACE_INFORMATION_H
|
||||
#define INSPIRE_FACE_INFORMATION_H
|
||||
|
||||
#define INSPIRE_FACE_VERSION_MAJOR_STR "1"
|
||||
#define INSPIRE_FACE_VERSION_MINOR_STR "2"
|
||||
#define INSPIRE_FACE_VERSION_PATCH_STR "0"
|
||||
|
||||
#define INSPIRE_FACE_EXTENDED_INFORMATION "InspireFace[Community Edition]@General - Build Time: 2025-03-25"
|
||||
|
||||
#endif // INSPIRE_FACE_INFORMATION_H
|
||||
@@ -1,42 +0,0 @@
|
||||
#ifndef INSPIRE_FACE_CHECK_H
|
||||
#define INSPIRE_FACE_CHECK_H
|
||||
#include "log.h"
|
||||
#include "herror.h"
|
||||
|
||||
#define INSPIREFACE_RETURN_IF_ERROR(...) \
|
||||
do { \
|
||||
const int32_t _status = (__VA_ARGS__); \
|
||||
if (_status != HSUCCEED) { \
|
||||
INSPIRE_LOGE("Error code: %d", _status); \
|
||||
return _status; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define INSPIREFACE_LOG_IF(severity, condition) \
|
||||
if (condition) \
|
||||
INSPIRE_LOG##severity
|
||||
|
||||
|
||||
#define INSPIREFACE_CHECK(condition) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
INSPIRE_LOGF("Check failed: (%s)", #condition); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define INSPIREFACE_CHECK_MSG(condition, message) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
INSPIRE_LOGF("Check failed: (%s) %s", #condition, message); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define INSPIREFACE_CHECK_EQ(a, b) INSPIREFACE_CHECK((a) == (b)) << "Expected equality of these values: " << #a << " vs " << #b
|
||||
#define INSPIREFACE_CHECK_NE(a, b) INSPIREFACE_CHECK((a) != (b)) << "Expected inequality of these values: " << #a << " vs " << #b
|
||||
#define INSPIREFACE_CHECK_LE(a, b) INSPIREFACE_CHECK((a) <= (b)) << "Expected " << #a << " <= " << #b
|
||||
#define INSPIREFAFECE_CHECK_LT(a, b) INSPIREFACE_CHECK((a) < (b)) << "Expected " << #a << " < " << #b
|
||||
#define INSPIREFAFECE_CHECK_GE(a, b) INSPIREFACE_CHECK((a) >= (b)) << "Expected " << #a << " >= " << #b
|
||||
#define INSPIREFAFECE_CHECK_GT(a, b) INSPIREFACE_CHECK((a) > (b)) << "Expected " << #a << " > " << #b
|
||||
|
||||
#endif // INSPIRE_FACE_CHECK_H
|
||||
@@ -3,11 +3,150 @@
|
||||
* @date 2024-10-01
|
||||
*/
|
||||
#include "log.h"
|
||||
#include <mutex>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
namespace inspire {
|
||||
|
||||
// Static Logger initialization
|
||||
// Implementation class for LogManager
|
||||
class LogManager::Impl {
|
||||
public:
|
||||
Impl() : currentLevel(LogLevel::ISF_LOG_INFO) {}
|
||||
|
||||
LogLevel currentLevel;
|
||||
static std::mutex mutex;
|
||||
};
|
||||
|
||||
// Static initialization
|
||||
std::mutex LogManager::Impl::mutex;
|
||||
LogManager* LogManager::instance = nullptr;
|
||||
std::mutex LogManager::mutex;
|
||||
|
||||
// Constructor
|
||||
LogManager::LogManager() : pImpl(std::make_unique<Impl>()) {}
|
||||
|
||||
// Destructor
|
||||
LogManager::~LogManager() = default;
|
||||
|
||||
// Get singleton instance
|
||||
LogManager* LogManager::getInstance() {
|
||||
std::lock_guard<std::mutex> lock(Impl::mutex);
|
||||
if (instance == nullptr) {
|
||||
instance = new LogManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
// Set log level
|
||||
void LogManager::setLogLevel(LogLevel level) {
|
||||
pImpl->currentLevel = level;
|
||||
}
|
||||
|
||||
// Get log level
|
||||
LogLevel LogManager::getLogLevel() const {
|
||||
return pImpl->currentLevel;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
// Android logging implementation
|
||||
void LogManager::logAndroid(LogLevel level, const char* tag, const char* format, ...) const {
|
||||
if (pImpl->currentLevel == LogLevel::ISF_LOG_NONE || level < pImpl->currentLevel)
|
||||
return;
|
||||
|
||||
int androidLevel;
|
||||
switch (level) {
|
||||
case LogLevel::ISF_LOG_DEBUG:
|
||||
androidLevel = ANDROID_LOG_DEBUG;
|
||||
break;
|
||||
case LogLevel::ISF_LOG_INFO:
|
||||
androidLevel = ANDROID_LOG_INFO;
|
||||
break;
|
||||
case LogLevel::ISF_LOG_WARN:
|
||||
androidLevel = ANDROID_LOG_WARN;
|
||||
break;
|
||||
case LogLevel::ISF_LOG_ERROR:
|
||||
androidLevel = ANDROID_LOG_ERROR;
|
||||
break;
|
||||
case LogLevel::ISF_LOG_FATAL:
|
||||
androidLevel = ANDROID_LOG_FATAL;
|
||||
break;
|
||||
default:
|
||||
androidLevel = ANDROID_LOG_DEFAULT;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
__android_log_vprint(androidLevel, tag, format, args);
|
||||
va_end(args);
|
||||
|
||||
// If the log level is fatal, flush the error stream and abort the program
|
||||
if (level == LogLevel::ISF_LOG_FATAL) {
|
||||
std::flush(std::cerr);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Standard logging implementation
|
||||
void LogManager::logStandard(LogLevel level, const char* filename, const char* function, int line, const char* format, ...) const {
|
||||
// Check whether the current level is LOG NONE or the log level is not enough to log
|
||||
if (pImpl->currentLevel == LogLevel::ISF_LOG_NONE || level < pImpl->currentLevel)
|
||||
return;
|
||||
|
||||
// Build log prefix dynamically based on available data
|
||||
bool hasPrintedPrefix = false;
|
||||
if (filename && strlen(filename) > 0) {
|
||||
printf("[%s]", filename);
|
||||
hasPrintedPrefix = true;
|
||||
}
|
||||
if (function && strlen(function) > 0) {
|
||||
printf("[%s]", function);
|
||||
hasPrintedPrefix = true;
|
||||
}
|
||||
if (line != -1) {
|
||||
printf("[%d]", line);
|
||||
hasPrintedPrefix = true;
|
||||
}
|
||||
|
||||
// Only add colon and space if any prefix was printed
|
||||
if (hasPrintedPrefix) {
|
||||
printf(": ");
|
||||
}
|
||||
|
||||
// Set text color for different log levels, but only if not on iOS
|
||||
#ifndef TARGET_OS_IOS
|
||||
if (level == LogLevel::ISF_LOG_ERROR || level == LogLevel::ISF_LOG_FATAL) {
|
||||
printf("\033[1;31m"); // Red color for errors and fatal issues
|
||||
} else if (level == LogLevel::ISF_LOG_WARN) {
|
||||
printf("\033[1;33m"); // Yellow color for warnings
|
||||
}
|
||||
#endif
|
||||
|
||||
// Print the actual log message
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
va_end(args);
|
||||
|
||||
// Reset text color if needed, but only if not on iOS
|
||||
#ifndef TARGET_OS_IOS
|
||||
if (level == LogLevel::ISF_LOG_ERROR || level == LogLevel::ISF_LOG_WARN || level == LogLevel::ISF_LOG_FATAL) {
|
||||
printf("\033[0m"); // Reset color
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("\n"); // New line after log message
|
||||
|
||||
// If the log level is fatal, flush the error stream and abort the program
|
||||
if (level == LogLevel::ISF_LOG_FATAL) {
|
||||
std::flush(std::cerr);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace inspire
|
||||
@@ -1,184 +0,0 @@
|
||||
#ifndef INSPIRE_FACE_LOG_H
|
||||
#define INSPIRE_FACE_LOG_H
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#ifndef INSPIRE_API
|
||||
#define INSPIRE_API
|
||||
#endif
|
||||
|
||||
// Macro to extract the filename from the full path
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||
|
||||
#ifdef ANDROID
|
||||
// Android platform log macros
|
||||
#include <android/log.h>
|
||||
#define INSPIRE_ANDROID_LOG_TAG "InspireFace"
|
||||
#define INSPIRE_LOGD(...) inspire::LogManager::getInstance()->logAndroid(inspire::ISF_LOG_DEBUG, INSPIRE_ANDROID_LOG_TAG, __VA_ARGS__)
|
||||
#define INSPIRE_LOGI(...) inspire::LogManager::getInstance()->logAndroid(inspire::ISF_LOG_INFO, INSPIRE_ANDROID_LOG_TAG, __VA_ARGS__)
|
||||
#define INSPIRE_LOGW(...) inspire::LogManager::getInstance()->logAndroid(inspire::ISF_LOG_WARN, INSPIRE_ANDROID_LOG_TAG, __VA_ARGS__)
|
||||
#define INSPIRE_LOGE(...) inspire::LogManager::getInstance()->logAndroid(inspire::ISF_LOG_ERROR, INSPIRE_ANDROID_LOG_TAG, __VA_ARGS__)
|
||||
#define INSPIRE_LOGF(...) inspire::LogManager::getInstance()->logAndroid(inspire::ISF_LOG_FATAL, INSPIRE_ANDROID_LOG_TAG, __VA_ARGS__)
|
||||
#else
|
||||
// Standard platform log macros
|
||||
#define INSPIRE_LOGD(...) inspire::LogManager::getInstance()->logStandard(inspire::ISF_LOG_DEBUG, __FILENAME__, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define INSPIRE_LOGI(...) inspire::LogManager::getInstance()->logStandard(inspire::ISF_LOG_INFO, "", "", -1, __VA_ARGS__)
|
||||
#define INSPIRE_LOGW(...) inspire::LogManager::getInstance()->logStandard(inspire::ISF_LOG_WARN, "", "", -1, __VA_ARGS__)
|
||||
#define INSPIRE_LOGE(...) inspire::LogManager::getInstance()->logStandard(inspire::ISF_LOG_ERROR, "", "", -1, __VA_ARGS__)
|
||||
#define INSPIRE_LOGF(...) inspire::LogManager::getInstance()->logStandard(inspire::ISF_LOG_FATAL, "", "", -1, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
// Macro to set the global log level
|
||||
#define INSPIRE_SET_LOG_LEVEL(level) inspire::LogManager::getInstance()->setLogLevel(level)
|
||||
|
||||
namespace inspire {
|
||||
|
||||
// Log levels
|
||||
enum LogLevel { ISF_LOG_NONE = 0, ISF_LOG_DEBUG, ISF_LOG_INFO, ISF_LOG_WARN, ISF_LOG_ERROR, ISF_LOG_FATAL };
|
||||
|
||||
/**
|
||||
* @class LogManager
|
||||
* @brief A singleton class for logging messages to the console or Android logcat.
|
||||
*
|
||||
* This class provides methods to log messages of different severity levels (DEBUG, INFO, WARN, ERROR, FATAL)
|
||||
* to the console or Android logcat based on the current log level setting.
|
||||
*/
|
||||
class INSPIRE_API LogManager {
|
||||
private:
|
||||
LogLevel currentLevel;
|
||||
static LogManager* instance;
|
||||
static std::mutex mutex;
|
||||
|
||||
// Private constructor
|
||||
LogManager() : currentLevel(ISF_LOG_INFO) {} // Default log level is INFO
|
||||
|
||||
public:
|
||||
// Disable copy construction and assignment
|
||||
LogManager(const LogManager&) = delete;
|
||||
LogManager& operator=(const LogManager&) = delete;
|
||||
|
||||
// Get the singleton instance
|
||||
static LogManager* getInstance() {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
if (instance == nullptr) {
|
||||
instance = new LogManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
// Set the log level
|
||||
void setLogLevel(LogLevel level) {
|
||||
currentLevel = level;
|
||||
}
|
||||
|
||||
// Get the current log level
|
||||
LogLevel getLogLevel() const {
|
||||
return currentLevel;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
// Method for logging on the Android platform
|
||||
void logAndroid(LogLevel level, const char* tag, const char* format, ...) const {
|
||||
if (currentLevel == ISF_LOG_NONE || level < currentLevel)
|
||||
return;
|
||||
|
||||
int androidLevel;
|
||||
switch (level) {
|
||||
case ISF_LOG_DEBUG:
|
||||
androidLevel = ANDROID_LOG_DEBUG;
|
||||
break;
|
||||
case ISF_LOG_INFO:
|
||||
androidLevel = ANDROID_LOG_INFO;
|
||||
break;
|
||||
case ISF_LOG_WARN:
|
||||
androidLevel = ANDROID_LOG_WARN;
|
||||
break;
|
||||
case ISF_LOG_ERROR:
|
||||
androidLevel = ANDROID_LOG_ERROR;
|
||||
break;
|
||||
case ISF_LOG_FATAL:
|
||||
androidLevel = ANDROID_LOG_FATAL;
|
||||
break;
|
||||
default:
|
||||
androidLevel = ANDROID_LOG_DEFAULT;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
__android_log_vprint(androidLevel, tag, format, args);
|
||||
va_end(args);
|
||||
|
||||
// If the log level is fatal, flush the error stream and abort the program
|
||||
if (level == ISF_LOG_FATAL) {
|
||||
std::flush(std::cerr);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Method for standard platform logging
|
||||
void logStandard(LogLevel level, const char* filename, const char* function, int line, const char* format, ...) const {
|
||||
// Check whether the current level is LOG NONE or the log level is not enough to log
|
||||
if (currentLevel == ISF_LOG_NONE || level < currentLevel)
|
||||
return;
|
||||
|
||||
// Build log prefix dynamically based on available data
|
||||
bool hasPrintedPrefix = false;
|
||||
if (filename && strlen(filename) > 0) {
|
||||
printf("[%s]", filename);
|
||||
hasPrintedPrefix = true;
|
||||
}
|
||||
if (function && strlen(function) > 0) {
|
||||
printf("[%s]", function);
|
||||
hasPrintedPrefix = true;
|
||||
}
|
||||
if (line != -1) {
|
||||
printf("[%d]", line);
|
||||
hasPrintedPrefix = true;
|
||||
}
|
||||
|
||||
// Only add colon and space if any prefix was printed
|
||||
if (hasPrintedPrefix) {
|
||||
printf(": ");
|
||||
}
|
||||
|
||||
// Set text color for different log levels, but only if not on iOS
|
||||
#ifndef TARGET_OS_IOS
|
||||
if (level == ISF_LOG_ERROR || level == ISF_LOG_FATAL) {
|
||||
printf("\033[1;31m"); // Red color for errors and fatal issues
|
||||
} else if (level == ISF_LOG_WARN) {
|
||||
printf("\033[1;33m"); // Yellow color for warnings
|
||||
}
|
||||
#endif
|
||||
|
||||
// Print the actual log message
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
va_end(args);
|
||||
|
||||
// Reset text color if needed, but only if not on iOS
|
||||
#ifndef TARGET_OS_IOS
|
||||
if (level == ISF_LOG_ERROR || level == ISF_LOG_WARN || level == ISF_LOG_FATAL) {
|
||||
printf("\033[0m"); // Reset color
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("\n"); // New line after log message
|
||||
|
||||
// If the log level is fatal, flush the error stream and abort the program
|
||||
if (level == ISF_LOG_FATAL) {
|
||||
std::flush(std::cerr);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
#endif // INSPIRE_FACE_LOG_H
|
||||
@@ -13,8 +13,8 @@
|
||||
#include "configurable.h"
|
||||
#include "log.h"
|
||||
#include "model_archive/inspire_archive.h"
|
||||
#include "nexus_processor/image_processor.h"
|
||||
#include "initialization_module/launch.h"
|
||||
#include "image_process/nexus_processor/image_processor.h"
|
||||
#include <launch.h>
|
||||
#include "system.h"
|
||||
|
||||
namespace inspire {
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
* @param type Type of the inference helper (default: INFER_MNN).
|
||||
* @return int32_t Status of the loading and initialization process.
|
||||
*/
|
||||
int32_t loadData(InspireModel &model, InferenceWrapper::EngineType type = InferenceWrapper::INFER_MNN, bool dynamic = false) {
|
||||
int32_t LoadData(InspireModel &model, InferenceWrapper::EngineType type = InferenceWrapper::INFER_MNN, bool dynamic = false) {
|
||||
m_infer_type_ = type;
|
||||
// must
|
||||
pushData<int>(model.Config(), "model_index", 0);
|
||||
@@ -78,7 +78,7 @@ public:
|
||||
m_nn_inference_->SetNumThreads(getData<int>("threads"));
|
||||
|
||||
if (m_infer_type_ == InferenceWrapper::INFER_TENSORRT) {
|
||||
m_nn_inference_->SetDevice(INSPIRE_LAUNCH->GetCudaDeviceId());
|
||||
m_nn_inference_->SetDevice(INSPIREFACE_CONTEXT->GetCudaDeviceId());
|
||||
}
|
||||
|
||||
#if defined(ISF_GLOBAL_INFERENCE_BACKEND_USE_MNN_CUDA) && !defined(ISF_ENABLE_RKNN)
|
||||
@@ -87,7 +87,13 @@ public:
|
||||
#endif
|
||||
|
||||
#if defined(ISF_ENABLE_APPLE_EXTENSION)
|
||||
m_nn_inference_->SetSpecialBackend(INSPIRE_LAUNCH->GetGlobalCoreMLInferenceMode());
|
||||
if (INSPIREFACE_CONTEXT->GetGlobalCoreMLInferenceMode() == InferenceWrapper::COREML_CPU) {
|
||||
m_nn_inference_->SetSpecialBackend(InferenceWrapper::COREML_CPU);
|
||||
} else if (INSPIREFACE_CONTEXT->GetGlobalCoreMLInferenceMode() == InferenceWrapper::COREML_GPU) {
|
||||
m_nn_inference_->SetSpecialBackend(InferenceWrapper::COREML_GPU);
|
||||
} else if (INSPIREFACE_CONTEXT->GetGlobalCoreMLInferenceMode() == InferenceWrapper::COREML_ANE) {
|
||||
m_nn_inference_->SetSpecialBackend(InferenceWrapper::COREML_ANE);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_output_tensor_info_list_.clear();
|
||||
@@ -99,7 +105,7 @@ public:
|
||||
}
|
||||
int32_t ret;
|
||||
if (model.loadFilePath) {
|
||||
auto extensionPath = INSPIRE_LAUNCH->GetExtensionPath();
|
||||
auto extensionPath = INSPIREFACE_CONTEXT->GetExtensionPath();
|
||||
if (extensionPath.empty()) {
|
||||
INSPIRE_LOGE("Extension path is empty");
|
||||
return InferenceWrapper::WrapperError;
|
||||
|
||||
@@ -1,23 +1,29 @@
|
||||
#ifdef ISF_ENABLE_TENSORRT
|
||||
#ifndef INSPIRE_CUDA_TOOLKIT_H
|
||||
#define INSPIRE_CUDA_TOOLKIT_H
|
||||
#include <cuda_toolkit.h>
|
||||
#include <cuda_runtime_api.h>
|
||||
#include <NvInfer.h>
|
||||
#endif // ISF_ENABLE_TENSORRT
|
||||
#include <log.h>
|
||||
#include "herror.h"
|
||||
#include <herror.h>
|
||||
|
||||
namespace inspire {
|
||||
|
||||
inline static int32_t GetCudaDeviceCount(int32_t *device_count) {
|
||||
int32_t INSPIRE_API_EXPORT GetCudaDeviceCount(int32_t *device_count) {
|
||||
#ifdef ISF_ENABLE_TENSORRT
|
||||
cudaError_t error = cudaGetDeviceCount(device_count);
|
||||
if (error != cudaSuccess) {
|
||||
INSPIRE_LOGE("CUDA error: %s", cudaGetErrorString(error));
|
||||
return HERR_DEVICE_CUDA_UNKNOWN_ERROR;
|
||||
}
|
||||
return HSUCCEED;
|
||||
#else
|
||||
*device_count = 0;
|
||||
return HERR_DEVICE_CUDA_NOT_SUPPORT;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline static int32_t CheckCudaUsability(int32_t *is_support) {
|
||||
int32_t INSPIRE_API_EXPORT CheckCudaUsability(int32_t *is_support) {
|
||||
#ifdef ISF_ENABLE_TENSORRT
|
||||
int device_count;
|
||||
auto ret = GetCudaDeviceCount(&device_count);
|
||||
if (ret != HSUCCEED) {
|
||||
@@ -30,9 +36,14 @@ inline static int32_t CheckCudaUsability(int32_t *is_support) {
|
||||
}
|
||||
*is_support = device_count > 0;
|
||||
return HSUCCEED;
|
||||
#else
|
||||
*is_support = 0;
|
||||
return HERR_DEVICE_CUDA_NOT_SUPPORT;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline static int32_t _PrintCudaDeviceInfo() {
|
||||
int32_t INSPIRE_API_EXPORT _PrintCudaDeviceInfo() {
|
||||
#ifdef ISF_ENABLE_TENSORRT
|
||||
try {
|
||||
INSPIRE_LOGW("TensorRT version: %d.%d.%d", NV_TENSORRT_MAJOR, NV_TENSORRT_MINOR, NV_TENSORRT_PATCH);
|
||||
|
||||
@@ -98,16 +109,22 @@ inline static int32_t _PrintCudaDeviceInfo() {
|
||||
INSPIRE_LOGE("error when printing CUDA device info: %s", e.what());
|
||||
return HERR_DEVICE_CUDA_UNKNOWN_ERROR;
|
||||
}
|
||||
#else
|
||||
INSPIRE_LOGE("CUDA/TensorRT support is not enabled");
|
||||
return HERR_DEVICE_CUDA_NOT_SUPPORT;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline static int32_t PrintCudaDeviceInfo() {
|
||||
int32_t INSPIRE_API_EXPORT PrintCudaDeviceInfo() {
|
||||
#ifdef ISF_ENABLE_TENSORRT
|
||||
INSPIRE_LOGW("================================================");
|
||||
auto ret = _PrintCudaDeviceInfo();
|
||||
INSPIRE_LOGW("================================================");
|
||||
return ret;
|
||||
#else
|
||||
INSPIRE_LOGE("CUDA/TensorRT support is not enabled");
|
||||
return HERR_DEVICE_CUDA_NOT_SUPPORT;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
#endif // INSPIRE_CUDA_TOOLKIT_H
|
||||
#endif // ISF_ENABLE_TENSORRT
|
||||
} // namespace inspire
|
||||
@@ -223,6 +223,12 @@ public:
|
||||
virtual int32_t Process(std::vector<OutputTensorInfo>& output_tensor_info_list) = 0;
|
||||
virtual int32_t ParameterInitialization(std::vector<InputTensorInfo>& input_tensor_info_list,
|
||||
std::vector<OutputTensorInfo>& output_tensor_info_list) = 0;
|
||||
|
||||
#ifdef BATCH_FORWARD_IMPLEMENTED
|
||||
virtual int32_t PreProcessBatch(const std::vector<std::vector<InputTensorInfo>>& input_tensor_info_list) = 0;
|
||||
virtual int32_t ProcessBatch(std::vector<std::vector<OutputTensorInfo>>& output_tensor_info_list) = 0;
|
||||
virtual int32_t PostProcessBatch(std::vector<std::vector<OutputTensorInfo>>& output_tensor_info_list) = 0;
|
||||
#endif
|
||||
|
||||
virtual int32_t SetSpecialBackend(SpecialBackend backend) {
|
||||
special_backend_ = backend;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#if INFERENCE_WRAPPER_ENABLE_TENSORRT
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
@@ -40,7 +41,6 @@ int32_t InferenceWrapperTensorRT::Initialize(char* model_buffer, int model_size,
|
||||
net_->setDevice(device_id_);
|
||||
auto ret = net_->readFromBin(model_buffer, model_size);
|
||||
if (ret != WrapperOk) {
|
||||
std::cout << "model_size: " << model_size << std::endl;
|
||||
PRINT_E("Failed to load TensorRT model\n");
|
||||
return WrapperError;
|
||||
}
|
||||
|
||||
@@ -1,392 +0,0 @@
|
||||
#ifndef INSPIRECV_IMAGE_PROCESS_H
|
||||
#define INSPIRECV_IMAGE_PROCESS_H
|
||||
|
||||
#include <memory>
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include <MNN/ImageProcess.hpp>
|
||||
#include "isf_check.h"
|
||||
|
||||
// using namespace inspire;
|
||||
namespace inspirecv {
|
||||
|
||||
/**
|
||||
* @brief Enum to represent rotation modes.
|
||||
*/
|
||||
enum ROTATION_MODE { ROTATION_0 = 0, ROTATION_90 = 1, ROTATION_180 = 2, ROTATION_270 = 3 };
|
||||
|
||||
/**
|
||||
* @brief Enum to represent data formats.
|
||||
*/
|
||||
enum DATA_FORMAT { NV21 = 0, NV12 = 1, RGBA = 2, RGB = 3, BGR = 4, BGRA = 5 };
|
||||
|
||||
/**
|
||||
* @brief A class to handle camera stream and image processing.
|
||||
*/
|
||||
class InspireImageProcess {
|
||||
public:
|
||||
static InspireImageProcess Create(const uint8_t *data_buffer, int height, int width, DATA_FORMAT data_format = BGR,
|
||||
ROTATION_MODE rotation_mode = ROTATION_0) {
|
||||
InspireImageProcess process;
|
||||
process.SetDataBuffer(data_buffer, height, width);
|
||||
process.SetDataFormat(data_format);
|
||||
process.SetRotationMode(rotation_mode);
|
||||
return process;
|
||||
}
|
||||
|
||||
InspireImageProcess() {
|
||||
SetDataFormat(NV21);
|
||||
SetDestFormat(BGR);
|
||||
config_.filterType = MNN::CV::BILINEAR;
|
||||
config_.wrap = MNN::CV::ZERO;
|
||||
rotation_mode_ = ROTATION_0;
|
||||
preview_size_ = 192;
|
||||
UpdateTransformMatrix();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the data buffer, height, and width of the camera stream.
|
||||
*
|
||||
* @param data_buffer Pointer to the data buffer.
|
||||
* @param height Height of the image.
|
||||
* @param width Width of the image.
|
||||
*/
|
||||
void SetDataBuffer(const uint8_t *data_buffer, int height, int width) {
|
||||
this->buffer_ = data_buffer;
|
||||
this->height_ = height;
|
||||
this->width_ = width;
|
||||
preview_scale_ = preview_size_ / static_cast<float>(std::max(height, width));
|
||||
UpdateTransformMatrix();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the preview size.
|
||||
*
|
||||
* @param size Preview size.
|
||||
*/
|
||||
void SetPreviewSize(const int size) {
|
||||
preview_size_ = size;
|
||||
preview_scale_ = preview_size_ / static_cast<float>(std::max(this->height_, this->width_));
|
||||
UpdateTransformMatrix();
|
||||
}
|
||||
|
||||
void SetPreviewScale(const float scale) {
|
||||
preview_scale_ = scale;
|
||||
preview_size_ = static_cast<int>(preview_scale_ * std::max(this->height_, this->width_));
|
||||
UpdateTransformMatrix();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the rotation mode.
|
||||
*
|
||||
* @param mode Rotation mode (e.g., ROTATION_0, ROTATION_90).
|
||||
*/
|
||||
void SetRotationMode(ROTATION_MODE mode) {
|
||||
rotation_mode_ = mode;
|
||||
UpdateTransformMatrix();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the data format.
|
||||
*
|
||||
* @param data_format Data format (e.g., NV21, RGBA).
|
||||
*/
|
||||
void SetDataFormat(DATA_FORMAT data_format) {
|
||||
if (data_format == NV21) {
|
||||
config_.sourceFormat = MNN::CV::YUV_NV21;
|
||||
}
|
||||
if (data_format == NV12) {
|
||||
config_.sourceFormat = MNN::CV::YUV_NV12;
|
||||
}
|
||||
if (data_format == RGBA) {
|
||||
config_.sourceFormat = MNN::CV::RGBA;
|
||||
}
|
||||
if (data_format == RGB) {
|
||||
config_.sourceFormat = MNN::CV::RGB;
|
||||
}
|
||||
if (data_format == BGR) {
|
||||
config_.sourceFormat = MNN::CV::BGR;
|
||||
}
|
||||
if (data_format == BGRA) {
|
||||
config_.sourceFormat = MNN::CV::BGRA;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the destination format.
|
||||
*
|
||||
* @param data_format Data format (e.g., NV21, RGBA).
|
||||
*/
|
||||
void SetDestFormat(DATA_FORMAT data_format) {
|
||||
if (data_format == NV21) {
|
||||
config_.destFormat = MNN::CV::YUV_NV21;
|
||||
}
|
||||
if (data_format == NV12) {
|
||||
config_.destFormat = MNN::CV::YUV_NV12;
|
||||
}
|
||||
if (data_format == RGBA) {
|
||||
config_.destFormat = MNN::CV::RGBA;
|
||||
}
|
||||
if (data_format == RGB) {
|
||||
config_.destFormat = MNN::CV::RGB;
|
||||
}
|
||||
if (data_format == BGR) {
|
||||
config_.destFormat = MNN::CV::BGR;
|
||||
}
|
||||
if (data_format == BGRA) {
|
||||
config_.destFormat = MNN::CV::BGRA;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get an affine-transformed image.
|
||||
*
|
||||
* @param affine_matrix Affine transformation matrix.
|
||||
* @param width_out Width of the output image.
|
||||
* @param height_out Height of the output image.
|
||||
* @return cv::Mat Affine-transformed image.
|
||||
*/
|
||||
inspirecv::Image ExecuteImageAffineProcessing(inspirecv::TransformMatrix &affine_matrix, const int width_out, const int height_out) const {
|
||||
int sw = width_;
|
||||
int sh = height_;
|
||||
int rot_sw = sw;
|
||||
int rot_sh = sh;
|
||||
MNN::CV::Matrix tr;
|
||||
std::vector<float> tr_cv({1, 0, 0, 0, 1, 0, 0, 0, 1});
|
||||
memcpy(tr_cv.data(), affine_matrix.Squeeze().data(), sizeof(float) * 6);
|
||||
tr.set9(tr_cv.data());
|
||||
MNN::CV::Matrix tr_inv;
|
||||
tr.invert(&tr_inv);
|
||||
std::shared_ptr<MNN::CV::ImageProcess> process(MNN::CV::ImageProcess::create(config_));
|
||||
process->setMatrix(tr_inv);
|
||||
auto img_out = inspirecv::Image::Create(width_out, height_out, 3);
|
||||
std::shared_ptr<MNN::Tensor> tensor(MNN::Tensor::create<uint8_t>(std::vector<int>{1, height_out, width_out, 3}, (uint8_t *)img_out.Data()));
|
||||
auto ret = process->convert(buffer_, sw, sh, 0, tensor.get());
|
||||
INSPIREFACE_CHECK_MSG(ret == MNN::ErrorCode::NO_ERROR, "ImageProcess::convert failed");
|
||||
return img_out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a preview image with optional rotation.
|
||||
*
|
||||
* @param with_rotation True if rotation is applied, false otherwise.
|
||||
* @return cv::Mat Preview image.
|
||||
*/
|
||||
inspirecv::Image ExecutePreviewImageProcessing(bool with_rotation) {
|
||||
return ExecuteImageScaleProcessing(preview_scale_, with_rotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the preview scale.
|
||||
*
|
||||
* @return float Preview scale.
|
||||
*/
|
||||
float GetPreviewScale() {
|
||||
return preview_scale_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Execute image scale processing.
|
||||
*
|
||||
* @param scale Scale factor.
|
||||
* @param with_rotation True if rotation is applied, false otherwise.
|
||||
* @return inspirecv::Image Scaled image.
|
||||
*/
|
||||
inspirecv::Image ExecuteImageScaleProcessing(const float scale, bool with_rotation) {
|
||||
int sw = width_;
|
||||
int sh = height_;
|
||||
int rot_sw = sw;
|
||||
int rot_sh = sh;
|
||||
// MNN::CV::Matrix tr;
|
||||
std::shared_ptr<MNN::CV::ImageProcess> process(MNN::CV::ImageProcess::create(config_));
|
||||
if (rotation_mode_ == ROTATION_270 && with_rotation) {
|
||||
float srcPoints[] = {
|
||||
0.0f, 0.0f, 0.0f, (float)(height_ - 1), (float)(width_ - 1), 0.0f, (float)(width_ - 1), (float)(height_ - 1),
|
||||
};
|
||||
float dstPoints[] = {(float)(height_ * scale - 1), 0.0f, 0.0f, 0.0f, (float)(height_ * scale - 1), (float)(width_ * scale - 1), 0.0f,
|
||||
(float)(width_ * scale - 1)};
|
||||
|
||||
tr_.setPolyToPoly((MNN::CV::Point *)dstPoints, (MNN::CV::Point *)srcPoints, 4);
|
||||
process->setMatrix(tr_);
|
||||
int scaled_height = static_cast<int>(width_ * scale);
|
||||
int scaled_width = static_cast<int>(height_ * scale);
|
||||
inspirecv::Image img_out(scaled_width, scaled_height, 3);
|
||||
std::shared_ptr<MNN::Tensor> tensor(
|
||||
MNN::Tensor::create<uint8_t>(std::vector<int>{1, scaled_height, scaled_width, 3}, (uint8_t *)img_out.Data()));
|
||||
auto ret = process->convert(buffer_, sw, sh, 0, tensor.get());
|
||||
INSPIREFACE_CHECK_MSG(ret == MNN::ErrorCode::NO_ERROR, "ImageProcess::convert failed");
|
||||
return img_out;
|
||||
} else if (rotation_mode_ == ROTATION_90 && with_rotation) {
|
||||
float srcPoints[] = {
|
||||
0.0f, 0.0f, 0.0f, (float)(height_ - 1), (float)(width_ - 1), 0.0f, (float)(width_ - 1), (float)(height_ - 1),
|
||||
};
|
||||
float dstPoints[] = {
|
||||
0.0f, (float)(width_ * scale - 1), (float)(height_ * scale - 1), (float)(width_ * scale - 1), 0.0f, 0.0f, (float)(height_ * scale - 1),
|
||||
0.0f,
|
||||
};
|
||||
tr_.setPolyToPoly((MNN::CV::Point *)dstPoints, (MNN::CV::Point *)srcPoints, 4);
|
||||
process->setMatrix(tr_);
|
||||
int scaled_height = static_cast<int>(width_ * scale);
|
||||
int scaled_width = static_cast<int>(height_ * scale);
|
||||
inspirecv::Image img_out(scaled_width, scaled_height, 3);
|
||||
std::shared_ptr<MNN::Tensor> tensor(
|
||||
MNN::Tensor::create<uint8_t>(std::vector<int>{1, scaled_height, scaled_width, 3}, (uint8_t *)img_out.Data()));
|
||||
auto ret = process->convert(buffer_, sw, sh, 0, tensor.get());
|
||||
INSPIREFACE_CHECK_MSG(ret == MNN::ErrorCode::NO_ERROR, "ImageProcess::convert failed");
|
||||
return img_out;
|
||||
} else if (rotation_mode_ == ROTATION_180 && with_rotation) {
|
||||
float srcPoints[] = {
|
||||
0.0f, 0.0f, 0.0f, (float)(height_ - 1), (float)(width_ - 1), 0.0f, (float)(width_ - 1), (float)(height_ - 1),
|
||||
};
|
||||
float dstPoints[] = {
|
||||
(float)(width_ * scale - 1),
|
||||
(float)(height_ * scale - 1),
|
||||
(float)(width_ * scale - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ * scale - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
};
|
||||
tr_.setPolyToPoly((MNN::CV::Point *)dstPoints, (MNN::CV::Point *)srcPoints, 4);
|
||||
process->setMatrix(tr_);
|
||||
int scaled_height = static_cast<int>(height_ * scale);
|
||||
int scaled_width = static_cast<int>(width_ * scale);
|
||||
inspirecv::Image img_out(scaled_width, scaled_height, 3);
|
||||
std::shared_ptr<MNN::Tensor> tensor(
|
||||
MNN::Tensor::create<uint8_t>(std::vector<int>{1, scaled_height, scaled_width, 3}, (uint8_t *)img_out.Data()));
|
||||
auto ret = process->convert(buffer_, sw, sh, 0, tensor.get());
|
||||
INSPIREFACE_CHECK_MSG(ret == MNN::ErrorCode::NO_ERROR, "ImageProcess::convert failed");
|
||||
return img_out;
|
||||
} else {
|
||||
float srcPoints[] = {
|
||||
0.0f, 0.0f, 0.0f, (float)(height_ - 1), (float)(width_ - 1), 0.0f, (float)(width_ - 1), (float)(height_ - 1),
|
||||
};
|
||||
float dstPoints[] = {
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ * scale - 1),
|
||||
(float)(width_ * scale - 1),
|
||||
0.0f,
|
||||
(float)(width_ * scale - 1),
|
||||
(float)(height_ * scale - 1),
|
||||
};
|
||||
tr_.setPolyToPoly((MNN::CV::Point *)dstPoints, (MNN::CV::Point *)srcPoints, 4);
|
||||
process->setMatrix(tr_);
|
||||
int scaled_height = static_cast<int>(height_ * scale);
|
||||
int scaled_width = static_cast<int>(width_ * scale);
|
||||
|
||||
inspirecv::Image img_out(scaled_width, scaled_height, 3);
|
||||
std::shared_ptr<MNN::Tensor> tensor(
|
||||
MNN::Tensor::create<uint8_t>(std::vector<int>{1, scaled_height, scaled_width, 3}, (uint8_t *)img_out.Data()));
|
||||
auto ret = process->convert(buffer_, sw, sh, 0, tensor.get());
|
||||
INSPIREFACE_CHECK_MSG(ret == MNN::ErrorCode::NO_ERROR, "ImageProcess::convert failed");
|
||||
return img_out;
|
||||
}
|
||||
}
|
||||
|
||||
inspirecv::TransformMatrix GetAffineMatrix() const {
|
||||
auto affine_matrix = inspirecv::TransformMatrix::Create();
|
||||
affine_matrix[0] = tr_[0];
|
||||
affine_matrix[1] = tr_[1];
|
||||
affine_matrix[2] = tr_[2];
|
||||
affine_matrix[3] = tr_[3];
|
||||
affine_matrix[4] = tr_[4];
|
||||
affine_matrix[5] = tr_[5];
|
||||
return affine_matrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the height of the camera stream image.
|
||||
*
|
||||
* @return int Height.
|
||||
*/
|
||||
int GetHeight() const {
|
||||
return height_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the width of the camera stream image.
|
||||
*
|
||||
* @return int Width.
|
||||
*/
|
||||
int GetWidth() const {
|
||||
return width_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current rotation mode.
|
||||
*
|
||||
* @return ROTATION_MODE Current rotation mode.
|
||||
*/
|
||||
ROTATION_MODE getRotationMode() const {
|
||||
return rotation_mode_;
|
||||
}
|
||||
|
||||
private:
|
||||
void UpdateTransformMatrix() {
|
||||
float srcPoints[] = {0.0f, 0.0f, 0.0f, (float)(height_ - 1), (float)(width_ - 1), 0.0f, (float)(width_ - 1), (float)(height_ - 1)};
|
||||
|
||||
float dstPoints[8];
|
||||
if (rotation_mode_ == ROTATION_270) {
|
||||
float points[] = {(float)(height_ * preview_scale_ - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ * preview_scale_ - 1),
|
||||
(float)(width_ * preview_scale_ - 1),
|
||||
0.0f,
|
||||
(float)(width_ * preview_scale_ - 1)};
|
||||
memcpy(dstPoints, points, sizeof(points));
|
||||
} else if (rotation_mode_ == ROTATION_90) {
|
||||
float points[] = {0.0f,
|
||||
(float)(width_ * preview_scale_ - 1),
|
||||
(float)(height_ * preview_scale_ - 1),
|
||||
(float)(width_ * preview_scale_ - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ * preview_scale_ - 1),
|
||||
0.0f};
|
||||
memcpy(dstPoints, points, sizeof(points));
|
||||
} else if (rotation_mode_ == ROTATION_180) {
|
||||
float points[] = {(float)(width_ * preview_scale_ - 1),
|
||||
(float)(height_ * preview_scale_ - 1),
|
||||
(float)(width_ * preview_scale_ - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ * preview_scale_ - 1),
|
||||
0.0f,
|
||||
0.0f};
|
||||
memcpy(dstPoints, points, sizeof(points));
|
||||
} else { // ROTATION_0
|
||||
float points[] = {0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ * preview_scale_ - 1),
|
||||
(float)(width_ * preview_scale_ - 1),
|
||||
0.0f,
|
||||
(float)(width_ * preview_scale_ - 1),
|
||||
(float)(height_ * preview_scale_ - 1)};
|
||||
memcpy(dstPoints, points, sizeof(points));
|
||||
}
|
||||
|
||||
tr_.setPolyToPoly((MNN::CV::Point *)dstPoints, (MNN::CV::Point *)srcPoints, 4);
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t *buffer_; ///< Pointer to the data buffer.
|
||||
int buffer_size_; ///< Size of the data buffer.
|
||||
std::vector<float> rotation_matrix; ///< Rotation matrix.
|
||||
int height_; ///< Height of the camera stream image.
|
||||
int width_; ///< Width of the camera stream image.
|
||||
float preview_scale_; ///< Scaling factor for the preview image.
|
||||
int preview_size_; ///< Size of the preview image.
|
||||
MNN::CV::Matrix tr_; ///< Affine transformation matrix.
|
||||
ROTATION_MODE rotation_mode_; ///< Current rotation mode.
|
||||
MNN::CV::ImageProcess::Config config_; ///< Configuration for image processing.
|
||||
std::shared_ptr<MNN::CV::ImageProcess> process_; ///< Image processing instance.
|
||||
};
|
||||
|
||||
} // namespace inspirecv
|
||||
|
||||
#endif // INSPIRECV_IMAGE_PROCESS_H
|
||||
@@ -10,7 +10,9 @@
|
||||
#include "inspire_model/inspire_model.h"
|
||||
#include "yaml-cpp/yaml.h"
|
||||
#include "fstream"
|
||||
#include "recognition_module/similarity_converter.h"
|
||||
#include "similarity_converter.h"
|
||||
#include "launch.h"
|
||||
#include "track_module/landmark/landmark_param.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
@@ -110,6 +112,17 @@ public:
|
||||
return m_archive_->GetFileContent(filename);
|
||||
}
|
||||
|
||||
const std::vector<int>& GetFaceDetectPixelList() const {
|
||||
return m_face_detect_pixel_list_;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& GetFaceDetectModelList() const {
|
||||
return m_face_detect_model_list_;
|
||||
}
|
||||
|
||||
const std::shared_ptr<LandmarkParam>& GetLandmarkParam() const {
|
||||
return m_landmark_param_;
|
||||
}
|
||||
private:
|
||||
int32_t loadManifestFile() {
|
||||
if (m_archive_->QueryLoadStatus() == SARC_SUCCESS) {
|
||||
@@ -156,10 +169,29 @@ private:
|
||||
config.middleScore, config.steepness, config.outputMin, config.outputMax);
|
||||
SIMILARITY_CONVERTER_SET_RECOMMENDED_COSINE_THRESHOLD(config.threshold);
|
||||
}
|
||||
// Load face detect model
|
||||
if (m_config_["face_detect_pixel_list"] && m_config_["face_detect_model_list"]) {
|
||||
auto node_face_detect_pixel_list = m_config_["face_detect_pixel_list"];
|
||||
for (std::size_t i = 0; i < node_face_detect_pixel_list.size(); ++i) {
|
||||
m_face_detect_pixel_list_.push_back(node_face_detect_pixel_list[i].as<int>());
|
||||
}
|
||||
auto node_face_detect_model_list = m_config_["face_detect_model_list"];
|
||||
for (std::size_t i = 0; i < node_face_detect_model_list.size(); ++i) {
|
||||
m_face_detect_model_list_.push_back(node_face_detect_model_list[i].as<std::string>());
|
||||
}
|
||||
if (m_face_detect_pixel_list_.size() != m_face_detect_model_list_.size()) {
|
||||
return FORMAT_ERROR;
|
||||
}
|
||||
} else {
|
||||
m_face_detect_pixel_list_ = {160, 320, 640};
|
||||
m_face_detect_model_list_ = {"face_detect_160", "face_detect_320", "face_detect_640"};
|
||||
}
|
||||
m_landmark_param_ = std::make_shared<LandmarkParam>(m_config_["landmark_table"]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::shared_ptr<CoreArchive> m_archive_;
|
||||
YAML::Node m_config_;
|
||||
@@ -172,6 +204,11 @@ private:
|
||||
std::string m_version_;
|
||||
std::string m_major_;
|
||||
std::string m_release_time_;
|
||||
|
||||
std::vector<int> m_face_detect_pixel_list_;
|
||||
std::vector<std::string> m_face_detect_model_list_;
|
||||
|
||||
std::shared_ptr<LandmarkParam> m_landmark_param_;
|
||||
};
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
111
cpp-package/inspireface/cpp/inspireface/middleware/timer.cpp
Normal file
111
cpp-package/inspireface/cpp/inspireface/middleware/timer.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
#include "spend_timer.h"
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include "log.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <chrono> // NOLINT
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
namespace inspire {
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
uint64_t INSPIRE_API_EXPORT _now() {
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
uint64_t INSPIRE_API_EXPORT _now() {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
return static_cast<uint64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
|
||||
}
|
||||
|
||||
#endif // defined(_MSC_VER)
|
||||
|
||||
int SpendTimer::is_enable = true;
|
||||
|
||||
SpendTimer::SpendTimer() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
SpendTimer::SpendTimer(const std::string &name) {
|
||||
name_ = name;
|
||||
Reset();
|
||||
}
|
||||
|
||||
void SpendTimer::Start() {
|
||||
start_ = _now();
|
||||
}
|
||||
|
||||
void SpendTimer::Stop() {
|
||||
stop_ = _now();
|
||||
uint64_t d = stop_ - start_;
|
||||
total_ += d;
|
||||
++count_;
|
||||
min_ = std::min(min_, d);
|
||||
max_ = std::max(max_, d);
|
||||
}
|
||||
|
||||
void SpendTimer::Reset() {
|
||||
start_ = 0;
|
||||
stop_ = 0;
|
||||
total_ = 0;
|
||||
count_ = 0;
|
||||
min_ = UINT64_MAX;
|
||||
max_ = 0;
|
||||
}
|
||||
|
||||
uint64_t SpendTimer::Get() const {
|
||||
return stop_ - start_;
|
||||
}
|
||||
|
||||
uint64_t SpendTimer::Average() const {
|
||||
return count_ == 0 ? 0 : total_ / count_;
|
||||
}
|
||||
|
||||
uint64_t SpendTimer::Total() const {
|
||||
return total_;
|
||||
}
|
||||
|
||||
uint64_t SpendTimer::Count() const {
|
||||
return count_;
|
||||
}
|
||||
|
||||
uint64_t SpendTimer::Min() const {
|
||||
return count_ == 0 ? 0 : min_;
|
||||
}
|
||||
|
||||
uint64_t SpendTimer::Max() const {
|
||||
return max_;
|
||||
}
|
||||
|
||||
const std::string &SpendTimer::name() const {
|
||||
return name_;
|
||||
}
|
||||
|
||||
std::string SpendTimer::Report() const {
|
||||
std::stringstream ss;
|
||||
if (is_enable) {
|
||||
ss << "[Time(us) Total:" << Total() << " Ave:" << Average() << " Min:" << Min() << " Max:" << Max() << " Count:" << Count() << " " << name_
|
||||
<< "]";
|
||||
} else {
|
||||
ss << "Timer Disabled.";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void SpendTimer::Disable() {
|
||||
is_enable = false;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const SpendTimer &timer) {
|
||||
os << timer.Report();
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace inspire
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
#include "log.h"
|
||||
#include "track_module/landmark/face_landmark_adapt.h"
|
||||
#include "track_module/landmark/landmark_param.h"
|
||||
#include "recognition_module/dest_const.h"
|
||||
#include "herror.h"
|
||||
#include "liveness/order_of_hyper_landmark.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
@@ -31,7 +31,7 @@ FacePipelineModule::FacePipelineModule(InspireArchive &archive, bool enableLiven
|
||||
INSPIRE_LOGE("InitAgePredict error.");
|
||||
}
|
||||
}
|
||||
|
||||
m_landmark_param_ = archive.GetLandmarkParam();
|
||||
// Initialize the mask detection model
|
||||
if (m_enable_mask_detect_) {
|
||||
InspireModel maskModel;
|
||||
@@ -73,9 +73,11 @@ FacePipelineModule::FacePipelineModule(InspireArchive &archive, bool enableLiven
|
||||
}
|
||||
}
|
||||
|
||||
int32_t FacePipelineModule::Process(inspirecv::InspireImageProcess &processor, const HyperFaceData &face, FaceProcessFunctionOption proc) {
|
||||
int32_t FacePipelineModule::Process(inspirecv::FrameProcess &processor, const FaceTrackWrap &face, FaceProcessFunctionOption proc) {
|
||||
// Original image
|
||||
inspirecv::Image originImage;
|
||||
inspirecv::Image scaleImage;
|
||||
std::vector<inspirecv::Point2f> stand_lmk;
|
||||
switch (proc) {
|
||||
case PROCESS_MASK: {
|
||||
if (m_mask_predict_ == nullptr) {
|
||||
@@ -97,8 +99,29 @@ int32_t FacePipelineModule::Process(inspirecv::InspireImageProcess &processor, c
|
||||
if (m_rgb_anti_spoofing_ == nullptr) {
|
||||
return HERR_SESS_PIPELINE_FAILURE; // uninitialized
|
||||
}
|
||||
// New scheme: padding differences cause errors in inference results
|
||||
// inspirecv::TransformMatrix rotation_mode_affine = processor.GetAffineMatrix();
|
||||
// if (stand_lmk.empty()) {
|
||||
// std::vector<inspirecv::Point2f> lmk;
|
||||
// for (const auto &p : face.densityLandmark) {
|
||||
// lmk.emplace_back(p.x, p.y);
|
||||
// }
|
||||
// stand_lmk = inspirecv::ApplyTransformToPoints(lmk, rotation_mode_affine.GetInverse());
|
||||
// }
|
||||
|
||||
// auto rect_face = inspirecv::MinBoundingRect(stand_lmk);
|
||||
// auto rect_pts = rect_face.Square(2.7f).As<float>().ToFourVertices();
|
||||
// std::vector<inspirecv::Point2f> dst_pts = {{0, 0}, {112, 0}, {112, 112}, {0, 112}};
|
||||
// std::vector<inspirecv::Point2f> camera_pts = inspirecv::ApplyTransformToPoints(rect_pts, rotation_mode_affine);
|
||||
|
||||
// auto affine = inspirecv::SimilarityTransformEstimate(camera_pts, dst_pts);
|
||||
// auto image_affine = processor.ExecuteImageAffineProcessing(affine, 112, 112);
|
||||
// image_affine.Write("liveness_affine.jpg");
|
||||
|
||||
if (originImage.Empty()) {
|
||||
// This is a poor approach that impacts performance,
|
||||
// but in order to capture clearer images and improve liveness detection accuracy,
|
||||
// we have to keep it.
|
||||
originImage = processor.ExecuteImageScaleProcessing(1.0, true);
|
||||
}
|
||||
inspirecv::Rect2i oriRect(face.rect.x, face.rect.y, face.rect.width, face.rect.height);
|
||||
@@ -106,6 +129,7 @@ int32_t FacePipelineModule::Process(inspirecv::InspireImageProcess &processor, c
|
||||
auto crop = originImage.Crop(rect);
|
||||
auto score = (*m_rgb_anti_spoofing_)(crop);
|
||||
// crop.Show();
|
||||
// crop.Resize(112, 112).Write("liveness.jpg");
|
||||
faceLivenessCache = score;
|
||||
break;
|
||||
}
|
||||
@@ -113,61 +137,37 @@ int32_t FacePipelineModule::Process(inspirecv::InspireImageProcess &processor, c
|
||||
if (m_blink_predict_ == nullptr) {
|
||||
return HERR_SESS_PIPELINE_FAILURE; // uninitialized
|
||||
}
|
||||
if (originImage.Empty()) {
|
||||
originImage = processor.ExecuteImageScaleProcessing(1.0, true);
|
||||
}
|
||||
std::vector<std::vector<int>> order_list = {HLMK_LEFT_EYE_POINTS_INDEX, HLMK_RIGHT_EYE_POINTS_INDEX};
|
||||
std::vector<std::vector<int>> order_list = {m_landmark_param_->semantic_index.left_eye_region, m_landmark_param_->semantic_index.right_eye_region};
|
||||
eyesStatusCache = {0, 0};
|
||||
inspirecv::Point2f left_eye = inspirecv::Point2f(face.keyPoints[0].x, face.keyPoints[0].y);
|
||||
inspirecv::Point2f right_eye = inspirecv::Point2f(face.keyPoints[1].x, face.keyPoints[1].y);
|
||||
std::vector<inspirecv::Point2f> eyes = {left_eye, right_eye};
|
||||
auto new_eyes_points = inspirecv::ApplyTransformToPoints(eyes, processor.GetAffineMatrix().GetInverse());
|
||||
// Get affine matrix
|
||||
inspirecv::TransformMatrix rotation_mode_affine = processor.GetAffineMatrix();
|
||||
// Get stand landmark
|
||||
if (stand_lmk.empty()) {
|
||||
std::vector<inspirecv::Point2f> lmk;
|
||||
for (const auto &p : face.densityLandmark) {
|
||||
lmk.emplace_back(p.x, p.y);
|
||||
}
|
||||
stand_lmk = inspirecv::ApplyTransformToPoints(lmk, rotation_mode_affine.GetInverse());
|
||||
}
|
||||
for (size_t i = 0; i < order_list.size(); i++) {
|
||||
const auto &index = order_list[i];
|
||||
std::vector<inspirecv::Point2i> points;
|
||||
for (const auto &idx : index) {
|
||||
points.emplace_back(face.densityLandmark[idx].x, face.densityLandmark[idx].y);
|
||||
points.emplace_back(stand_lmk[idx].GetX(), stand_lmk[idx].GetY());
|
||||
}
|
||||
auto rect = inspirecv::MinBoundingRect(points);
|
||||
auto mat = processor.GetAffineMatrix();
|
||||
auto new_rect = inspirecv::ApplyTransformToRect(rect, mat.GetInverse()).Square(1.3f);
|
||||
// Use more accurate 5 key point calibration
|
||||
auto cx = new_eyes_points[i].GetX();
|
||||
auto cy = new_eyes_points[i].GetY();
|
||||
new_rect.SetX(cx - new_rect.GetWidth() / 2);
|
||||
new_rect.SetY(cy - new_rect.GetHeight() / 2);
|
||||
auto rect_eye = inspirecv::MinBoundingRect(points).Square(1.5f);
|
||||
auto rect_pts_eye = rect_eye.As<float>().ToFourVertices();
|
||||
std::vector<inspirecv::Point2f> dst_pts_eye = {{0, 0}, {64, 0}, {64, 64}, {0, 64}};
|
||||
std::vector<inspirecv::Point2f> camera_pts_eye = inspirecv::ApplyTransformToPoints(rect_pts_eye, rotation_mode_affine);
|
||||
|
||||
// Ensure rect stays within image bounds while maintaining aspect ratio
|
||||
float originalAspectRatio = new_rect.GetWidth() / new_rect.GetHeight();
|
||||
|
||||
// Adjust position and size to fit within image bounds
|
||||
if (new_rect.GetX() < 0) {
|
||||
new_rect.SetWidth(new_rect.GetWidth() + new_rect.GetX()); // Reduce width by overflow amount
|
||||
new_rect.SetX(0);
|
||||
}
|
||||
if (new_rect.GetY() < 0) {
|
||||
new_rect.SetHeight(new_rect.GetHeight() + new_rect.GetY()); // Reduce height by overflow amount
|
||||
new_rect.SetY(0);
|
||||
}
|
||||
|
||||
float rightOverflow = (new_rect.GetX() + new_rect.GetWidth()) - originImage.Width();
|
||||
if (rightOverflow > 0) {
|
||||
new_rect.SetWidth(new_rect.GetWidth() - rightOverflow);
|
||||
}
|
||||
|
||||
float bottomOverflow = (new_rect.GetY() + new_rect.GetHeight()) - originImage.Height();
|
||||
if (bottomOverflow > 0) {
|
||||
new_rect.SetHeight(new_rect.GetHeight() - bottomOverflow);
|
||||
}
|
||||
|
||||
// Maintain minimum size (e.g., 20x20 ixels)
|
||||
const float minSize = 20.0f;
|
||||
if (new_rect.GetWidth() < minSize || new_rect.GetHeight() < minSize) {
|
||||
continue; // Skip this eye if the crop region is too small
|
||||
}
|
||||
|
||||
auto crop = originImage.Crop(new_rect);
|
||||
auto score = (*m_blink_predict_)(crop);
|
||||
auto affine_eye = inspirecv::SimilarityTransformEstimate(camera_pts_eye, dst_pts_eye);
|
||||
auto eye_affine = processor.ExecuteImageAffineProcessing(affine_eye, 64, 64);
|
||||
// eye_affine.Write("eye_"+std::to_string(i)+".jpg");
|
||||
// auto crop = originImage.Crop(new_rect);
|
||||
auto score = (*m_blink_predict_)(eye_affine);
|
||||
eyesStatusCache[i] = score;
|
||||
}
|
||||
break;
|
||||
@@ -190,12 +190,12 @@ int32_t FacePipelineModule::Process(inspirecv::InspireImageProcess &processor, c
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FacePipelineModule::Process(inspirecv::InspireImageProcess &processor, FaceObjectInternal &face) {
|
||||
int32_t FacePipelineModule::Process(inspirecv::FrameProcess &processor, FaceObjectInternal &face) {
|
||||
// In the tracking state, the count meets the requirements or the pipeline is executed in the detection state
|
||||
auto lmk = face.keyPointFive;
|
||||
std::vector<inspirecv::Point2f> lmk_5 = {lmk[FaceLandmarkAdapt::LEFT_EYE_CENTER], lmk[FaceLandmarkAdapt::RIGHT_EYE_CENTER],
|
||||
lmk[FaceLandmarkAdapt::NOSE_CORNER], lmk[FaceLandmarkAdapt::MOUTH_LEFT_CORNER],
|
||||
lmk[FaceLandmarkAdapt::MOUTH_RIGHT_CORNER]};
|
||||
std::vector<inspirecv::Point2f> lmk_5 = {lmk[m_landmark_param_->semantic_index.left_eye_center], lmk[m_landmark_param_->semantic_index.right_eye_center],
|
||||
lmk[m_landmark_param_->semantic_index.nose_corner], lmk[m_landmark_param_->semantic_index.mouth_left_corner],
|
||||
lmk[m_landmark_param_->semantic_index.mouth_right_corner]};
|
||||
auto trans = inspirecv::SimilarityTransformEstimateUmeyama(SIMILARITY_TRANSFORM_DEST, lmk_5);
|
||||
auto crop = processor.ExecuteImageAffineProcessing(trans, FACE_CROP_SIZE, FACE_CROP_SIZE);
|
||||
if (m_mask_predict_ != nullptr) {
|
||||
@@ -225,7 +225,7 @@ int32_t FacePipelineModule::Process(inspirecv::InspireImageProcess &processor, F
|
||||
|
||||
int32_t FacePipelineModule::InitFaceAttributePredict(InspireModel &model) {
|
||||
m_attribute_predict_ = std::make_shared<FaceAttributePredictAdapt>();
|
||||
auto ret = m_attribute_predict_->loadData(model, model.modelType);
|
||||
auto ret = m_attribute_predict_->LoadData(model, model.modelType);
|
||||
if (ret != InferenceWrapper::WrapperOk) {
|
||||
return HERR_ARCHIVE_LOAD_FAILURE;
|
||||
}
|
||||
@@ -234,7 +234,7 @@ int32_t FacePipelineModule::InitFaceAttributePredict(InspireModel &model) {
|
||||
|
||||
int32_t FacePipelineModule::InitMaskPredict(InspireModel &model) {
|
||||
m_mask_predict_ = std::make_shared<MaskPredictAdapt>();
|
||||
auto ret = m_mask_predict_->loadData(model, model.modelType);
|
||||
auto ret = m_mask_predict_->LoadData(model, model.modelType);
|
||||
if (ret != InferenceWrapper::WrapperOk) {
|
||||
return HERR_ARCHIVE_LOAD_FAILURE;
|
||||
}
|
||||
@@ -248,7 +248,7 @@ int32_t FacePipelineModule::InitRBGAntiSpoofing(InspireModel &model) {
|
||||
#else
|
||||
m_rgb_anti_spoofing_ = std::make_shared<RBGAntiSpoofingAdapt>(input_size[0]);
|
||||
#endif
|
||||
auto ret = m_rgb_anti_spoofing_->loadData(model, model.modelType);
|
||||
auto ret = m_rgb_anti_spoofing_->LoadData(model, model.modelType);
|
||||
if (ret != InferenceWrapper::WrapperOk) {
|
||||
return HERR_ARCHIVE_LOAD_FAILURE;
|
||||
}
|
||||
@@ -257,7 +257,7 @@ int32_t FacePipelineModule::InitRBGAntiSpoofing(InspireModel &model) {
|
||||
|
||||
int32_t FacePipelineModule::InitBlinkFromLivenessInteraction(InspireModel &model) {
|
||||
m_blink_predict_ = std::make_shared<BlinkPredictAdapt>();
|
||||
auto ret = m_blink_predict_->loadData(model, model.modelType);
|
||||
auto ret = m_blink_predict_->LoadData(model, model.modelType);
|
||||
if (ret != InferenceWrapper::WrapperOk) {
|
||||
return HERR_ARCHIVE_LOAD_FAILURE;
|
||||
}
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
#ifndef INSPIRE_FACE_PIPELINE_MODULE_H
|
||||
#define INSPIRE_FACE_PIPELINE_MODULE_H
|
||||
|
||||
#include "middleware/inspirecv_image_process.h"
|
||||
#include "frame_process.h"
|
||||
#include "common/face_info/face_object_internal.h"
|
||||
#include "attribute/face_attribute_adapt.h"
|
||||
#include "attribute/mask_predict_adapt.h"
|
||||
#include "liveness/rgb_anti_spoofing_adapt.h"
|
||||
#include "liveness/blink_predict_adapt.h"
|
||||
#include "middleware/model_archive/inspire_archive.h"
|
||||
#include "common/face_data/face_data_type.h"
|
||||
|
||||
#include "face_warpper.h"
|
||||
#include "track_module/landmark/landmark_param.h"
|
||||
namespace inspire {
|
||||
|
||||
/**
|
||||
@@ -56,17 +56,17 @@ public:
|
||||
* @param face FaceObject representing the detected face.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t Process(inspirecv::InspireImageProcess &processor, FaceObjectInternal &face);
|
||||
int32_t Process(inspirecv::FrameProcess &processor, FaceObjectInternal &face);
|
||||
|
||||
/**
|
||||
* @brief Processes a face using the specified FaceProcessFunction.
|
||||
*
|
||||
* @param image CameraStream instance containing the image.
|
||||
* @param face HyperFaceData representing the detected face.
|
||||
* @param face FaceTrackWrap representing the detected face.
|
||||
* @param proc The FaceProcessFunction to apply to the face.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t Process(inspirecv::InspireImageProcess &processor, const HyperFaceData &face, FaceProcessFunctionOption proc);
|
||||
int32_t Process(inspirecv::FrameProcess &processor, const FaceTrackWrap &face, FaceProcessFunctionOption proc);
|
||||
|
||||
/**
|
||||
* @brief Get Rgb AntiSpoofing module
|
||||
@@ -125,6 +125,7 @@ private:
|
||||
std::shared_ptr<MaskPredictAdapt> m_mask_predict_; ///< Pointer to MaskPredict instance.
|
||||
std::shared_ptr<RBGAntiSpoofingAdapt> m_rgb_anti_spoofing_; ///< Pointer to RBGAntiSpoofing instance.
|
||||
std::shared_ptr<BlinkPredictAdapt> m_blink_predict_; ///< Pointer to Blink predict instance.
|
||||
std::shared_ptr<LandmarkParam> m_landmark_param_; ///< Pointer to LandmarkParam instance.
|
||||
|
||||
public:
|
||||
float faceMaskCache; ///< Cache for face mask detection result.
|
||||
|
||||
@@ -96,6 +96,7 @@ JNIEXPORT jobject INSPIRE_FACE_JNI(InspireFace_CreateSession)(JNIEnv *env, jobje
|
||||
jfieldID enableFaceQualityField = env->GetFieldID(customParamClass, "enableFaceQuality", "I");
|
||||
jfieldID enableFaceAttributeField = env->GetFieldID(customParamClass, "enableFaceAttribute", "I");
|
||||
jfieldID enableInteractionLivenessField = env->GetFieldID(customParamClass, "enableInteractionLiveness", "I");
|
||||
jfieldID enableFacePoseField = env->GetFieldID(customParamClass, "enableFacePose", "I");
|
||||
|
||||
// Create HFSessionCustomParameter struct
|
||||
HFSessionCustomParameter parameter;
|
||||
@@ -106,6 +107,7 @@ JNIEXPORT jobject INSPIRE_FACE_JNI(InspireFace_CreateSession)(JNIEnv *env, jobje
|
||||
parameter.enable_face_quality = env->GetIntField(customParameter, enableFaceQualityField);
|
||||
parameter.enable_face_attribute = env->GetIntField(customParameter, enableFaceAttributeField);
|
||||
parameter.enable_interaction_liveness = env->GetIntField(customParameter, enableInteractionLivenessField);
|
||||
parameter.enable_face_pose = env->GetIntField(customParameter, enableFacePoseField);
|
||||
|
||||
// Create session
|
||||
HFSession handle;
|
||||
@@ -164,6 +166,7 @@ JNIEXPORT jobject INSPIRE_FACE_JNI(InspireFace_CreateImageStreamFromBitmap)(JNIE
|
||||
return nullptr;
|
||||
}
|
||||
if (AndroidBitmap_lockPixels(env, bitmap, &pixels) < 0) {
|
||||
AndroidBitmap_unlockPixels(env, bitmap);
|
||||
INSPIRE_LOGE("Failed to lock pixels");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -236,6 +239,7 @@ JNIEXPORT jobject INSPIRE_FACE_JNI(InspireFace_CreateImageStreamFromByteBuffer)(
|
||||
jfieldID streamHandleField = env->GetFieldID(streamClass, "handle", "J");
|
||||
jobject imageStreamObj = env->NewObject(streamClass, constructor);
|
||||
env->SetLongField(imageStreamObj, streamHandleField, (jlong)streamHandle);
|
||||
env->ReleaseByteArrayElements(data, (jbyte *)buf, JNI_ABORT);
|
||||
|
||||
return imageStreamObj;
|
||||
}
|
||||
@@ -365,6 +369,9 @@ JNIEXPORT jobject INSPIRE_FACE_JNI(InspireFace_ExecuteFaceTrack)(JNIEnv *env, jo
|
||||
env->SetLongField(token, tokenHandleField, (jlong)results.tokens[i].data);
|
||||
env->SetIntField(token, sizeField, results.tokens[i].size);
|
||||
env->SetObjectArrayElement(tokenArray, i, token);
|
||||
env->DeleteLocalRef(rect);
|
||||
env->DeleteLocalRef(angle);
|
||||
env->DeleteLocalRef(token);
|
||||
}
|
||||
|
||||
// Set arrays to MultipleFaceData
|
||||
@@ -1311,7 +1318,7 @@ JNIEXPORT jboolean INSPIRE_FACE_JNI(InspireFace_MultipleFacePipelineProcess)(JNI
|
||||
jfieldID enableFaceQualityField = env->GetFieldID(paramClass, "enableFaceQuality", "I");
|
||||
jfieldID enableFaceAttributeField = env->GetFieldID(paramClass, "enableFaceAttribute", "I");
|
||||
jfieldID enableInteractionLivenessField = env->GetFieldID(paramClass, "enableInteractionLiveness", "I");
|
||||
jfieldID enableDetectModeLandmarkField = env->GetFieldID(paramClass, "enableDetectModeLandmark", "I");
|
||||
jfieldID enableFacePoseField = env->GetFieldID(paramClass, "enableFacePose", "I");
|
||||
// Get parameter values
|
||||
HFSessionCustomParameter customParam;
|
||||
customParam.enable_recognition = env->GetIntField(parameter, enableRecognitionField);
|
||||
@@ -1321,7 +1328,7 @@ JNIEXPORT jboolean INSPIRE_FACE_JNI(InspireFace_MultipleFacePipelineProcess)(JNI
|
||||
customParam.enable_face_quality = env->GetIntField(parameter, enableFaceQualityField);
|
||||
customParam.enable_face_attribute = env->GetIntField(parameter, enableFaceAttributeField);
|
||||
customParam.enable_interaction_liveness = env->GetIntField(parameter, enableInteractionLivenessField);
|
||||
customParam.enable_detect_mode_landmark = env->GetIntField(parameter, enableDetectModeLandmarkField);
|
||||
customParam.enable_face_pose = env->GetIntField(parameter, enableFacePoseField);
|
||||
// Call native function
|
||||
HResult ret = HFMultipleFacePipelineProcess((HFSession)sessionHandle, (HFImageStream)streamHandleValue, &faceData, customParam);
|
||||
|
||||
@@ -1645,6 +1652,12 @@ JNIEXPORT jobject INSPIRE_FACE_JNI(InspireFace_GetFaceAttributeResult)(JNIEnv *e
|
||||
|
||||
if (!raceArray || !genderArray || !ageBracketArray) {
|
||||
INSPIRE_LOGE("Failed to create arrays");
|
||||
if (raceArray)
|
||||
env->DeleteLocalRef(raceArray);
|
||||
if (genderArray)
|
||||
env->DeleteLocalRef(genderArray);
|
||||
if (ageBracketArray)
|
||||
env->DeleteLocalRef(ageBracketArray);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -1656,6 +1669,10 @@ JNIEXPORT jobject INSPIRE_FACE_JNI(InspireFace_GetFaceAttributeResult)(JNIEnv *e
|
||||
env->SetObjectField(attributeObj, genderField, genderArray);
|
||||
env->SetObjectField(attributeObj, ageBracketField, ageBracketArray);
|
||||
|
||||
env->DeleteLocalRef(raceArray);
|
||||
env->DeleteLocalRef(genderArray);
|
||||
env->DeleteLocalRef(ageBracketArray);
|
||||
|
||||
return attributeObj;
|
||||
}
|
||||
|
||||
@@ -1689,9 +1706,8 @@ JNIEXPORT jobject INSPIRE_FACE_JNI(InspireFace_QueryInspireFaceVersion)(JNIEnv *
|
||||
jfieldID majorField = env->GetFieldID(versionClass, "major", "I");
|
||||
jfieldID minorField = env->GetFieldID(versionClass, "minor", "I");
|
||||
jfieldID patchField = env->GetFieldID(versionClass, "patch", "I");
|
||||
jfieldID infoField = env->GetFieldID(versionClass, "information", "Ljava/lang/String;");
|
||||
|
||||
if (!majorField || !minorField || !patchField || !infoField) {
|
||||
if (!majorField || !minorField || !patchField) {
|
||||
INSPIRE_LOGE("Failed to get InspireFaceVersion field IDs");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1701,32 +1717,6 @@ JNIEXPORT jobject INSPIRE_FACE_JNI(InspireFace_QueryInspireFaceVersion)(JNIEnv *
|
||||
env->SetIntField(version, minorField, versionInfo.minor);
|
||||
env->SetIntField(version, patchField, versionInfo.patch);
|
||||
|
||||
// Get extended information
|
||||
HFInspireFaceExtendedInformation extendedInfo;
|
||||
HFQueryInspireFaceExtendedInformation(&extendedInfo);
|
||||
|
||||
// Sanitize the information string to ensure valid UTF-8
|
||||
std::string sanitizedInfo;
|
||||
const char *rawInfo = extendedInfo.information;
|
||||
while (*rawInfo) {
|
||||
unsigned char c = static_cast<unsigned char>(*rawInfo);
|
||||
if (c < 0x80 || (c >= 0xC0 && c <= 0xF4)) {
|
||||
// Valid UTF-8 start byte
|
||||
sanitizedInfo += *rawInfo;
|
||||
}
|
||||
rawInfo++;
|
||||
}
|
||||
|
||||
// Convert sanitized string to Java string
|
||||
jstring infoString = env->NewStringUTF(sanitizedInfo.c_str());
|
||||
if (infoString) {
|
||||
env->SetObjectField(version, infoField, infoString);
|
||||
} else {
|
||||
// Fallback to a safe string if conversion fails
|
||||
jstring fallbackString = env->NewStringUTF("Version information unavailable");
|
||||
env->SetObjectField(version, infoField, fallbackString);
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,13 +23,14 @@ FeatureExtractionModule::FeatureExtractionModule(InspireArchive &archive, bool e
|
||||
INSPIRE_LOGE("FaceRecognition error.");
|
||||
}
|
||||
}
|
||||
m_landmark_param_ = archive.GetLandmarkParam();
|
||||
}
|
||||
|
||||
int32_t FeatureExtractionModule::InitExtractInteraction(InspireModel &model) {
|
||||
try {
|
||||
auto input_size = model.Config().get<std::vector<int>>("input_size");
|
||||
m_extract_ = std::make_shared<ExtractAdapt>();
|
||||
auto ret = m_extract_->loadData(model, model.modelType);
|
||||
auto ret = m_extract_->LoadData(model, model.modelType);
|
||||
if (ret != InferenceWrapper::WrapperOk) {
|
||||
return HERR_ARCHIVE_LOAD_FAILURE;
|
||||
}
|
||||
@@ -45,7 +46,7 @@ int32_t FeatureExtractionModule::QueryStatus() const {
|
||||
return m_status_code_;
|
||||
}
|
||||
|
||||
int32_t FeatureExtractionModule::FaceExtract(inspirecv::InspireImageProcess &processor, const HyperFaceData &face, Embedded &embedded, float &norm,
|
||||
int32_t FeatureExtractionModule::FaceExtract(inspirecv::FrameProcess &processor, const FaceTrackWrap &face, Embedded &embedded, float &norm,
|
||||
bool normalize) {
|
||||
if (m_extract_ == nullptr) {
|
||||
return HERR_SESS_REC_EXTRACT_FAILURE;
|
||||
@@ -64,16 +65,37 @@ int32_t FeatureExtractionModule::FaceExtract(inspirecv::InspireImageProcess &pro
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t FeatureExtractionModule::FaceExtract(inspirecv::InspireImageProcess &processor, const FaceObjectInternal &face, Embedded &embedded,
|
||||
float &norm, bool normalize) {
|
||||
int32_t FeatureExtractionModule::FaceExtractWithAlignmentImage(inspirecv::FrameProcess &processor, Embedded &embedded, float &norm,
|
||||
bool normalize) {
|
||||
if (m_extract_ == nullptr) {
|
||||
return HERR_SESS_REC_EXTRACT_FAILURE;
|
||||
}
|
||||
auto crop = processor.ExecuteImageScaleProcessing(1.0f, false);
|
||||
embedded = (*m_extract_)(crop, norm, normalize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t FeatureExtractionModule::FaceExtractWithAlignmentImage(const inspirecv::Image& wrapped, Embedded &embedded, float &norm,
|
||||
bool normalize) {
|
||||
if (m_extract_ == nullptr) {
|
||||
return HERR_SESS_REC_EXTRACT_FAILURE;
|
||||
}
|
||||
embedded = (*m_extract_)(wrapped, norm, normalize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t FeatureExtractionModule::FaceExtract(inspirecv::FrameProcess &processor, const FaceObjectInternal &face, Embedded &embedded, float &norm,
|
||||
bool normalize) {
|
||||
if (m_extract_ == nullptr) {
|
||||
return HERR_SESS_REC_EXTRACT_FAILURE;
|
||||
}
|
||||
|
||||
auto lmk = face.landmark_;
|
||||
std::vector<inspirecv::Point2f> lmk_5 = {lmk[FaceLandmarkAdapt::LEFT_EYE_CENTER], lmk[FaceLandmarkAdapt::RIGHT_EYE_CENTER],
|
||||
lmk[FaceLandmarkAdapt::NOSE_CORNER], lmk[FaceLandmarkAdapt::MOUTH_LEFT_CORNER],
|
||||
lmk[FaceLandmarkAdapt::MOUTH_RIGHT_CORNER]};
|
||||
std::vector<inspirecv::Point2f> lmk_5 = {lmk[m_landmark_param_->semantic_index.left_eye_center], lmk[m_landmark_param_->semantic_index.right_eye_center],
|
||||
lmk[m_landmark_param_->semantic_index.nose_corner], lmk[m_landmark_param_->semantic_index.mouth_left_corner],
|
||||
lmk[m_landmark_param_->semantic_index.mouth_right_corner]};
|
||||
|
||||
auto trans = inspirecv::SimilarityTransformEstimateUmeyama(SIMILARITY_TRANSFORM_DEST, lmk_5);
|
||||
auto crop = processor.ExecuteImageAffineProcessing(trans, FACE_CROP_SIZE, FACE_CROP_SIZE);
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
#include <mutex>
|
||||
#include "extract/extract_adapt.h"
|
||||
#include "common/face_info/face_object_internal.h"
|
||||
#include "common/face_data/face_data_type.h"
|
||||
#include "face_warpper.h"
|
||||
#include "middleware/model_archive/inspire_archive.h"
|
||||
#include "middleware/inspirecv_image_process.h"
|
||||
#include "frame_process.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
@@ -35,23 +35,40 @@ public:
|
||||
/**
|
||||
* @brief Extracts a facial feature from an image and stores it in the provided 'embedded'.
|
||||
*
|
||||
* @param processor inspirecv::InspireImageProcess instance containing the image.
|
||||
* @param processor inspirecv::FrameProcess instance containing the image.
|
||||
* @param face FaceObject representing the detected face.
|
||||
* @param embedded Output parameter to store the extracted facial feature.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t FaceExtract(inspirecv::InspireImageProcess &processor, const FaceObjectInternal &face, Embedded &embedded, float &norm,
|
||||
bool normalize = false);
|
||||
int32_t FaceExtract(inspirecv::FrameProcess &processor, const FaceObjectInternal &face, Embedded &embedded, float &norm, bool normalize = false);
|
||||
|
||||
/**
|
||||
* @brief Extracts a facial feature from an image and stores it in the provided 'embedded'.
|
||||
*
|
||||
* @param processor inspirecv::InspireImageProcess instance containing the image.
|
||||
* @param face HyperFaceData representing the detected face.
|
||||
* @param processor inspirecv::FrameProcess instance containing the image.
|
||||
* @param face FaceTrackWrap representing the detected face.
|
||||
* @param embedded Output parameter to store the extracted facial feature.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t FaceExtract(inspirecv::InspireImageProcess &processor, const HyperFaceData &face, Embedded &embedded, float &norm, bool normalize = true);
|
||||
int32_t FaceExtract(inspirecv::FrameProcess &processor, const FaceTrackWrap &face, Embedded &embedded, float &norm, bool normalize = true);
|
||||
|
||||
/**
|
||||
* @brief Extracts a facial feature from an image and stores it in the provided 'embedded'.
|
||||
*
|
||||
* @param processor inspirecv::FrameProcess instance containing the image.
|
||||
* @param embedded Output parameter to store the extracted facial feature.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t FaceExtractWithAlignmentImage(inspirecv::FrameProcess &processor, Embedded &embedding, float &norm, bool normalize = true);
|
||||
|
||||
/**
|
||||
* @brief Extracts a facial feature from an image and stores it in the provided 'embedding'.
|
||||
*
|
||||
* @param wrapped inspirecv::Image instance containing the image.
|
||||
* @param embedding Output parameter to store the extracted facial feature.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t FaceExtractWithAlignmentImage(const inspirecv::Image& wrapped, Embedded &embedding, float &norm, bool normalize = true);
|
||||
|
||||
/**
|
||||
* @brief Gets the Extract instance associated with this FaceRecognition.
|
||||
@@ -71,6 +88,7 @@ private:
|
||||
|
||||
private:
|
||||
std::shared_ptr<ExtractAdapt> m_extract_; ///< Pointer to the Extract instance.
|
||||
std::shared_ptr<LandmarkParam> m_landmark_param_; ///< Pointer to the LandmarkParam instance.
|
||||
|
||||
int32_t m_status_code_; ///< Status code
|
||||
};
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
/**
|
||||
* Created by Jingyu Yan
|
||||
* @date 2024-10-01
|
||||
*/
|
||||
|
||||
#include "launch.h"
|
||||
#include "log.h"
|
||||
#include "herror.h"
|
||||
#include "isf_check.h"
|
||||
|
||||
// Include the implementation details here, hidden from public header
|
||||
#include "middleware/model_archive/inspire_archive.h"
|
||||
#if defined(ISF_ENABLE_RGA)
|
||||
#include "image_process/nexus_processor/rga/dma_alloc.h"
|
||||
#endif
|
||||
#include <mutex>
|
||||
#include "middleware/inference_wrapper/inference_wrapper.h"
|
||||
#include "middleware/system.h"
|
||||
#if defined(ISF_ENABLE_TENSORRT)
|
||||
#include "cuda_toolkit.h"
|
||||
#endif
|
||||
|
||||
#define APPLE_EXTENSION_SUFFIX ".bundle"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
// Implementation class definition
|
||||
class Launch::Impl {
|
||||
public:
|
||||
Impl() : m_load_(false), m_archive_(nullptr), m_cuda_device_id_(0), m_global_coreml_inference_mode_(InferenceWrapper::COREML_ANE) {
|
||||
#if defined(ISF_ENABLE_RGA)
|
||||
#if defined(ISF_RKNPU_RV1106)
|
||||
m_rockchip_dma_heap_path_ = RV1106_CMA_HEAP_PATH;
|
||||
#else
|
||||
m_rockchip_dma_heap_path_ = DMA_HEAP_DMA32_UNCACHE_PATCH;
|
||||
#endif
|
||||
INSPIRE_LOGW("Rockchip dma heap configured path: %s", m_rockchip_dma_heap_path_.c_str());
|
||||
#endif
|
||||
m_face_detect_pixel_list_ = {160, 320, 640};
|
||||
m_face_detect_model_list_ = {"face_detect_160", "face_detect_320", "face_detect_640"};
|
||||
}
|
||||
// Face Detection pixel size
|
||||
std::vector<int32_t> m_face_detect_pixel_list_;
|
||||
|
||||
// Face Detection model list
|
||||
std::vector<std::string> m_face_detect_model_list_;
|
||||
|
||||
// Static members
|
||||
static std::mutex mutex_;
|
||||
static std::shared_ptr<Launch> instance_;
|
||||
|
||||
// Data members
|
||||
std::string m_rockchip_dma_heap_path_;
|
||||
std::string m_extension_path_;
|
||||
std::unique_ptr<InspireArchive> m_archive_;
|
||||
bool m_load_;
|
||||
int32_t m_cuda_device_id_;
|
||||
InferenceWrapper::SpecialBackend m_global_coreml_inference_mode_;
|
||||
};
|
||||
|
||||
// Initialize static members
|
||||
std::mutex Launch::Impl::mutex_;
|
||||
std::shared_ptr<Launch> Launch::Impl::instance_ = nullptr;
|
||||
|
||||
// Constructor implementation
|
||||
Launch::Launch() : pImpl(std::make_unique<Impl>()) {}
|
||||
|
||||
// Destructor implementation
|
||||
Launch::~Launch() = default;
|
||||
|
||||
std::shared_ptr<Launch> Launch::GetInstance() {
|
||||
std::lock_guard<std::mutex> lock(Impl::mutex_);
|
||||
if (!Impl::instance_) {
|
||||
Impl::instance_ = std::shared_ptr<Launch>(new Launch());
|
||||
}
|
||||
return Impl::instance_;
|
||||
}
|
||||
|
||||
InspireArchive& Launch::getMArchive() {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mutex_);
|
||||
if (!pImpl->m_archive_) {
|
||||
throw std::runtime_error("Archive not initialized");
|
||||
}
|
||||
return *(pImpl->m_archive_);
|
||||
}
|
||||
|
||||
int32_t Launch::Load(const std::string& path) {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mutex_);
|
||||
#if defined(ISF_ENABLE_TENSORRT)
|
||||
int32_t support_cuda;
|
||||
auto ret = CheckCudaUsability(&support_cuda);
|
||||
if (ret != HSUCCEED) {
|
||||
INSPIRE_LOGE("An error occurred while checking CUDA device support. Please ensure that your environment supports CUDA!");
|
||||
return ret;
|
||||
}
|
||||
if (!support_cuda) {
|
||||
INSPIRE_LOGE("Your environment does not support CUDA! Please ensure that your environment supports CUDA!");
|
||||
return HERR_DEVICE_CUDA_NOT_SUPPORT;
|
||||
}
|
||||
#endif
|
||||
INSPIREFACE_CHECK_MSG(os::IsExists(path), "The package path does not exist because the launch failed.");
|
||||
#if defined(ISF_ENABLE_APPLE_EXTENSION)
|
||||
BuildAppleExtensionPath(path);
|
||||
#endif
|
||||
if (!pImpl->m_load_) {
|
||||
try {
|
||||
pImpl->m_archive_ = std::make_unique<InspireArchive>();
|
||||
pImpl->m_archive_->ReLoad(path);
|
||||
|
||||
// Update face detect pixel list and model list
|
||||
pImpl->m_face_detect_pixel_list_ = pImpl->m_archive_->GetFaceDetectPixelList();
|
||||
pImpl->m_face_detect_model_list_ = pImpl->m_archive_->GetFaceDetectModelList();
|
||||
|
||||
if (pImpl->m_archive_->QueryStatus() == SARC_SUCCESS) {
|
||||
pImpl->m_load_ = true;
|
||||
INSPIRE_LOGI("Successfully loaded resources");
|
||||
return HSUCCEED;
|
||||
} else {
|
||||
pImpl->m_archive_.reset();
|
||||
INSPIRE_LOGE("Failed to load resources");
|
||||
return HERR_ARCHIVE_LOAD_MODEL_FAILURE;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
pImpl->m_archive_.reset();
|
||||
INSPIRE_LOGE("Exception during resource loading: %s", e.what());
|
||||
return HERR_ARCHIVE_LOAD_MODEL_FAILURE;
|
||||
}
|
||||
} else {
|
||||
INSPIRE_LOGW("There is no need to call launch more than once, as subsequent calls will not affect the initialization.");
|
||||
return HSUCCEED;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t Launch::Reload(const std::string& path) {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mutex_);
|
||||
INSPIREFACE_CHECK_MSG(os::IsExists(path), "The package path does not exist because the launch failed.");
|
||||
#if defined(ISF_ENABLE_APPLE_EXTENSION)
|
||||
BuildAppleExtensionPath(path);
|
||||
#endif
|
||||
try {
|
||||
// Clean up existing archive if it exists
|
||||
if (pImpl->m_archive_) {
|
||||
pImpl->m_archive_.reset();
|
||||
pImpl->m_load_ = false;
|
||||
}
|
||||
|
||||
// Create and load new archive
|
||||
pImpl->m_archive_ = std::make_unique<InspireArchive>();
|
||||
pImpl->m_archive_->ReLoad(path);
|
||||
|
||||
if (pImpl->m_archive_->QueryStatus() == SARC_SUCCESS) {
|
||||
pImpl->m_load_ = true;
|
||||
INSPIRE_LOGI("Successfully reloaded resources");
|
||||
return HSUCCEED;
|
||||
} else {
|
||||
pImpl->m_archive_.reset();
|
||||
INSPIRE_LOGE("Failed to reload resources");
|
||||
return HERR_ARCHIVE_LOAD_MODEL_FAILURE;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
pImpl->m_archive_.reset();
|
||||
INSPIRE_LOGE("Exception during resource reloading: %s", e.what());
|
||||
return HERR_ARCHIVE_LOAD_MODEL_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
bool Launch::isMLoad() const {
|
||||
return pImpl->m_load_;
|
||||
}
|
||||
|
||||
void Launch::Unload() {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mutex_);
|
||||
if (pImpl->m_load_) {
|
||||
pImpl->m_archive_.reset();
|
||||
pImpl->m_load_ = false;
|
||||
INSPIRE_LOGI("All resources have been successfully unloaded and system is reset.");
|
||||
} else {
|
||||
INSPIRE_LOGW("Unload called but system was not loaded.");
|
||||
}
|
||||
}
|
||||
|
||||
void Launch::SetRockchipDmaHeapPath(const std::string& path) {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mutex_);
|
||||
pImpl->m_rockchip_dma_heap_path_ = path;
|
||||
}
|
||||
|
||||
std::string Launch::GetRockchipDmaHeapPath() const {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mutex_);
|
||||
return pImpl->m_rockchip_dma_heap_path_;
|
||||
}
|
||||
|
||||
void Launch::ConfigurationExtensionPath(const std::string& path) {
|
||||
#if defined(ISF_ENABLE_APPLE_EXTENSION)
|
||||
INSPIREFACE_CHECK_MSG(os::IsDir(path), "The apple extension path is not a directory, please check.");
|
||||
#endif
|
||||
INSPIREFACE_CHECK_MSG(os::IsExists(path), "The extension path is not exists, please check.");
|
||||
pImpl->m_extension_path_ = path;
|
||||
}
|
||||
|
||||
std::string Launch::GetExtensionPath() const {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mutex_);
|
||||
return pImpl->m_extension_path_;
|
||||
}
|
||||
|
||||
void Launch::SetGlobalCoreMLInferenceMode(NNInferenceBackend mode) {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mutex_);
|
||||
if (mode == NN_INFERENCE_CPU) {
|
||||
pImpl->m_global_coreml_inference_mode_ = InferenceWrapper::COREML_CPU;
|
||||
} else if (mode == NN_INFERENCE_COREML_GPU) {
|
||||
pImpl->m_global_coreml_inference_mode_ = InferenceWrapper::COREML_GPU;
|
||||
} else if (mode == NN_INFERENCE_COREML_ANE) {
|
||||
pImpl->m_global_coreml_inference_mode_ = InferenceWrapper::COREML_ANE;
|
||||
} else {
|
||||
INSPIRE_LOGE("Invalid CoreML inference mode");
|
||||
}
|
||||
if (pImpl->m_global_coreml_inference_mode_ == InferenceWrapper::COREML_CPU) {
|
||||
INSPIRE_LOGW("Global CoreML Compute Units set to CPU Only.");
|
||||
} else if (pImpl->m_global_coreml_inference_mode_ == InferenceWrapper::COREML_GPU) {
|
||||
INSPIRE_LOGW("Global CoreML Compute Units set to CPU and GPU.");
|
||||
} else if (pImpl->m_global_coreml_inference_mode_ == InferenceWrapper::COREML_ANE) {
|
||||
INSPIRE_LOGW("Global CoreML Compute Units set to Auto Switch (ANE, GPU, CPU).");
|
||||
}
|
||||
}
|
||||
|
||||
Launch::NNInferenceBackend Launch::GetGlobalCoreMLInferenceMode() const {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mutex_);
|
||||
if (pImpl->m_global_coreml_inference_mode_ == InferenceWrapper::COREML_CPU) {
|
||||
return NN_INFERENCE_CPU;
|
||||
} else if (pImpl->m_global_coreml_inference_mode_ == InferenceWrapper::COREML_GPU) {
|
||||
return NN_INFERENCE_COREML_GPU;
|
||||
} else if (pImpl->m_global_coreml_inference_mode_ == InferenceWrapper::COREML_ANE) {
|
||||
return NN_INFERENCE_COREML_ANE;
|
||||
} else {
|
||||
INSPIRE_LOGE("Invalid CoreML inference mode");
|
||||
return NN_INFERENCE_CPU;
|
||||
}
|
||||
}
|
||||
|
||||
void Launch::BuildAppleExtensionPath(const std::string& resource_path) {
|
||||
std::string basename = os::Basename(resource_path);
|
||||
pImpl->m_extension_path_ = os::PathJoin(os::Dirname(resource_path), basename + APPLE_EXTENSION_SUFFIX);
|
||||
INSPIREFACE_CHECK_MSG(os::IsExists(pImpl->m_extension_path_), "The apple extension path is not exists, please check.");
|
||||
INSPIREFACE_CHECK_MSG(os::IsDir(pImpl->m_extension_path_), "The apple extension path is not a directory, please check.");
|
||||
}
|
||||
|
||||
void Launch::SetCudaDeviceId(int32_t device_id) {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mutex_);
|
||||
pImpl->m_cuda_device_id_ = device_id;
|
||||
}
|
||||
|
||||
int32_t Launch::GetCudaDeviceId() const {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mutex_);
|
||||
return pImpl->m_cuda_device_id_;
|
||||
}
|
||||
|
||||
void Launch::SetFaceDetectPixelList(const std::vector<int32_t>& pixel_list) {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mutex_);
|
||||
pImpl->m_face_detect_pixel_list_ = pixel_list;
|
||||
}
|
||||
|
||||
std::vector<int32_t> Launch::GetFaceDetectPixelList() const {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mutex_);
|
||||
return pImpl->m_face_detect_pixel_list_;
|
||||
}
|
||||
|
||||
void Launch::SetFaceDetectModelList(const std::vector<std::string>& model_list) {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mutex_);
|
||||
pImpl->m_face_detect_model_list_ = model_list;
|
||||
}
|
||||
|
||||
std::vector<std::string> Launch::GetFaceDetectModelList() const {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mutex_);
|
||||
return pImpl->m_face_detect_model_list_;
|
||||
}
|
||||
|
||||
void Launch::SwitchLandmarkEngine(LandmarkEngine engine) {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mutex_);
|
||||
if (pImpl->m_archive_->QueryStatus() != SARC_SUCCESS) {
|
||||
INSPIRE_LOGE("The InspireFace is not initialized, please call launch first.");
|
||||
return;
|
||||
}
|
||||
auto landmark_param = pImpl->m_archive_->GetLandmarkParam();
|
||||
bool ret = false;
|
||||
if (engine == LANDMARK_HYPLMV2_0_25) {
|
||||
ret = landmark_param->ReLoad("landmark");
|
||||
} else if (engine == LANDMARK_HYPLMV2_0_50) {
|
||||
ret = landmark_param->ReLoad("landmark_0_50");
|
||||
} else if (engine == LANDMARK_INSIGHTFACE_2D106_TRACK) {
|
||||
ret = landmark_param->ReLoad("landmark_insightface_2d106");
|
||||
}
|
||||
INSPIREFACE_CHECK_MSG(ret, "Failed to switch landmark engine");
|
||||
}
|
||||
|
||||
} // namespace inspire
|
||||
@@ -35,6 +35,7 @@ private:
|
||||
std::unordered_map<long, bool> sessionMap;
|
||||
std::unordered_map<long, bool> streamMap;
|
||||
std::unordered_map<long, bool> imageBitmapMap;
|
||||
std::unordered_map<long, bool> faceFeatureMap;
|
||||
|
||||
// The private constructor guarantees singletons
|
||||
ResourceManager() {}
|
||||
@@ -106,6 +107,23 @@ public:
|
||||
return false; // Release failed, possibly because the handle could not be found or was released
|
||||
}
|
||||
|
||||
// Create and record face features
|
||||
void createFaceFeature(long handle) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
faceFeatureMap[handle] = false; // false indicates that it is not released
|
||||
}
|
||||
|
||||
// Release face feature
|
||||
bool releaseFaceFeature(long handle) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
auto it = faceFeatureMap.find(handle);
|
||||
if (it != faceFeatureMap.end() && !it->second) {
|
||||
it->second = true; // Mark as released
|
||||
return true;
|
||||
}
|
||||
return false; // Release failed, possibly because the handle could not be found or was released
|
||||
}
|
||||
|
||||
// Gets a list of unreleased session handles
|
||||
std::vector<long> getUnreleasedSessions() {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
@@ -142,10 +160,24 @@ public:
|
||||
return unreleasedImageBitmaps;
|
||||
}
|
||||
|
||||
// Gets a list of unreleased face feature handles
|
||||
std::vector<long> getUnreleasedFaceFeatures() {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
std::vector<long> unreleasedFaceFeatures;
|
||||
for (const auto& entry : faceFeatureMap) {
|
||||
if (!entry.second) {
|
||||
unreleasedFaceFeatures.push_back(entry.first);
|
||||
}
|
||||
}
|
||||
return unreleasedFaceFeatures;
|
||||
}
|
||||
|
||||
// Method to print resource management statistics
|
||||
void printResourceStatistics() {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
INSPIRE_LOGI("================================================================");
|
||||
INSPIRE_LOGI("%-15s%-15s%-15s%-15s", "Resource Name", "Total Created", "Total Released", "Not Released");
|
||||
INSPIRE_LOGI("----------------------------------------------------------------");
|
||||
|
||||
// Print session statistics
|
||||
int totalSessionsCreated = sessionMap.size();
|
||||
@@ -182,6 +214,19 @@ public:
|
||||
++bitmapsNotReleased;
|
||||
}
|
||||
INSPIRE_LOGI("%-15s%-15d%-15d%-15d", "Bitmap", totalBitmapsCreated, totalBitmapsReleased, bitmapsNotReleased);
|
||||
|
||||
// Print face feature statistics
|
||||
int totalFeaturesCreated = faceFeatureMap.size();
|
||||
int totalFeaturesReleased = 0;
|
||||
int featuresNotReleased = 0;
|
||||
for (const auto& entry : faceFeatureMap) {
|
||||
if (entry.second)
|
||||
++totalFeaturesReleased;
|
||||
if (!entry.second)
|
||||
++featuresNotReleased;
|
||||
}
|
||||
INSPIRE_LOGI("%-15s%-15d%-15d%-15d", "FaceFeature", totalFeaturesCreated, totalFeaturesReleased, featuresNotReleased);
|
||||
INSPIRE_LOGI("================================================================");
|
||||
}
|
||||
};
|
||||
|
||||
277
cpp-package/inspireface/cpp/inspireface/session.cpp
Normal file
277
cpp-package/inspireface/cpp/inspireface/session.cpp
Normal file
@@ -0,0 +1,277 @@
|
||||
#include <memory>
|
||||
#include "session.h"
|
||||
#include "engine/face_session.h"
|
||||
#include "recognition_module/dest_const.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
class Session::Impl {
|
||||
public:
|
||||
Impl() : m_face_session_(std::make_unique<FaceSession>()) {}
|
||||
|
||||
int32_t Configure(DetectModuleMode detect_mode, int32_t max_detect_face, CustomPipelineParameter param, int32_t detect_level_px,
|
||||
int32_t track_by_detect_mode_fps) {
|
||||
return m_face_session_->Configuration(detect_mode, max_detect_face, param, detect_level_px, track_by_detect_mode_fps);
|
||||
}
|
||||
|
||||
~Impl() = default;
|
||||
|
||||
void SetTrackPreviewSize(int32_t preview_size) {
|
||||
m_face_session_->SetTrackPreviewSize(preview_size);
|
||||
}
|
||||
|
||||
void SetFilterMinimumFacePixelSize(int32_t min_face_pixel_size) {
|
||||
m_face_session_->SetTrackFaceMinimumSize(min_face_pixel_size);
|
||||
}
|
||||
|
||||
void SetFaceDetectThreshold(float threshold) {
|
||||
m_face_session_->SetFaceDetectThreshold(threshold);
|
||||
}
|
||||
|
||||
void SetTrackModeSmoothRatio(int32_t smooth_ratio) {
|
||||
m_face_session_->SetTrackModeSmoothRatio(smooth_ratio);
|
||||
}
|
||||
|
||||
void SetTrackModeNumSmoothCacheFrame(int32_t num_smooth_cache_frame) {
|
||||
m_face_session_->SetTrackModeNumSmoothCacheFrame(num_smooth_cache_frame);
|
||||
}
|
||||
|
||||
void SetTrackModeDetectInterval(int32_t detect_interval) {
|
||||
m_face_session_->SetTrackModeDetectInterval(detect_interval);
|
||||
}
|
||||
|
||||
int32_t FaceDetectAndTrack(inspirecv::FrameProcess& process, std::vector<FaceTrackWrap>& results) {
|
||||
int32_t ret = m_face_session_->FaceDetectAndTrack(process);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
results.clear();
|
||||
const auto& face_data = m_face_session_->GetDetectCache();
|
||||
for (const auto& data : face_data) {
|
||||
FaceTrackWrap hyper_face_data;
|
||||
RunDeserializeHyperFaceData(data, hyper_face_data);
|
||||
results.emplace_back(hyper_face_data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inspirecv::Rect2i GetFaceBoundingBox(const FaceTrackWrap& face_data) {
|
||||
return inspirecv::Rect2i{face_data.rect.x, face_data.rect.y, face_data.rect.width, face_data.rect.height};
|
||||
}
|
||||
|
||||
std::vector<inspirecv::Point2f> GetFaceDenseLandmark(const FaceTrackWrap& face_data) {
|
||||
std::vector<inspirecv::Point2f> points;
|
||||
for (const auto& p : face_data.densityLandmark) {
|
||||
points.emplace_back(inspirecv::Point2f(p.x, p.y));
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
std::vector<inspirecv::Point2f> GetFaceFiveKeyPoints(const FaceTrackWrap& face_data) {
|
||||
std::vector<inspirecv::Point2f> points;
|
||||
for (const auto& p : face_data.keyPoints) {
|
||||
points.emplace_back(inspirecv::Point2f(p.x, p.y));
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
int32_t FaceFeatureExtract(inspirecv::FrameProcess& process, FaceTrackWrap& data, FaceEmbedding& embedding, bool normalize) {
|
||||
int32_t ret = m_face_session_->FaceFeatureExtract(process, data, normalize);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
embedding.isNormal = normalize;
|
||||
embedding.embedding = m_face_session_->GetFaceFeatureCache();
|
||||
embedding.norm = m_face_session_->GetFaceFeatureNormCache();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t FaceFeatureExtractWithAlignmentImage(inspirecv::FrameProcess& process, FaceEmbedding& embedding, bool normalize) {
|
||||
int32_t ret = m_face_session_->FaceFeatureExtractWithAlignmentImage(process, embedding.embedding, embedding.norm, normalize);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
embedding.isNormal = normalize;
|
||||
embedding.norm = embedding.norm;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t FaceFeatureExtractWithAlignmentImage(const inspirecv::Image& wrapped, FaceEmbedding& embedding, bool normalize) {
|
||||
int32_t ret = m_face_session_->FaceFeatureExtractWithAlignmentImage(wrapped, embedding, embedding.norm, normalize);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
embedding.isNormal = normalize;
|
||||
embedding.norm = embedding.norm;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GetFaceAlignmentImage(inspirecv::FrameProcess& process, FaceTrackWrap& data, inspirecv::Image& wrapped) {
|
||||
std::vector<inspirecv::Point2f> pointsFive;
|
||||
for (const auto& p : data.keyPoints) {
|
||||
pointsFive.push_back(inspirecv::Point2f(p.x, p.y));
|
||||
}
|
||||
auto trans = inspirecv::SimilarityTransformEstimateUmeyama(SIMILARITY_TRANSFORM_DEST, pointsFive);
|
||||
wrapped = process.ExecuteImageAffineProcessing(trans, FACE_CROP_SIZE, FACE_CROP_SIZE);
|
||||
}
|
||||
|
||||
int32_t MultipleFacePipelineProcess(inspirecv::FrameProcess& process, const CustomPipelineParameter& param,
|
||||
const std::vector<FaceTrackWrap>& face_data_list) {
|
||||
int32_t ret = m_face_session_->FacesProcess(process, face_data_list, param);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<float> GetRGBLivenessConfidence() {
|
||||
return m_face_session_->GetDetConfidenceCache();
|
||||
}
|
||||
|
||||
std::vector<float> GetFaceMaskConfidence() {
|
||||
return m_face_session_->GetMaskResultsCache();
|
||||
}
|
||||
|
||||
std::vector<float> GetFaceQualityConfidence() {
|
||||
return m_face_session_->GetFaceQualityScoresResultsCache();
|
||||
}
|
||||
|
||||
std::vector<FaceInteractionState> GetFaceInteractionState() {
|
||||
auto left_eyes_confidence = m_face_session_->GetFaceInteractionLeftEyeStatusCache();
|
||||
auto right_eyes_confidence = m_face_session_->GetFaceInteractionRightEyeStatusCache();
|
||||
std::vector<FaceInteractionState> face_interaction_state;
|
||||
for (size_t i = 0; i < left_eyes_confidence.size(); ++i) {
|
||||
face_interaction_state.emplace_back(FaceInteractionState{left_eyes_confidence[i], right_eyes_confidence[i]});
|
||||
}
|
||||
return face_interaction_state;
|
||||
}
|
||||
|
||||
std::vector<FaceInteractionAction> GetFaceInteractionAction() {
|
||||
auto num = m_face_session_->GetFaceNormalAactionsResultCache().size();
|
||||
std::vector<FaceInteractionAction> face_interaction_action;
|
||||
face_interaction_action.resize(num);
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
face_interaction_action[i].normal = m_face_session_->GetFaceNormalAactionsResultCache()[i];
|
||||
face_interaction_action[i].shake = m_face_session_->GetFaceShakeAactionsResultCache()[i];
|
||||
face_interaction_action[i].jawOpen = m_face_session_->GetFaceJawOpenAactionsResultCache()[i];
|
||||
face_interaction_action[i].headRaise = m_face_session_->GetFaceRaiseHeadAactionsResultCache()[i];
|
||||
face_interaction_action[i].blink = m_face_session_->GetFaceBlinkAactionsResultCache()[i];
|
||||
}
|
||||
return face_interaction_action;
|
||||
}
|
||||
|
||||
std::vector<FaceAttributeResult> GetFaceAttributeResult() {
|
||||
auto num = m_face_session_->GetFaceNormalAactionsResultCache().size();
|
||||
std::vector<FaceAttributeResult> face_attribute_result;
|
||||
face_attribute_result.resize(num);
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
face_attribute_result[i].race = m_face_session_->GetFaceRaceResultsCache()[i];
|
||||
face_attribute_result[i].gender = m_face_session_->GetFaceGenderResultsCache()[i];
|
||||
face_attribute_result[i].ageBracket = m_face_session_->GetFaceAgeBracketResultsCache()[i];
|
||||
}
|
||||
return face_attribute_result;
|
||||
}
|
||||
|
||||
std::unique_ptr<FaceSession> m_face_session_;
|
||||
};
|
||||
|
||||
Session::Session() : pImpl(std::make_unique<Impl>()) {}
|
||||
|
||||
Session::~Session() = default;
|
||||
|
||||
Session::Session(Session&&) noexcept = default;
|
||||
|
||||
Session& Session::operator=(Session&&) noexcept = default;
|
||||
|
||||
Session Session::Create(DetectModuleMode detect_mode, int32_t max_detect_face, const CustomPipelineParameter& param, int32_t detect_level_px,
|
||||
int32_t track_by_detect_mode_fps) {
|
||||
Session session;
|
||||
session.pImpl->Configure(detect_mode, max_detect_face, param, detect_level_px, track_by_detect_mode_fps);
|
||||
return session;
|
||||
}
|
||||
|
||||
void Session::SetTrackPreviewSize(int32_t preview_size) {
|
||||
pImpl->SetTrackPreviewSize(preview_size);
|
||||
}
|
||||
|
||||
void Session::SetFilterMinimumFacePixelSize(int32_t min_face_pixel_size) {
|
||||
pImpl->SetFilterMinimumFacePixelSize(min_face_pixel_size);
|
||||
}
|
||||
|
||||
void Session::SetFaceDetectThreshold(float threshold) {
|
||||
pImpl->SetFaceDetectThreshold(threshold);
|
||||
}
|
||||
|
||||
void Session::SetTrackModeSmoothRatio(int32_t smooth_ratio) {
|
||||
pImpl->SetTrackModeSmoothRatio(smooth_ratio);
|
||||
}
|
||||
|
||||
void Session::SetTrackModeNumSmoothCacheFrame(int32_t num_smooth_cache_frame) {
|
||||
pImpl->SetTrackModeNumSmoothCacheFrame(num_smooth_cache_frame);
|
||||
}
|
||||
|
||||
void Session::SetTrackModeDetectInterval(int32_t detect_interval) {
|
||||
pImpl->SetTrackModeDetectInterval(detect_interval);
|
||||
}
|
||||
|
||||
int32_t Session::FaceDetectAndTrack(inspirecv::FrameProcess& process, std::vector<FaceTrackWrap>& results) {
|
||||
return pImpl->FaceDetectAndTrack(process, results);
|
||||
}
|
||||
|
||||
inspirecv::Rect2i Session::GetFaceBoundingBox(const FaceTrackWrap& face_data) {
|
||||
return pImpl->GetFaceBoundingBox(face_data);
|
||||
}
|
||||
|
||||
std::vector<inspirecv::Point2f> Session::GetFaceDenseLandmark(const FaceTrackWrap& face_data) {
|
||||
return pImpl->GetFaceDenseLandmark(face_data);
|
||||
}
|
||||
|
||||
std::vector<inspirecv::Point2f> Session::GetFaceFiveKeyPoints(const FaceTrackWrap& face_data) {
|
||||
return pImpl->GetFaceFiveKeyPoints(face_data);
|
||||
}
|
||||
|
||||
int32_t Session::FaceFeatureExtract(inspirecv::FrameProcess& process, FaceTrackWrap& data, FaceEmbedding& embedding, bool normalize) {
|
||||
return pImpl->FaceFeatureExtract(process, data, embedding, normalize);
|
||||
}
|
||||
|
||||
int32_t Session::FaceFeatureExtractWithAlignmentImage(inspirecv::FrameProcess& process, FaceEmbedding& embedding, bool normalize) {
|
||||
return pImpl->FaceFeatureExtractWithAlignmentImage(process, embedding, normalize);
|
||||
}
|
||||
|
||||
int32_t Session::FaceFeatureExtractWithAlignmentImage(const inspirecv::Image& wrapped, FaceEmbedding& embedding, bool normalize) {
|
||||
return pImpl->FaceFeatureExtractWithAlignmentImage(wrapped, embedding, normalize);
|
||||
}
|
||||
|
||||
void Session::GetFaceAlignmentImage(inspirecv::FrameProcess& process, FaceTrackWrap& data, inspirecv::Image& wrapped) {
|
||||
pImpl->GetFaceAlignmentImage(process, data, wrapped);
|
||||
}
|
||||
|
||||
int32_t Session::MultipleFacePipelineProcess(inspirecv::FrameProcess& process, const CustomPipelineParameter& param,
|
||||
const std::vector<FaceTrackWrap>& face_data_list) {
|
||||
return pImpl->MultipleFacePipelineProcess(process, param, face_data_list);
|
||||
}
|
||||
|
||||
std::vector<float> Session::GetRGBLivenessConfidence() {
|
||||
return pImpl->GetRGBLivenessConfidence();
|
||||
}
|
||||
|
||||
std::vector<float> Session::GetFaceMaskConfidence() {
|
||||
return pImpl->GetFaceMaskConfidence();
|
||||
}
|
||||
|
||||
std::vector<float> Session::GetFaceQualityConfidence() {
|
||||
return pImpl->GetFaceQualityConfidence();
|
||||
}
|
||||
|
||||
std::vector<FaceInteractionState> Session::GetFaceInteractionState() {
|
||||
return pImpl->GetFaceInteractionState();
|
||||
}
|
||||
|
||||
std::vector<FaceInteractionAction> Session::GetFaceInteractionAction() {
|
||||
return pImpl->GetFaceInteractionAction();
|
||||
}
|
||||
|
||||
std::vector<FaceAttributeResult> Session::GetFaceAttributeResult() {
|
||||
return pImpl->GetFaceAttributeResult();
|
||||
}
|
||||
|
||||
} // namespace inspire
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include "face_detect_adapt.h"
|
||||
#include "cost_time.h"
|
||||
#include <inspirecv/time_spend.h>
|
||||
#include "spend_timer.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
@@ -13,7 +13,7 @@ FaceDetectAdapt::FaceDetectAdapt(int input_size, float nms_threshold, float cls_
|
||||
: AnyNetAdapter("FaceDetectAdapt"), m_nms_threshold_(nms_threshold), m_cls_threshold_(cls_threshold), m_input_size_(input_size) {}
|
||||
|
||||
FaceLocList FaceDetectAdapt::operator()(const inspirecv::Image &bgr) {
|
||||
inspirecv::TimeSpend time_image_process("Image process");
|
||||
inspire::SpendTimer time_image_process("Image process");
|
||||
time_image_process.Start();
|
||||
int ori_w = bgr.Width();
|
||||
int ori_h = bgr.Height();
|
||||
@@ -31,14 +31,14 @@ FaceLocList FaceDetectAdapt::operator()(const inspirecv::Image &bgr) {
|
||||
// pad.Write("pad.jpg");
|
||||
// LOGD("Prepare");
|
||||
AnyTensorOutputs outputs;
|
||||
inspirecv::TimeSpend time_forward("Forward");
|
||||
inspire::SpendTimer time_forward("Forward");
|
||||
time_forward.Start();
|
||||
Forward(pad, outputs);
|
||||
time_forward.Stop();
|
||||
// std::cout << time_forward << std::endl;
|
||||
// LOGD("Forward");
|
||||
|
||||
inspirecv::TimeSpend time_decode("Decode");
|
||||
inspire::SpendTimer time_decode("Decode");
|
||||
time_decode.Start();
|
||||
std::vector<FaceLoc> results;
|
||||
std::vector<int> strides = {8, 16, 32};
|
||||
@@ -154,4 +154,8 @@ bool SortBoxSizeAdapt(const FaceLoc &a, const FaceLoc &b) {
|
||||
return sq_a > sq_b;
|
||||
}
|
||||
|
||||
int FaceDetectAdapt::GetInputSize() const {
|
||||
return m_input_size_;
|
||||
}
|
||||
|
||||
} // namespace inspire
|
||||
@@ -6,9 +6,9 @@
|
||||
#pragma once
|
||||
#ifndef INSPIRE_FACE_TRACK_MODULE_FACE_DETECT_FACE_DETECT_ADAPT_H
|
||||
#define INSPIRE_FACE_TRACK_MODULE_FACE_DETECT_FACE_DETECT_ADAPT_H
|
||||
#include "../../data_type.h"
|
||||
#include "data_type.h"
|
||||
#include "middleware/any_net_adapter.h"
|
||||
#include "middleware/nexus_processor/image_processor.h"
|
||||
#include "image_process/nexus_processor/image_processor.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
@@ -41,6 +41,12 @@ public:
|
||||
/** @brief Set face classification threshold */
|
||||
void SetClsThreshold(float mClsThreshold);
|
||||
|
||||
/**
|
||||
* @brief Get the input size
|
||||
* @return int The input size
|
||||
*/
|
||||
int GetInputSize() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Applies non-maximum suppression to reduce overlapping detected faces.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#pragma once
|
||||
#ifndef INSPIRE_FACE_TRACK_MODULE_FACE_DETECT_RNET_ADAPT_H
|
||||
#define INSPIRE_FACE_TRACK_MODULE_FACE_DETECT_RNET_ADAPT_H
|
||||
#include "../../data_type.h"
|
||||
#include "data_type.h"
|
||||
#include "middleware/any_net_adapter.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "face_track_module.h"
|
||||
#include "log.h"
|
||||
#include "landmark/mean_shape.h"
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include "middleware/costman.h"
|
||||
@@ -14,7 +13,8 @@
|
||||
#include "herror.h"
|
||||
#include "middleware/costman.h"
|
||||
#include "cost_time.h"
|
||||
#include <inspirecv/time_spend.h>
|
||||
#include "spend_timer.h"
|
||||
#include "launch.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
@@ -35,7 +35,8 @@ FaceTrackModule::FaceTrackModule(DetectModuleMode mode, int max_detected_faces,
|
||||
// In lightweight tracking mode, landmark detection is always required
|
||||
m_detect_mode_landmark_ = true;
|
||||
} else {
|
||||
m_detect_mode_landmark_ = detect_mode_landmark;
|
||||
// This version uses lmk106 to replace five key points, so lmk must be forcibly enabled!
|
||||
m_detect_mode_landmark_ = true;
|
||||
}
|
||||
if (m_mode_ == DETECT_MODE_TRACK_BY_DETECT) {
|
||||
m_TbD_tracker_ = std::make_shared<BYTETracker>(TbD_mode_fps, 30);
|
||||
@@ -45,17 +46,20 @@ FaceTrackModule::FaceTrackModule(DetectModuleMode mode, int max_detected_faces,
|
||||
void FaceTrackModule::SparseLandmarkPredict(const inspirecv::Image &raw_face_crop, std::vector<inspirecv::Point2f> &landmarks_output, float &score,
|
||||
float size) {
|
||||
COST_TIME_SIMPLE(SparseLandmarkPredict);
|
||||
landmarks_output.resize(FaceLandmarkAdapt::NUM_OF_LANDMARK);
|
||||
landmarks_output.resize(m_landmark_param_->num_of_landmark);
|
||||
std::vector<float> lmk_out = (*m_landmark_predictor_)(raw_face_crop);
|
||||
for (int i = 0; i < FaceLandmarkAdapt::NUM_OF_LANDMARK; ++i) {
|
||||
for (int i = 0; i < m_landmark_param_->num_of_landmark; ++i) {
|
||||
float x = lmk_out[i * 2 + 0] * size;
|
||||
float y = lmk_out[i * 2 + 1] * size;
|
||||
landmarks_output[i] = inspirecv::Point<float>(x, y);
|
||||
}
|
||||
score = (*m_refine_net_)(raw_face_crop);
|
||||
}
|
||||
|
||||
bool FaceTrackModule::TrackFace(inspirecv::InspireImageProcess &image, FaceObjectInternal &face) {
|
||||
float FaceTrackModule::PredictTrackScore(const inspirecv::Image &raw_face_crop) {
|
||||
return (*m_refine_net_)(raw_face_crop);
|
||||
}
|
||||
|
||||
bool FaceTrackModule::TrackFace(inspirecv::FrameProcess &image, FaceObjectInternal &face) {
|
||||
COST_TIME_SIMPLE(TrackFace);
|
||||
// If the face confidence level is below 0.1, disable tracking
|
||||
if (face.GetConfidence() < 0.1) {
|
||||
@@ -79,21 +83,13 @@ bool FaceTrackModule::TrackFace(inspirecv::InspireImageProcess &image, FaceObjec
|
||||
inspirecv::TransformMatrix rotation_mode_affine = image.GetAffineMatrix();
|
||||
std::vector<inspirecv::Point2f> camera_pts = ApplyTransformToPoints(rect_pts, rotation_mode_affine);
|
||||
// camera_pts.erase(camera_pts.end() - 1);
|
||||
std::vector<inspirecv::Point2f> dst_pts = {{0, 0}, {112, 0}, {112, 112}, {0, 112}};
|
||||
std::vector<inspirecv::Point2f> dst_pts = {{0, 0},
|
||||
{(float)m_landmark_param_->input_size, 0},
|
||||
{(float)m_landmark_param_->input_size, (float)m_landmark_param_->input_size},
|
||||
{0, (float)m_landmark_param_->input_size}};
|
||||
affine = inspirecv::SimilarityTransformEstimate(camera_pts, dst_pts);
|
||||
face.setTransMatrix(affine);
|
||||
|
||||
std::vector<inspirecv::Point2f> dst_pts_extensive = {{0, 0},
|
||||
{(float)m_crop_extensive_size_, 0},
|
||||
{(float)m_crop_extensive_size_, (float)m_crop_extensive_size_},
|
||||
{0, (float)m_crop_extensive_size_}};
|
||||
// Add extensive rect
|
||||
inspirecv::Rect2i extensive_rect = rect_square.Square(m_crop_extensive_ratio_);
|
||||
auto extensive_rect_pts = extensive_rect.As<float>().ToFourVertices();
|
||||
std::vector<inspirecv::Point2f> camera_pts_extensive = ApplyTransformToPoints(extensive_rect_pts, rotation_mode_affine);
|
||||
inspirecv::TransformMatrix extensive_affine = inspirecv::SimilarityTransformEstimate(camera_pts_extensive, dst_pts);
|
||||
face.setTransMatrixExtensive(extensive_affine);
|
||||
|
||||
if (!m_detect_mode_landmark_) {
|
||||
/*If landmark is not extracted, the detection frame of the preview image needs to be changed
|
||||
back to the coordinate system of the original image */
|
||||
@@ -105,41 +101,72 @@ bool FaceTrackModule::TrackFace(inspirecv::InspireImageProcess &image, FaceObjec
|
||||
|
||||
if (m_face_quality_ != nullptr) {
|
||||
COST_TIME_SIMPLE(FaceQuality);
|
||||
auto affine_extensive = face.getTransMatrixExtensive();
|
||||
auto pre_crop = image.ExecuteImageAffineProcessing(affine_extensive, m_crop_extensive_size_, m_crop_extensive_size_);
|
||||
auto affine_extensive = face.getTransMatrix();
|
||||
auto trans_e = ScaleAffineMatrixPreserveCenter(affine_extensive, m_crop_extensive_ratio_, m_landmark_param_->input_size);
|
||||
auto pre_crop = image.ExecuteImageAffineProcessing(trans_e, m_landmark_param_->input_size, m_landmark_param_->input_size);
|
||||
auto res = (*m_face_quality_)(pre_crop);
|
||||
// pre_crop.Show("pre_crop");
|
||||
|
||||
auto affine_extensive_inv = affine_extensive.GetInverse();
|
||||
std::vector<inspirecv::Point2f> lmk_extensive = ApplyTransformToPoints(res.lmk, affine_extensive_inv);
|
||||
res.lmk = lmk_extensive;
|
||||
face.high_result = res;
|
||||
} else {
|
||||
// If face pose and quality model is not initialized, set the default value
|
||||
FacePoseQualityAdaptResult empty_result;
|
||||
empty_result.lmk = std::vector<inspirecv::Point2f>(5, inspirecv::Point2f(0, 0));
|
||||
empty_result.lmk_quality = std::vector<float>(5, 2.0f);
|
||||
empty_result.pitch = 0.0f;
|
||||
empty_result.yaw = 0.0f;
|
||||
empty_result.roll = 0.0f;
|
||||
face.high_result = empty_result;
|
||||
}
|
||||
|
||||
if (m_detect_mode_landmark_) {
|
||||
// If Landmark need to be extracted in detection mode,
|
||||
// Landmark must be detected when fast tracing is enabled
|
||||
affine = face.getTransMatrix();
|
||||
inspirecv::Image crop;
|
||||
// Get the RGB image after affine transformation
|
||||
crop = image.ExecuteImageAffineProcessing(affine, 112, 112);
|
||||
inspirecv::TransformMatrix affine_inv = affine.GetInverse();
|
||||
|
||||
std::vector<inspirecv::Point2f> landmark_rawout;
|
||||
std::vector<float> bbox;
|
||||
std::vector<std::vector<inspirecv::Point2f>> multiscale_landmark_back;
|
||||
|
||||
auto track_crop = image.ExecuteImageAffineProcessing(affine, m_landmark_param_->input_size, m_landmark_param_->input_size);
|
||||
score = PredictTrackScore(track_crop);
|
||||
// track_crop.Show("track_crop");
|
||||
|
||||
for (int i = 0; i < m_multiscale_landmark_scales_.size(); i++) {
|
||||
inspirecv::Image crop;
|
||||
// Get the RGB image after affine transformation
|
||||
auto affine_scale = ScaleAffineMatrixPreserveCenter(affine, m_multiscale_landmark_scales_[i], m_landmark_param_->input_size);
|
||||
crop = image.ExecuteImageAffineProcessing(affine_scale, m_landmark_param_->input_size, m_landmark_param_->input_size);
|
||||
|
||||
std::vector<inspirecv::Point2f> lmk_predict;
|
||||
|
||||
// Predicted sparse key point
|
||||
SparseLandmarkPredict(crop, lmk_predict, score, m_landmark_param_->input_size);
|
||||
|
||||
// Save the first scale landmark
|
||||
if (i == 0) {
|
||||
landmark_rawout = lmk_predict;
|
||||
}
|
||||
|
||||
std::vector<inspirecv::Point2f> lmk_back;
|
||||
// Convert key points back to the original coordinate system
|
||||
lmk_back.resize(lmk_predict.size());
|
||||
lmk_back = inspirecv::ApplyTransformToPoints(lmk_predict, affine_scale.GetInverse());
|
||||
|
||||
multiscale_landmark_back.push_back(lmk_back);
|
||||
}
|
||||
|
||||
landmark_back = MultiFrameLandmarkMean(multiscale_landmark_back);
|
||||
|
||||
Timer lmk_cost_time;
|
||||
// Predicted sparse key point
|
||||
SparseLandmarkPredict(crop, landmark_rawout, score, 112);
|
||||
// Extract 5 key points
|
||||
std::vector<inspirecv::Point2f> lmk_5 = {
|
||||
landmark_rawout[FaceLandmarkAdapt::LEFT_EYE_CENTER], landmark_rawout[FaceLandmarkAdapt::RIGHT_EYE_CENTER],
|
||||
landmark_rawout[FaceLandmarkAdapt::NOSE_CORNER], landmark_rawout[FaceLandmarkAdapt::MOUTH_LEFT_CORNER],
|
||||
landmark_rawout[FaceLandmarkAdapt::MOUTH_RIGHT_CORNER]};
|
||||
landmark_rawout[m_landmark_param_->semantic_index.left_eye_center], landmark_rawout[m_landmark_param_->semantic_index.right_eye_center],
|
||||
landmark_rawout[m_landmark_param_->semantic_index.nose_corner], landmark_rawout[m_landmark_param_->semantic_index.mouth_left_corner],
|
||||
landmark_rawout[m_landmark_param_->semantic_index.mouth_right_corner]};
|
||||
face.setAlignMeanSquareError(lmk_5);
|
||||
|
||||
// Convert key points back to the original coordinate system
|
||||
landmark_back.resize(landmark_rawout.size());
|
||||
landmark_back = inspirecv::ApplyTransformToPoints(landmark_rawout, affine_inv);
|
||||
int MODE = 1;
|
||||
|
||||
if (MODE > 0) {
|
||||
@@ -148,15 +175,16 @@ bool FaceTrackModule::TrackFace(inspirecv::InspireImageProcess &image, FaceObjec
|
||||
} else if (face.TrackingState() == ISF_READY || face.TrackingState() == ISF_TRACKING) {
|
||||
COST_TIME_SIMPLE(LandmarkBack);
|
||||
inspirecv::TransformMatrix trans_m;
|
||||
inspirecv::TransformMatrix tmp = face.getTransMatrix();
|
||||
std::vector<inspirecv::Point2f> inside_points = landmark_rawout;
|
||||
|
||||
std::vector<inspirecv::Point2f> mean_shape_(FaceLandmarkAdapt::NUM_OF_LANDMARK);
|
||||
for (int k = 0; k < FaceLandmarkAdapt::NUM_OF_LANDMARK; k++) {
|
||||
mean_shape_[k].SetX(mean_shape[k * 2]);
|
||||
mean_shape_[k].SetY(mean_shape[k * 2 + 1]);
|
||||
// inspirecv::TransformMatrix tmp = face.getTransMatrix();
|
||||
std::vector<inspirecv::Point2f> inside_points;
|
||||
if (m_landmark_param_->input_size == 112) {
|
||||
inside_points = landmark_rawout;
|
||||
} else {
|
||||
inside_points = LandmarkCropped(landmark_rawout);
|
||||
}
|
||||
|
||||
auto &mean_shape_ = m_landmark_param_->mean_shape_points;
|
||||
|
||||
auto _affine = inspirecv::SimilarityTransformEstimate(inside_points, mean_shape_);
|
||||
auto mid_inside_points = ApplyTransformToPoints(inside_points, _affine);
|
||||
inside_points = FixPointsMeanshape(mid_inside_points, mean_shape_);
|
||||
@@ -164,44 +192,19 @@ bool FaceTrackModule::TrackFace(inspirecv::InspireImageProcess &image, FaceObjec
|
||||
trans_m = inspirecv::SimilarityTransformEstimate(landmark_back, inside_points);
|
||||
face.setTransMatrix(trans_m);
|
||||
face.EnableTracking();
|
||||
|
||||
Timer extensive_cost_time;
|
||||
// Add extensive rect
|
||||
// Calculate center point of landmarks
|
||||
inspirecv::Point2f center(0.0f, 0.0f);
|
||||
for (const auto &pt : landmark_back) {
|
||||
center.SetX(center.GetX() + pt.GetX());
|
||||
center.SetY(center.GetY() + pt.GetY());
|
||||
}
|
||||
center.SetX(center.GetX() / landmark_back.size());
|
||||
center.SetY(center.GetY() / landmark_back.size());
|
||||
|
||||
// Create expanded points by scaling from center by 1.3
|
||||
std::vector<inspirecv::Point2f> lmk_back_rect = landmark_back;
|
||||
for (auto &pt : lmk_back_rect) {
|
||||
pt.SetX(center.GetX() + (pt.GetX() - center.GetX()) * m_crop_extensive_ratio_);
|
||||
pt.SetY(center.GetY() + (pt.GetY() - center.GetY()) * m_crop_extensive_ratio_);
|
||||
}
|
||||
inspirecv::TransformMatrix extensive_affine = inspirecv::SimilarityTransformEstimate(lmk_back_rect, mid_inside_points);
|
||||
face.setTransMatrixExtensive(extensive_affine);
|
||||
// INSPIRE_LOGD("Extensive Affine Cost %f", extensive_cost_time.GetCostTimeUpdate());
|
||||
}
|
||||
}
|
||||
// Add five key points to landmark_back
|
||||
for (int i = 0; i < 5; i++) {
|
||||
landmark_back.push_back(face.high_result.lmk[i]);
|
||||
}
|
||||
// Update face key points
|
||||
face.SetLandmark(landmark_back, true, true, m_track_mode_smooth_ratio_, m_track_mode_num_smooth_cache_frame_,
|
||||
(FaceLandmarkAdapt::NUM_OF_LANDMARK + 10) * 2);
|
||||
m_landmark_param_->num_of_landmark * 2);
|
||||
// Get the smoothed landmark
|
||||
auto &landmark_smooth = face.landmark_smooth_aux_.back();
|
||||
// Update the face key points
|
||||
face.high_result.lmk[0] = landmark_smooth[FaceLandmarkAdapt::NUM_OF_LANDMARK + 0];
|
||||
face.high_result.lmk[1] = landmark_smooth[FaceLandmarkAdapt::NUM_OF_LANDMARK + 1];
|
||||
face.high_result.lmk[2] = landmark_smooth[FaceLandmarkAdapt::NUM_OF_LANDMARK + 2];
|
||||
face.high_result.lmk[3] = landmark_smooth[FaceLandmarkAdapt::NUM_OF_LANDMARK + 3];
|
||||
face.high_result.lmk[4] = landmark_smooth[FaceLandmarkAdapt::NUM_OF_LANDMARK + 4];
|
||||
face.high_result.lmk[0] = landmark_smooth[m_landmark_param_->semantic_index.left_eye_center];
|
||||
face.high_result.lmk[1] = landmark_smooth[m_landmark_param_->semantic_index.right_eye_center];
|
||||
face.high_result.lmk[2] = landmark_smooth[m_landmark_param_->semantic_index.nose_corner];
|
||||
face.high_result.lmk[3] = landmark_smooth[m_landmark_param_->semantic_index.mouth_left_corner];
|
||||
face.high_result.lmk[4] = landmark_smooth[m_landmark_param_->semantic_index.mouth_right_corner];
|
||||
}
|
||||
|
||||
// If tracking status, update the confidence level
|
||||
@@ -212,17 +215,18 @@ bool FaceTrackModule::TrackFace(inspirecv::InspireImageProcess &image, FaceObjec
|
||||
return true;
|
||||
}
|
||||
|
||||
void FaceTrackModule::UpdateStream(inspirecv::InspireImageProcess &image) {
|
||||
inspirecv::TimeSpend total("UpdateStream");
|
||||
void FaceTrackModule::UpdateStream(inspirecv::FrameProcess &image) {
|
||||
inspire::SpendTimer total("UpdateStream");
|
||||
total.Start();
|
||||
COST_TIME_SIMPLE(FaceTrackUpdateStream);
|
||||
detection_index_ += 1;
|
||||
if (m_mode_ == DETECT_MODE_ALWAYS_DETECT || m_mode_ == DETECT_MODE_TRACK_BY_DETECT)
|
||||
trackingFace.clear();
|
||||
if (trackingFace.empty() || detection_index_ % detection_interval_ == 0 || m_mode_ == DETECT_MODE_ALWAYS_DETECT ||
|
||||
if (trackingFace.empty() || (detection_interval_ > 0 && detection_index_ % detection_interval_ == 0) || m_mode_ == DETECT_MODE_ALWAYS_DETECT ||
|
||||
m_mode_ == DETECT_MODE_TRACK_BY_DETECT) {
|
||||
image.SetPreviewSize(track_preview_size_);
|
||||
inspirecv::Image image_detect = image.ExecutePreviewImageProcessing(true);
|
||||
m_debug_preview_image_size_ = image_detect.Width();
|
||||
|
||||
nms();
|
||||
for (auto const &face : trackingFace) {
|
||||
@@ -336,7 +340,7 @@ void FaceTrackModule::DetectFace(const inspirecv::Image &input, float scale) {
|
||||
tracking_idx_ = tracking_idx_ + 1;
|
||||
}
|
||||
|
||||
FaceObjectInternal faceinfo(tracking_idx_, bbox[i], FaceLandmarkAdapt::NUM_OF_LANDMARK + 10);
|
||||
FaceObjectInternal faceinfo(tracking_idx_, bbox[i], m_landmark_param_->num_of_landmark + 10);
|
||||
faceinfo.detect_bbox_ = bbox[i];
|
||||
faceinfo.SetConfidence(boxes[i].score);
|
||||
|
||||
@@ -350,11 +354,12 @@ void FaceTrackModule::DetectFace(const inspirecv::Image &input, float scale) {
|
||||
}
|
||||
}
|
||||
|
||||
int FaceTrackModule::Configuration(inspire::InspireArchive &archive, const std::string &expansion_path) {
|
||||
int FaceTrackModule::Configuration(inspire::InspireArchive &archive, const std::string &expansion_path, bool enable_face_pose_and_quality) {
|
||||
// Initialize the detection model
|
||||
m_landmark_param_ = archive.GetLandmarkParam();
|
||||
m_expansion_path_ = std::move(expansion_path);
|
||||
InspireModel detModel;
|
||||
auto scheme = ChoiceMultiLevelDetectModel(m_dynamic_detection_input_level_);
|
||||
auto scheme = ChoiceMultiLevelDetectModel(m_dynamic_detection_input_level_, track_preview_size_);
|
||||
auto ret = archive.LoadModel(scheme, detModel);
|
||||
if (ret != SARC_SUCCESS) {
|
||||
INSPIRE_LOGE("Load %s error: %d", scheme.c_str(), ret);
|
||||
@@ -364,9 +369,9 @@ int FaceTrackModule::Configuration(inspire::InspireArchive &archive, const std::
|
||||
|
||||
// Initialize the landmark model
|
||||
InspireModel lmkModel;
|
||||
ret = archive.LoadModel("landmark", lmkModel);
|
||||
ret = archive.LoadModel(m_landmark_param_->landmark_engine_name, lmkModel);
|
||||
if (ret != SARC_SUCCESS) {
|
||||
INSPIRE_LOGE("Load %s error: %d", "landmark", ret);
|
||||
INSPIRE_LOGE("Load %s error: %d", m_landmark_param_->landmark_engine_name.c_str(), ret);
|
||||
return HERR_ARCHIVE_LOAD_MODEL_FAILURE;
|
||||
}
|
||||
InitLandmarkModel(lmkModel);
|
||||
@@ -379,22 +384,25 @@ int FaceTrackModule::Configuration(inspire::InspireArchive &archive, const std::
|
||||
return HERR_ARCHIVE_LOAD_MODEL_FAILURE;
|
||||
}
|
||||
InitRNetModel(rnetModel);
|
||||
|
||||
// Initialize the pose quality model
|
||||
InspireModel pquModel;
|
||||
ret = archive.LoadModel("pose_quality", pquModel);
|
||||
if (ret != SARC_SUCCESS) {
|
||||
INSPIRE_LOGE("Load %s error: %d", "pose_quality", ret);
|
||||
return HERR_ARCHIVE_LOAD_MODEL_FAILURE;
|
||||
if (enable_face_pose_and_quality) {
|
||||
// Initialize the pose quality model
|
||||
InspireModel pquModel;
|
||||
ret = archive.LoadModel("pose_quality", pquModel);
|
||||
if (ret != SARC_SUCCESS) {
|
||||
INSPIRE_LOGE("Load %s error: %d", "pose_quality", ret);
|
||||
return HERR_ARCHIVE_LOAD_MODEL_FAILURE;
|
||||
}
|
||||
InitFacePoseAndQualityModel(pquModel);
|
||||
}
|
||||
InitFacePoseModel(pquModel);
|
||||
|
||||
m_landmark_crop_ratio_ = m_landmark_param_->expansion_scale;
|
||||
m_multiscale_landmark_scales_ = GenerateCropScales(m_landmark_crop_ratio_, m_multiscale_landmark_loop_num_);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FaceTrackModule::InitLandmarkModel(InspireModel &model) {
|
||||
m_landmark_predictor_ = std::make_shared<FaceLandmarkAdapt>(112);
|
||||
auto ret = m_landmark_predictor_->loadData(model, model.modelType);
|
||||
m_landmark_predictor_ =
|
||||
std::make_shared<FaceLandmarkAdapt>(m_landmark_param_->input_size, m_landmark_param_->normalization_mode == "CenterScaling");
|
||||
auto ret = m_landmark_predictor_->LoadData(model, model.modelType);
|
||||
if (ret != InferenceWrapper::WrapperOk) {
|
||||
return HERR_ARCHIVE_LOAD_FAILURE;
|
||||
}
|
||||
@@ -406,7 +414,7 @@ int FaceTrackModule::InitDetectModel(InspireModel &model) {
|
||||
input_size = model.Config().get<std::vector<int>>("input_size");
|
||||
|
||||
m_face_detector_ = std::make_shared<FaceDetectAdapt>(input_size[0]);
|
||||
auto ret = m_face_detector_->loadData(model, model.modelType, false);
|
||||
auto ret = m_face_detector_->LoadData(model, model.modelType, false);
|
||||
if (ret != InferenceWrapper::WrapperOk) {
|
||||
return HERR_ARCHIVE_LOAD_FAILURE;
|
||||
}
|
||||
@@ -415,16 +423,16 @@ int FaceTrackModule::InitDetectModel(InspireModel &model) {
|
||||
|
||||
int FaceTrackModule::InitRNetModel(InspireModel &model) {
|
||||
m_refine_net_ = std::make_shared<RNetAdapt>();
|
||||
auto ret = m_refine_net_->loadData(model, model.modelType);
|
||||
auto ret = m_refine_net_->LoadData(model, model.modelType);
|
||||
if (ret != InferenceWrapper::WrapperOk) {
|
||||
return HERR_ARCHIVE_LOAD_FAILURE;
|
||||
}
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int FaceTrackModule::InitFacePoseModel(InspireModel &model) {
|
||||
int FaceTrackModule::InitFacePoseAndQualityModel(InspireModel &model) {
|
||||
m_face_quality_ = std::make_shared<FacePoseQualityAdapt>();
|
||||
auto ret = m_face_quality_->loadData(model, model.modelType);
|
||||
auto ret = m_face_quality_->LoadData(model, model.modelType);
|
||||
if (ret != InferenceWrapper::WrapperOk) {
|
||||
return HERR_ARCHIVE_LOAD_FAILURE;
|
||||
}
|
||||
@@ -441,35 +449,46 @@ void FaceTrackModule::SetMinimumFacePxSize(float value) {
|
||||
|
||||
void FaceTrackModule::SetTrackPreviewSize(int preview_size) {
|
||||
track_preview_size_ = preview_size;
|
||||
if (track_preview_size_ == -1) {
|
||||
track_preview_size_ = m_face_detector_->GetInputSize();
|
||||
} else if (track_preview_size_ < 192) {
|
||||
INSPIRE_LOGW("Track preview size %d is less than the minimum input size %d", track_preview_size_, 192);
|
||||
track_preview_size_ = 192;
|
||||
}
|
||||
}
|
||||
|
||||
std::string FaceTrackModule::ChoiceMultiLevelDetectModel(const int32_t pixel_size) {
|
||||
const int32_t supported_sizes[] = {160, 320, 640};
|
||||
const std::string scheme_names[] = {"face_detect_160", "face_detect_320", "face_detect_640"};
|
||||
const int32_t num_sizes = sizeof(supported_sizes) / sizeof(supported_sizes[0]);
|
||||
int32_t FaceTrackModule::GetTrackPreviewSize() const {
|
||||
return track_preview_size_;
|
||||
}
|
||||
|
||||
std::string FaceTrackModule::ChoiceMultiLevelDetectModel(const int32_t pixel_size, int32_t &final_size) {
|
||||
const auto face_detect_pixel_list = Launch::GetInstance()->GetFaceDetectPixelList();
|
||||
const auto face_detect_model_list = Launch::GetInstance()->GetFaceDetectModelList();
|
||||
const int32_t num_sizes = face_detect_pixel_list.size();
|
||||
if (pixel_size == -1) {
|
||||
return scheme_names[1];
|
||||
final_size = face_detect_pixel_list[1];
|
||||
return face_detect_model_list[1];
|
||||
}
|
||||
|
||||
// Check for exact match
|
||||
for (int i = 0; i < num_sizes; ++i) {
|
||||
if (pixel_size == supported_sizes[i]) {
|
||||
return scheme_names[i];
|
||||
if (pixel_size == face_detect_pixel_list[i]) {
|
||||
final_size = face_detect_pixel_list[i];
|
||||
return face_detect_model_list[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Find the closest match
|
||||
int32_t closest_size = supported_sizes[0];
|
||||
std::string closest_scheme = scheme_names[0];
|
||||
int32_t min_diff = std::abs(pixel_size - supported_sizes[0]);
|
||||
int32_t closest_size = face_detect_pixel_list[0];
|
||||
std::string closest_scheme = face_detect_model_list[0];
|
||||
int32_t min_diff = std::abs(pixel_size - face_detect_pixel_list[0]);
|
||||
|
||||
for (int i = 1; i < num_sizes; ++i) {
|
||||
int32_t diff = std::abs(pixel_size - supported_sizes[i]);
|
||||
int32_t diff = std::abs(pixel_size - face_detect_pixel_list[i]);
|
||||
if (diff < min_diff) {
|
||||
min_diff = diff;
|
||||
closest_size = supported_sizes[i];
|
||||
closest_scheme = scheme_names[i];
|
||||
closest_size = face_detect_pixel_list[i];
|
||||
closest_scheme = face_detect_model_list[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,6 +496,7 @@ std::string FaceTrackModule::ChoiceMultiLevelDetectModel(const int32_t pixel_siz
|
||||
"Input pixel size %d is not supported. Choosing the closest scheme: %s closest_scheme for "
|
||||
"size %d.",
|
||||
pixel_size, closest_scheme.c_str(), closest_size);
|
||||
final_size = closest_size;
|
||||
|
||||
return closest_scheme;
|
||||
}
|
||||
@@ -497,4 +517,13 @@ void FaceTrackModule::SetTrackModeDetectInterval(int value) {
|
||||
detection_interval_ = value;
|
||||
}
|
||||
|
||||
void FaceTrackModule::SetMultiscaleLandmarkLoop(int value) {
|
||||
m_multiscale_landmark_loop_num_ = value;
|
||||
m_multiscale_landmark_scales_ = GenerateCropScales(m_landmark_crop_ratio_, m_multiscale_landmark_loop_num_);
|
||||
}
|
||||
|
||||
int32_t FaceTrackModule::GetDebugPreviewImageSize() const {
|
||||
return m_debug_preview_image_size_;
|
||||
}
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
@@ -8,26 +8,17 @@
|
||||
#include <iostream>
|
||||
#include "face_detect/face_detect_adapt.h"
|
||||
#include "face_detect/rnet_adapt.h"
|
||||
#include "landmark/face_landmark_adapt.h"
|
||||
#include "landmark/all.h"
|
||||
#include "common/face_info/face_object_internal.h"
|
||||
#include "middleware/inspirecv_image_process.h"
|
||||
#include "frame_process.h"
|
||||
#include "quality/face_pose_quality_adapt.h"
|
||||
#include "middleware/model_archive/inspire_archive.h"
|
||||
#include "tracker_optional/bytetrack/BYTETracker.h"
|
||||
#include <data_type.h>
|
||||
#include "landmark/landmark_param.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
/**
|
||||
* @enum DetectMode
|
||||
* @brief Enumeration for different detection modes.
|
||||
*/
|
||||
enum DetectModuleMode {
|
||||
DETECT_MODE_ALWAYS_DETECT = 0, ///< Detection mode: Always detect
|
||||
DETECT_MODE_LIGHT_TRACK, ///< Detection mode: Light face track
|
||||
DETECT_MODE_TRACK_BY_DETECT, ///< Detection mode: Tracking by detection
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @class FaceTrack
|
||||
* @brief Class for tracking faces in video streams.
|
||||
@@ -44,7 +35,7 @@ public:
|
||||
* @param track_preview_size Size of the preview for tracking.
|
||||
* @param dynamic_detection_input_level Change the detector input size.
|
||||
*/
|
||||
explicit FaceTrackModule(DetectModuleMode mode, int max_detected_faces = 1, int detection_interval = 20, int track_preview_size = 192,
|
||||
explicit FaceTrackModule(DetectModuleMode mode, int max_detected_faces = 1, int detection_interval = 20, int track_preview_size = -1,
|
||||
int dynamic_detection_input_level = -1, int TbD_mode_fps = 30, bool detect_mode_landmark = true);
|
||||
|
||||
/**
|
||||
@@ -53,20 +44,26 @@ public:
|
||||
* @param expansion_path Expand the path if you need it.
|
||||
* @return int Status of the configuration.
|
||||
*/
|
||||
int Configuration(InspireArchive &archive, const std::string &expansion_path = "");
|
||||
int Configuration(InspireArchive &archive, const std::string &expansion_path = "", bool enable_face_pose_and_quality = false);
|
||||
|
||||
/**
|
||||
* @brief Updates the video stream for face tracking.
|
||||
* @param image Camera stream to process.
|
||||
* @param is_detect Flag to enable/disable face detection.
|
||||
*/
|
||||
void UpdateStream(inspirecv::InspireImageProcess &image);
|
||||
void UpdateStream(inspirecv::FrameProcess &image);
|
||||
|
||||
/**
|
||||
* @brief Sets the preview size for tracking.
|
||||
* @param preview_size Size of the preview for tracking.
|
||||
*/
|
||||
void SetTrackPreviewSize(int preview_size = 192);
|
||||
void SetTrackPreviewSize(int preview_size = -1);
|
||||
|
||||
/**
|
||||
* @brief Gets the preview size for tracking.
|
||||
* @return Size of the preview for tracking.
|
||||
*/
|
||||
int32_t GetTrackPreviewSize() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -79,13 +76,20 @@ private:
|
||||
void SparseLandmarkPredict(const inspirecv::Image &raw_face_crop, std::vector<inspirecv::Point2f> &landmarks_output, float &score,
|
||||
float size = 112.0);
|
||||
|
||||
/**
|
||||
* @brief Predicts the tracking score for a cropped face image.
|
||||
* @param raw_face_crop Cropped face image.
|
||||
* @return float Tracking score.
|
||||
*/
|
||||
float PredictTrackScore(const inspirecv::Image &raw_face_crop);
|
||||
|
||||
/**
|
||||
* @brief Tracks a face in the given image stream.
|
||||
* @param image Camera stream containing the face.
|
||||
* @param face FaceObject to be tracked.
|
||||
* @return bool Status of face tracking.
|
||||
*/
|
||||
bool TrackFace(inspirecv::InspireImageProcess &image, FaceObjectInternal &face);
|
||||
bool TrackFace(inspirecv::FrameProcess &image, FaceObjectInternal &face);
|
||||
|
||||
/**
|
||||
* @brief Blacks out the region specified in the image for tracking.
|
||||
@@ -129,18 +133,18 @@ private:
|
||||
int InitRNetModel(InspireModel &model);
|
||||
|
||||
/**
|
||||
* @brief Initializes the face pose estimation model.
|
||||
* @param model Pointer to the face pose model to be initialized.
|
||||
* @brief Initializes the face pose and quality estimation model.
|
||||
* @param model Pointer to the face pose and quality model to be initialized.
|
||||
* @return int Status of the initialization process. Returns 0 for success.
|
||||
*/
|
||||
int InitFacePoseModel(InspireModel &model);
|
||||
int InitFacePoseAndQualityModel(InspireModel &model);
|
||||
|
||||
/**
|
||||
* @brief Select the detection model scheme to be used according to the input pixel level.
|
||||
* @param pixel_size Currently, only 160, 320, and 640 pixel sizes are supported.
|
||||
* @return Return the corresponding scheme name, only ”face_detect_160”, ”face_detect_320”, ”face_detect_640” are supported.
|
||||
*/
|
||||
std::string ChoiceMultiLevelDetectModel(const int32_t pixel_size);
|
||||
std::string ChoiceMultiLevelDetectModel(const int32_t pixel_size, int32_t &final_size);
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -177,9 +181,18 @@ public:
|
||||
*/
|
||||
void SetTrackModeDetectInterval(int value);
|
||||
|
||||
/**
|
||||
* @brief Set the multiscale landmark loop num
|
||||
* @param value Multiscale landmark loop num
|
||||
*/
|
||||
void SetMultiscaleLandmarkLoop(int value);
|
||||
|
||||
public:
|
||||
std::vector<FaceObjectInternal> trackingFace; ///< Vector of FaceObjects currently being tracked.
|
||||
|
||||
public:
|
||||
int32_t GetDebugPreviewImageSize() const;
|
||||
|
||||
private:
|
||||
const int max_detected_faces_; ///< Maximum number of faces to detect.
|
||||
std::vector<FaceObjectInternal> candidate_faces_; ///< Vector of candidate FaceObjects for tracking.
|
||||
@@ -189,6 +202,10 @@ private:
|
||||
int track_preview_size_; ///< Size of the tracking preview.
|
||||
int filter_minimum_face_px_size = 0; ///< Minimum face pixel allowed to be retained (take the edge with the smallest Rect).
|
||||
|
||||
private:
|
||||
// Debug cache
|
||||
int32_t m_debug_preview_image_size_{0}; ///< Debug preview image size
|
||||
|
||||
private:
|
||||
std::shared_ptr<FaceDetectAdapt> m_face_detector_; ///< Shared pointer to the face detector.
|
||||
std::shared_ptr<FaceLandmarkAdapt> m_landmark_predictor_; ///< Shared pointer to the landmark predictor.
|
||||
@@ -212,6 +229,14 @@ private:
|
||||
int m_track_mode_num_smooth_cache_frame_ = 5; ///< Track mode number of smooth cache frame
|
||||
|
||||
float m_track_mode_smooth_ratio_ = 0.05; ///< Track mode smooth ratio
|
||||
|
||||
int m_multiscale_landmark_loop_num_ = 1; ///< Multiscale landmark loop num
|
||||
|
||||
float m_landmark_crop_ratio_ = 1.1f;
|
||||
|
||||
std::vector<float> m_multiscale_landmark_scales_;
|
||||
|
||||
std::shared_ptr<LandmarkParam> m_landmark_param_;
|
||||
};
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
@@ -8,5 +8,8 @@
|
||||
|
||||
#include "face_landmark_adapt.h"
|
||||
#include "mean_shape.h"
|
||||
#include "order_of_hyper_landmark.h"
|
||||
#include "face_landmark_adapt.h"
|
||||
#include "landmark_tools.h"
|
||||
|
||||
#endif // INSPIREFACE_LMK_ALL_H
|
||||
|
||||
@@ -12,12 +12,18 @@ std::vector<float> FaceLandmarkAdapt::operator()(const inspirecv::Image& bgr_aff
|
||||
COST_TIME_SIMPLE(FaceLandmarkAdapt);
|
||||
AnyTensorOutputs outputs;
|
||||
Forward(bgr_affine, outputs);
|
||||
const auto& out = outputs[0].second;
|
||||
auto& out = outputs[0].second;
|
||||
if (m_is_center_scaling_) {
|
||||
for (int i = 0; i < out.size(); ++i) {
|
||||
out[i] = (out[i] + 1) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
FaceLandmarkAdapt::FaceLandmarkAdapt(int input_size) : AnyNetAdapter("FaceLandmarkAdapt"), m_input_size_(input_size) {}
|
||||
FaceLandmarkAdapt::FaceLandmarkAdapt(int input_size, bool is_center_scaling)
|
||||
: AnyNetAdapter("FaceLandmarkAdapt"), m_input_size_(input_size), m_is_center_scaling_(is_center_scaling) {}
|
||||
|
||||
int FaceLandmarkAdapt::getInputSize() const {
|
||||
return m_input_size_;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#pragma once
|
||||
#ifndef INSPIRE_FACE_TRACK_MODULE_LANDMARK_FACE_LANDMARK_ADAPT_H
|
||||
#define INSPIRE_FACE_TRACK_MODULE_LANDMARK_FACE_LANDMARK_ADAPT_H
|
||||
#include "../../data_type.h"
|
||||
#include "data_type.h"
|
||||
#include "middleware/any_net_adapter.h"
|
||||
|
||||
namespace inspire {
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
* @brief Constructor for the FaceLandmark class.
|
||||
* @param input_size The size of the input image for the neural network.
|
||||
*/
|
||||
explicit FaceLandmarkAdapt(int input_size = 112);
|
||||
explicit FaceLandmarkAdapt(int input_size = 112, bool is_center_scaling = false);
|
||||
|
||||
/**
|
||||
* @brief Gets the input size for the neural network model.
|
||||
@@ -38,18 +38,12 @@ public:
|
||||
int getInputSize() const;
|
||||
|
||||
public:
|
||||
const static int LEFT_EYE_CENTER = 67; ///< Landmark index for the center of the left eye.
|
||||
const static int RIGHT_EYE_CENTER = 68; ///< Landmark index for the center of the right eye.
|
||||
const static int NOSE_CORNER = 100; ///< Landmark index for the tip of the nose.
|
||||
const static int MOUTH_LEFT_CORNER = 104; ///< Landmark index for the left corner of the mouth.
|
||||
const static int MOUTH_RIGHT_CORNER = 105; ///< Landmark index for the right corner of the mouth.
|
||||
const static int MOUTH_LOWER = 84; ///< Landmark index for the lower corner of the mouth.
|
||||
const static int MOUTH_UPPER = 87; ///< Landmark index for the upper corner of the mouth.
|
||||
|
||||
const static int NUM_OF_LANDMARK = 106; ///< Total number of landmarks detected.
|
||||
|
||||
private:
|
||||
const int m_input_size_; ///< The input size for the neural network model.
|
||||
bool m_is_center_scaling_; ///< Whether to use center scaling.
|
||||
};
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
#ifndef INSPIRE_LANDMARK_PARAM_H
|
||||
#define INSPIRE_LANDMARK_PARAM_H
|
||||
|
||||
#include "data_type.h"
|
||||
#include "yaml-cpp/yaml.h"
|
||||
#include "mean_shape.h"
|
||||
#include "log.h"
|
||||
#include "landmark_tools.h"
|
||||
#include "order_of_hyper_landmark.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
typedef struct {
|
||||
int32_t left_eye_center = 67;
|
||||
int32_t right_eye_center = 68;
|
||||
int32_t nose_corner = 100;
|
||||
int32_t mouth_left_corner = 104;
|
||||
int32_t mouth_right_corner = 105;
|
||||
int32_t mouth_lower = 84;
|
||||
int32_t mouth_upper = 87;
|
||||
std::vector<int32_t> left_eye_region = HLMK_LEFT_EYE_POINTS_INDEX;
|
||||
std::vector<int32_t> right_eye_region = HLMK_RIGHT_EYE_POINTS_INDEX;
|
||||
} SemanticIndex;
|
||||
|
||||
class INSPIRE_API LandmarkParam {
|
||||
public:
|
||||
LandmarkParam(const YAML::Node &config) {
|
||||
LoadDefaultMeshShape();
|
||||
if (!config) {
|
||||
} else {
|
||||
// TODO: parse config
|
||||
m_is_available_ = true;
|
||||
}
|
||||
m_table_ = config;
|
||||
}
|
||||
|
||||
void LoadDefaultMeshShape() {
|
||||
mean_shape_points.clear();
|
||||
mean_shape_points.resize(num_of_landmark);
|
||||
for (int k = 0; k < num_of_landmark; k++) {
|
||||
mean_shape_points[k].SetX(HYPLMK_MESH_SHAPE[k * 2]);
|
||||
mean_shape_points[k].SetY(HYPLMK_MESH_SHAPE[k * 2 + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
bool ReLoad(const std::string &name) {
|
||||
if (!m_is_available_) {
|
||||
landmark_engine_name = name;
|
||||
return true;
|
||||
}
|
||||
// parse config
|
||||
auto landmark_table = m_table_[name];
|
||||
if (!landmark_table) {
|
||||
INSPIRE_LOGE("landmark config not found: %s", name.c_str());
|
||||
return false;
|
||||
}
|
||||
num_of_landmark = landmark_table["num_of_landmark"].as<int>();
|
||||
expansion_scale = landmark_table["expansion_scale"].as<float>();
|
||||
input_size = landmark_table["input_size"].as<int>();
|
||||
auto semanic_index = landmark_table["semantic_index"];
|
||||
if (!semanic_index) {
|
||||
INSPIRE_LOGE("semantic_index not found: %s", name.c_str());
|
||||
return false;
|
||||
}
|
||||
semantic_index.left_eye_center = semanic_index["left_eye_center"].as<int>();
|
||||
semantic_index.right_eye_center = semanic_index["right_eye_center"].as<int>();
|
||||
semantic_index.nose_corner = semanic_index["nose_corner"].as<int>();
|
||||
semantic_index.mouth_left_corner = semanic_index["mouth_left_corner"].as<int>();
|
||||
semantic_index.mouth_right_corner = semanic_index["mouth_right_corner"].as<int>();
|
||||
semantic_index.mouth_lower = semanic_index["mouth_lower"].as<int>();
|
||||
semantic_index.mouth_upper = semanic_index["mouth_upper"].as<int>();
|
||||
auto left_eye_region = semanic_index["left_eye_region"];
|
||||
if (left_eye_region) {
|
||||
semantic_index.left_eye_region = left_eye_region.as<std::vector<int>>();
|
||||
}
|
||||
auto right_eye_region = semanic_index["right_eye_region"];
|
||||
if (right_eye_region) {
|
||||
semantic_index.right_eye_region = right_eye_region.as<std::vector<int>>();
|
||||
}
|
||||
auto mesh_shape = landmark_table["mesh_shape"];
|
||||
if (mesh_shape.size() > 0) {
|
||||
std::vector<float> mesh_shape_data = mesh_shape.as<std::vector<float>>();
|
||||
mean_shape_points.clear();
|
||||
mean_shape_points.resize(num_of_landmark);
|
||||
if (mesh_shape_data.size() == num_of_landmark * 2) {
|
||||
for (int i = 0; i < num_of_landmark; i++) {
|
||||
mean_shape_points[i].SetX(mesh_shape_data[i * 2]);
|
||||
mean_shape_points[i].SetY(mesh_shape_data[i * 2 + 1]);
|
||||
}
|
||||
mean_shape_points = LandmarkCropped(mean_shape_points);
|
||||
// auto img = inspirecv::Image::Create(192, 192, 3);
|
||||
// img.Fill(0);
|
||||
// for (int i = 0; i < num_of_landmark; i++) {
|
||||
// auto point = mean_shape_points[i];
|
||||
// img.DrawCircle(inspirecv::Point2i(point.GetX(), point.GetY()), 2, inspirecv::Color::Red);
|
||||
// }
|
||||
// img.Show("mean_shape");
|
||||
} else {
|
||||
INSPIRE_LOGE("norm_track_index_from_112x size is not equal to num_of_landmark: %s", name.c_str());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LoadDefaultMeshShape();
|
||||
}
|
||||
normalization_mode = landmark_table["normalization_mode"].as<std::string>();
|
||||
landmark_engine_name = name;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
int num_of_landmark{106};
|
||||
float expansion_scale{1.1f};
|
||||
int input_size{112};
|
||||
std::vector<inspirecv::Point2f> mean_shape_points;
|
||||
SemanticIndex semantic_index;
|
||||
std::string landmark_engine_name{"landmark"};
|
||||
std::string normalization_mode{"MinMax"};
|
||||
|
||||
private:
|
||||
YAML::Node m_table_;
|
||||
bool m_is_available_{false};
|
||||
};
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
#endif // INSPIRE_LANDMARK_PARAM_H
|
||||
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* Created by Jingyu Yan
|
||||
* @date 2025-04-26
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef INSPIRE_FACE_TRACK_MODULE_LANDMARK_TOOLS_H
|
||||
#define INSPIRE_FACE_TRACK_MODULE_LANDMARK_TOOLS_H
|
||||
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <inspirecv/inspirecv.h>
|
||||
|
||||
namespace inspire {
|
||||
|
||||
// Generate crop scales
|
||||
inline std::vector<float> GenerateCropScales(float start_scale, int N) {
|
||||
std::vector<float> result;
|
||||
if (N <= 0)
|
||||
return result;
|
||||
|
||||
result.push_back(start_scale);
|
||||
|
||||
float delta_step = 0.02f; // Initial step size
|
||||
int direction = -1; // First decrease
|
||||
int expand_count = 1; // Current expansion count
|
||||
|
||||
for (int i = 1; i < N; ++i) {
|
||||
// The step size increases slightly every two expansions, e.g. 0.02 -> 0.04 -> 0.06
|
||||
float current_delta = delta_step * (static_cast<float>((expand_count + 1) / 2));
|
||||
|
||||
float new_scale = start_scale + direction * current_delta;
|
||||
|
||||
// Keep 5 decimal places
|
||||
new_scale = std::round(new_scale * 100000.0f) / 100000.0f;
|
||||
|
||||
result.push_back(new_scale);
|
||||
|
||||
direction *= -1; // Alternating positive and negative
|
||||
expand_count++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline inspirecv::TransformMatrix ScaleAffineMatrixPreserveCenter(const inspirecv::TransformMatrix& affine, float scale, int output_size = 112) {
|
||||
// The center point in the output image is (cx, cy).
|
||||
float cx = output_size / 2.0f;
|
||||
float cy = output_size / 2.0f;
|
||||
|
||||
// 1. Obtain the position of the current center point in the original image (inverse affine transformation)
|
||||
inspirecv::TransformMatrix inv_affine = affine.GetInverse();
|
||||
float center_x = inv_affine.Get(0, 0) * cx + inv_affine.Get(0, 1) * cy + inv_affine.Get(0, 2);
|
||||
float center_y = inv_affine.Get(1, 0) * cx + inv_affine.Get(1, 1) * cy + inv_affine.Get(1, 2);
|
||||
|
||||
// 2. Create a new scaling matrix (note that the scale value should be reduced → to "expand the cropping area")
|
||||
float inv_scale = 1.0f / scale;
|
||||
float new_a11 = affine.Get(0, 0) * inv_scale;
|
||||
float new_a12 = affine.Get(0, 1) * inv_scale;
|
||||
float new_a21 = affine.Get(1, 0) * inv_scale;
|
||||
float new_a22 = affine.Get(1, 1) * inv_scale;
|
||||
|
||||
// 3. Calculate the new offset to ensure that the center of the scaled image is still mapped to (cx, cy)
|
||||
float new_b1 = cx - (new_a11 * center_x + new_a12 * center_y);
|
||||
float new_b2 = cy - (new_a21 * center_x + new_a22 * center_y);
|
||||
|
||||
return inspirecv::TransformMatrix::Create(new_a11, new_a12, new_b1, new_a21, new_a22, new_b2);
|
||||
}
|
||||
|
||||
inline std::vector<inspirecv::Point2f> MultiFrameLandmarkMean(const std::vector<std::vector<inspirecv::Point2f>>& points) {
|
||||
std::vector<inspirecv::Point2f> mean_points;
|
||||
|
||||
if (points.empty()) {
|
||||
return mean_points;
|
||||
}
|
||||
|
||||
if (points.size() == 1) {
|
||||
return points[0];
|
||||
}
|
||||
|
||||
size_t num_frames = points.size();
|
||||
size_t num_points = points[0].size();
|
||||
|
||||
// Initialize to 0
|
||||
mean_points.resize(num_points, inspirecv::Point2f(0.0f, 0.0f));
|
||||
|
||||
// Accumulate the coordinates of each point
|
||||
for (const auto& frame : points) {
|
||||
if (frame.size() != num_points)
|
||||
continue; // skip invalid frame size
|
||||
|
||||
for (size_t i = 0; i < num_points; ++i) {
|
||||
mean_points[i].SetX(mean_points[i].GetX() + frame[i].GetX());
|
||||
mean_points[i].SetY(mean_points[i].GetY() + frame[i].GetY());
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the average
|
||||
for (auto& pt : mean_points) {
|
||||
pt.SetX(pt.GetX() / static_cast<float>(num_frames));
|
||||
pt.SetY(pt.GetY() / static_cast<float>(num_frames));
|
||||
}
|
||||
|
||||
return mean_points;
|
||||
}
|
||||
|
||||
inline std::vector<inspirecv::Point2f> LandmarkCropped(const std::vector<inspirecv::Point2f>& points, int output_size = 192) {
|
||||
inspirecv::Rect2f rect = inspirecv::MinBoundingRect(points);
|
||||
|
||||
// Calculate the scale
|
||||
float scale = output_size / std::max(rect.GetWidth(), rect.GetHeight());
|
||||
|
||||
// Create the result vector and scale each point
|
||||
std::vector<inspirecv::Point2f> result;
|
||||
result.reserve(points.size());
|
||||
for (const auto& pt : points) {
|
||||
// Translate to the origin (subtract the top-left corner coordinates), then scale
|
||||
result.push_back(inspirecv::Point2f((pt.GetX() - rect.GetX()) * scale, (pt.GetY() - rect.GetY()) * scale));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
#endif // INSPIRE_FACE_TRACK_MODULE_LANDMARK_TOOLS_H
|
||||
@@ -6,7 +6,8 @@
|
||||
#ifndef INSPIREFACE_MEAN_SHAPE_H
|
||||
#define INSPIREFACE_MEAN_SHAPE_H
|
||||
|
||||
static const float mean_shape[212] = {
|
||||
// The mean shape of the hyperlandmarkv2 model
|
||||
static const float HYPLMK_MESH_SHAPE[212] = {
|
||||
108.38947968990857, 25.872507850440652, 107.83061691599185, 32.740667888401575, 107.39614893771035, 39.61981246234094, 106.91122964874452,
|
||||
46.49403692042678, 106.2010288700007, 53.34741525135486, 105.09197874965457, 60.15582154225913, 103.42464830472807, 66.83258235371402,
|
||||
101.06766895276914, 73.25011372147983, 97.9868709520959, 79.30544663628336, 94.26571910204586, 84.93503057741032, 90.00562918536812,
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
|
||||
namespace inspire {
|
||||
|
||||
// HyperLandmark left eye contour points sequence of dense facial landmarks.
|
||||
// HyperLandmarkV2 left eye contour points sequence of dense facial landmarks.
|
||||
const std::vector<int> HLMK_LEFT_EYE_POINTS_INDEX = {51, 52, 53, 54, 55, 56, 57, 58};
|
||||
|
||||
// HyperLandmark right eye contour points sequence of dense facial landmarks.
|
||||
// HyperLandmarkV2 right eye contour points sequence of dense facial landmarks.
|
||||
const std::vector<int> HLMK_RIGHT_EYE_POINTS_INDEX = {59, 60, 61, 62, 63, 64, 65, 66};
|
||||
|
||||
} // namespace inspire
|
||||
@@ -13,7 +13,14 @@ FacePoseQualityAdapt::FacePoseQualityAdapt() : AnyNetAdapter("FacePoseQuality")
|
||||
FacePoseQualityAdaptResult FacePoseQualityAdapt::operator()(const inspirecv::Image &img) {
|
||||
FacePoseQualityAdaptResult res;
|
||||
AnyTensorOutputs outputs;
|
||||
Forward(img, outputs);
|
||||
if (img.Width() != INPUT_WIDTH || img.Height() != INPUT_HEIGHT) {
|
||||
uint8_t* resized_data = nullptr;
|
||||
m_processor_->Resize(img.Data(), img.Width(), img.Height(), img.Channels(), &resized_data, INPUT_WIDTH, INPUT_HEIGHT);
|
||||
auto resized = inspirecv::Image::Create(INPUT_WIDTH, INPUT_HEIGHT, img.Channels(), resized_data, false);
|
||||
Forward(resized, outputs);
|
||||
} else {
|
||||
Forward(img, outputs);
|
||||
}
|
||||
const auto &output = outputs[0].second;
|
||||
res.pitch = output[0] * 90;
|
||||
res.yaw = output[1] * 90;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef INSPIRE_FACE_TRACK_MODULE_QUALITY_FACE_POSE_QUALITY_ADAPT_H
|
||||
#define INSPIRE_FACE_TRACK_MODULE_QUALITY_FACE_POSE_QUALITY_ADAPT_H
|
||||
|
||||
#include "../../data_type.h"
|
||||
#include "data_type.h"
|
||||
#include "middleware/any_net_adapter.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
@@ -1 +1 @@
|
||||
InspireFace Version: 1.2.0
|
||||
InspireFace Version: 1.2.1
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(InspireFaceSample)
|
||||
|
||||
option(ISF_BUILD_SAMPLE_CLUTTERED "Whether to compile the cluttered sample program (debug code during development)" OFF)
|
||||
option(ISF_BUILD_SAMPLE_INTERNAL "Whether to compile the internal sample program (debug code during development)" OFF)
|
||||
|
||||
include_directories(${SRC_DIR})
|
||||
include_directories(${SRC_DIR}/inspireface/c_api)
|
||||
include_directories(${SRC_DIR}/inspireface/include)
|
||||
|
||||
if (ISF_ENABLE_RKNN AND ISF_RKNPU_MAJOR STREQUAL "rknpu1")
|
||||
set(ISF_RKNN_API_LIB ${ISF_THIRD_PARTY_DIR}/inspireface-precompile-lite/rknn/${ISF_RKNPU_MAJOR}/runtime/${ISF_RK_DEVICE_TYPE}/Linux/librknn_api/${CPU_ARCH}/)
|
||||
@@ -24,75 +26,129 @@ if (ISF_ENABLE_RKNN AND ISF_RKNPU_MAJOR STREQUAL "rknpu2" AND ISF_RK_COMPILER_TY
|
||||
set(ext rknnrt dl)
|
||||
endif ()
|
||||
|
||||
add_executable(Leak api/leak.cpp)
|
||||
add_executable(Leak api/leak.c)
|
||||
target_link_libraries(Leak InspireFace ${ext})
|
||||
set_target_properties(Leak PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/api/"
|
||||
)
|
||||
|
||||
# # Examples of face detection and tracking
|
||||
add_executable(FaceTrackSample api/sample_face_track.cpp)
|
||||
add_executable(FaceTrackSample api/sample_face_track.c)
|
||||
target_link_libraries(FaceTrackSample InspireFace ${ext})
|
||||
set_target_properties(FaceTrackSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/api/"
|
||||
)
|
||||
|
||||
add_executable(FaceTrackBenchmarkSample api/sample_face_track_benchmark.cpp)
|
||||
add_executable(FaceTrackBenchmarkSample api/sample_face_track_benchmark.c)
|
||||
target_link_libraries(FaceTrackBenchmarkSample InspireFace ${ext})
|
||||
set_target_properties(FaceTrackBenchmarkSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/api/"
|
||||
)
|
||||
|
||||
# Examples of face recognition
|
||||
add_executable(FaceComparisonSample api/sample_face_comparison.cpp)
|
||||
add_executable(FaceComparisonSample api/sample_face_comparison.c)
|
||||
target_link_libraries(FaceComparisonSample InspireFace ${ext})
|
||||
set_target_properties(FaceComparisonSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/api/"
|
||||
)
|
||||
|
||||
add_executable(FaceFeatureHubSample api/sample_feature_hub.cpp)
|
||||
add_executable(FaceFeatureHubSample api/sample_feature_hub.c)
|
||||
target_link_libraries(FaceFeatureHubSample InspireFace ${ext})
|
||||
set_target_properties(FaceFeatureHubSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/api/"
|
||||
)
|
||||
|
||||
|
||||
add_executable(FaceLoadReloadSample api/sample_load_reload.cpp)
|
||||
add_executable(FaceLoadReloadSample api/sample_load_reload.c)
|
||||
target_link_libraries(FaceLoadReloadSample InspireFace ${ext})
|
||||
set_target_properties(FaceLoadReloadSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/api/"
|
||||
)
|
||||
|
||||
add_executable(FaceTrackerSample source/tracker_sample.cpp)
|
||||
target_link_libraries(FaceTrackerSample InspireFace ${ext})
|
||||
set_target_properties(FaceTrackerSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
add_executable(CppResourcePoolSample api/sample_cpp_resource_pool.cpp)
|
||||
target_link_libraries(CppResourcePoolSample InspireFace ${ext})
|
||||
set_target_properties(CppResourcePoolSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/api/"
|
||||
)
|
||||
|
||||
add_executable(ExpansionLoadSample source/expansion_load.cpp)
|
||||
target_link_libraries(ExpansionLoadSample InspireFace ${ext})
|
||||
set_target_properties(ExpansionLoadSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
add_executable(FaceCrudSample api/sample_face_crud.c)
|
||||
target_link_libraries(FaceCrudSample InspireFace ${ext})
|
||||
set_target_properties(FaceCrudSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/api/"
|
||||
)
|
||||
|
||||
add_executable(FaceTrackPipelineSample source/tracker_pipeline.cpp)
|
||||
target_link_libraries(FaceTrackPipelineSample InspireFace ${ext})
|
||||
set_target_properties(FaceTrackPipelineSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
add_executable(FeatureHubPersistenceSample api/sample_feature_hub_persistence.c)
|
||||
target_link_libraries(FeatureHubPersistenceSample InspireFace ${ext})
|
||||
set_target_properties(FeatureHubPersistenceSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/api/"
|
||||
)
|
||||
|
||||
add_executable(FeatureHubSample source/feature_hub_sample.cpp)
|
||||
target_link_libraries(FeatureHubSample InspireFace ${ext})
|
||||
set_target_properties(FeatureHubSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
|
||||
|
||||
# --- C++ API ---
|
||||
|
||||
add_executable(CppSessionSample cpp_api/cpp_sample_face_track.cpp)
|
||||
target_link_libraries(CppSessionSample InspireFace ${ext})
|
||||
set_target_properties(CppSessionSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cpp_api/"
|
||||
)
|
||||
|
||||
add_executable(LandmarkSample source/landmark_sample.cpp)
|
||||
target_link_libraries(LandmarkSample InspireFace ${ext})
|
||||
set_target_properties(LandmarkSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
add_executable(CppFaceComparisonSample cpp_api/cpp_sample_face_comparison.cpp)
|
||||
target_link_libraries(CppFaceComparisonSample InspireFace ${ext})
|
||||
set_target_properties(CppFaceComparisonSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cpp_api/"
|
||||
)
|
||||
|
||||
add_executable(CppFaceCrudSample cpp_api/cpp_sample_face_crud.cpp)
|
||||
target_link_libraries(CppFaceCrudSample InspireFace ${ext})
|
||||
set_target_properties(CppFaceCrudSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cpp_api/"
|
||||
)
|
||||
|
||||
add_executable(CppSampleAffine cpp_api/cpp_sample_affine.cpp)
|
||||
target_link_libraries(CppSampleAffine InspireFace ${ext})
|
||||
set_target_properties(CppSampleAffine PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cpp_api/"
|
||||
)
|
||||
|
||||
add_executable(CppSampleInspireCV cpp_api/cpp_sample_inspirecv.cpp)
|
||||
target_link_libraries(CppSampleInspireCV InspireFace ${ext})
|
||||
set_target_properties(CppSampleInspireCV PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cpp_api/"
|
||||
)
|
||||
|
||||
if(ISF_BUILD_SAMPLE_INTERNAL)
|
||||
add_executable(FaceTrackerSample source/tracker_sample.cpp)
|
||||
target_link_libraries(FaceTrackerSample InspireFace ${ext})
|
||||
set_target_properties(FaceTrackerSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
)
|
||||
|
||||
add_executable(ExpansionLoadSample source/expansion_load.cpp)
|
||||
target_link_libraries(ExpansionLoadSample InspireFace ${ext})
|
||||
set_target_properties(ExpansionLoadSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
)
|
||||
|
||||
add_executable(FaceTrackPipelineSample source/tracker_pipeline.cpp)
|
||||
target_link_libraries(FaceTrackPipelineSample InspireFace ${ext})
|
||||
set_target_properties(FaceTrackPipelineSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
)
|
||||
|
||||
add_executable(FeatureHubSample source/feature_hub_sample.cpp)
|
||||
target_link_libraries(FeatureHubSample InspireFace ${ext})
|
||||
set_target_properties(FeatureHubSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
)
|
||||
|
||||
add_executable(LandmarkSample source/landmark_sample.cpp)
|
||||
target_link_libraries(LandmarkSample InspireFace ${ext})
|
||||
set_target_properties(LandmarkSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
# Platform watershed
|
||||
if (ISF_BUILD_LINUX_ARM7 OR ISF_BUILD_LINUX_AARCH64)
|
||||
@@ -108,194 +164,194 @@ if(ISF_RK_DEVICE_TYPE STREQUAL "RV1106")
|
||||
add_executable(FaceTrackSampleRV1106 rv1106/face_detect.cpp)
|
||||
target_link_libraries(FaceTrackSampleRV1106 InspireFace ${ext})
|
||||
set_target_properties(FaceTrackSampleRV1106 PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/internal/"
|
||||
)
|
||||
|
||||
add_executable(FaceAttributeSampleRV1106 rv1106/face_attribute.cpp)
|
||||
target_link_libraries(FaceAttributeSampleRV1106 InspireFace ${ext})
|
||||
set_target_properties(FaceAttributeSampleRV1106 PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/internal/"
|
||||
)
|
||||
endif()
|
||||
|
||||
add_executable(NexusImageSample rv1106/rga_image.cpp)
|
||||
target_link_libraries(NexusImageSample InspireFace ${ext})
|
||||
set_target_properties(NexusImageSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/"
|
||||
)
|
||||
set_target_properties(NexusImageSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/internal/"
|
||||
)
|
||||
|
||||
# These sample programs are debugging and testing code left behind by developers during the development process.
|
||||
# They are cluttered and have not been organized, or similar functionalities have already been organized in the standard samples.
|
||||
# You can ignore them.
|
||||
if (ISF_BUILD_SAMPLE_CLUTTERED)
|
||||
if (NOT ISF_BUILD_LINUX_ARM7 AND NOT ISF_BUILD_LINUX_AARCH64)
|
||||
|
||||
# =======================InspireFace Sample===========================
|
||||
add_executable(TrackerSample cluttered/standard/tracker_sample.cpp)
|
||||
target_link_libraries(TrackerSample InspireFace)
|
||||
|
||||
set_target_properties(TrackerSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
|
||||
add_executable(ContextSample cluttered/standard/context_sample.cpp)
|
||||
target_link_libraries(ContextSample InspireFace)
|
||||
|
||||
# These sample programs are debugging and testing code left behind by developers during the development process.
|
||||
# They are cluttered and have not been organized, or similar functionalities have already been organized in the standard samples.
|
||||
# You can ignore them.
|
||||
if (ISF_BUILD_SAMPLE_CLUTTERED)
|
||||
if (NOT ISF_BUILD_LINUX_ARM7 AND NOT ISF_BUILD_LINUX_AARCH64)
|
||||
|
||||
# =======================InspireFace Sample===========================
|
||||
add_executable(TrackerSample cluttered/standard/tracker_sample.cpp)
|
||||
target_link_libraries(TrackerSample InspireFace)
|
||||
|
||||
set_target_properties(TrackerSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
set_target_properties(ContextSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
|
||||
add_executable(ContextSample cluttered/standard/context_sample.cpp)
|
||||
target_link_libraries(ContextSample InspireFace)
|
||||
add_executable(TestSample cluttered/standard/test_sample.cpp)
|
||||
target_link_libraries(TestSample InspireFace)
|
||||
|
||||
set_target_properties(ContextSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
set_target_properties(TestSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
add_executable(NetSample cluttered/standard/net_sample.cpp)
|
||||
target_link_libraries(NetSample InspireFace)
|
||||
|
||||
set_target_properties(NetSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
|
||||
add_executable(TestSample cluttered/standard/test_sample.cpp)
|
||||
target_link_libraries(TestSample InspireFace)
|
||||
add_executable(RecSample cluttered/standard/rec_sample.cpp)
|
||||
target_link_libraries(RecSample InspireFace)
|
||||
|
||||
set_target_properties(TestSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
add_executable(NetSample cluttered/standard/net_sample.cpp)
|
||||
target_link_libraries(NetSample InspireFace)
|
||||
|
||||
set_target_properties(NetSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
set_target_properties(RecSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
|
||||
add_executable(RecSample cluttered/standard/rec_sample.cpp)
|
||||
target_link_libraries(RecSample InspireFace)
|
||||
add_executable(BMSample cluttered/standard/bm_sample.cpp)
|
||||
target_link_libraries(BMSample InspireFace)
|
||||
|
||||
set_target_properties(RecSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
set_target_properties(BMSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
|
||||
add_executable(BMSample cluttered/standard/bm_sample.cpp)
|
||||
target_link_libraries(BMSample InspireFace)
|
||||
else()
|
||||
|
||||
set_target_properties(BMSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
# =======================RK Temporary test category===========================
|
||||
|
||||
if (ISF_ENABLE_RKNN)
|
||||
set(ISF_RKNN_API_LIB ${ISF_THIRD_PARTY_DIR}/${ISF_RKNPU_MAJOR}/runtime/${ISF_RK_DEVICE_TYPE}/Linux/librknn_api/${CPU_ARCH}/)
|
||||
message("Enable RKNN Inference")
|
||||
link_directories(${ISF_RKNN_API_LIB})
|
||||
|
||||
# Face detection
|
||||
add_executable(RKFaceDetSample cluttered/rk_sample/rk_face_det_sample.cpp)
|
||||
target_link_libraries(RKFaceDetSample InspireFace rknn_api dl)
|
||||
|
||||
set_target_properties(RKFaceDetSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
# Simple network test
|
||||
add_executable(RKSimpleNetSample cluttered/rk_sample/rk_simple_net_sample.cpp)
|
||||
target_link_libraries(RKSimpleNetSample InspireFace rknn_api dl)
|
||||
|
||||
set_target_properties(RKSimpleNetSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
# Face recognize
|
||||
add_executable(RKFaceRecSample cluttered/rk_sample/rk_face_recognize_sample.cpp)
|
||||
target_link_libraries(RKFaceRecSample InspireFace rknn_api dl)
|
||||
|
||||
set_target_properties(RKFaceRecSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
# Tracking module
|
||||
add_executable(RKTrackerSample cluttered/rk_sample/rk_tracker_sample.cpp)
|
||||
target_link_libraries(RKTrackerSample InspireFace rknn_api dl)
|
||||
|
||||
set_target_properties(RKTrackerSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
# Debug
|
||||
add_executable(DebugRKRec cluttered/rk_sample/debug_rk_rec.cpp)
|
||||
target_link_libraries(DebugRKRec InspireFace rknn_api dl)
|
||||
|
||||
set_target_properties(DebugRKRec PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
|
||||
else()
|
||||
add_executable(ArchTest cluttered/standard/archive_test.cpp)
|
||||
target_link_libraries(ArchTest InspireFace)
|
||||
|
||||
# =======================RK Temporary test category===========================
|
||||
set_target_properties(ArchTest PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
if (ISF_ENABLE_RKNN)
|
||||
set(ISF_RKNN_API_LIB ${ISF_THIRD_PARTY_DIR}/${ISF_RKNPU_MAJOR}/runtime/${ISF_RK_DEVICE_TYPE}/Linux/librknn_api/${CPU_ARCH}/)
|
||||
message("Enable RKNN Inference")
|
||||
link_directories(${ISF_RKNN_API_LIB})
|
||||
|
||||
# Face detection
|
||||
add_executable(RKFaceDetSample cluttered/rk_sample/rk_face_det_sample.cpp)
|
||||
target_link_libraries(RKFaceDetSample InspireFace rknn_api dl)
|
||||
|
||||
set_target_properties(RKFaceDetSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
# Simple network test
|
||||
add_executable(RKSimpleNetSample cluttered/rk_sample/rk_simple_net_sample.cpp)
|
||||
target_link_libraries(RKSimpleNetSample InspireFace rknn_api dl)
|
||||
|
||||
set_target_properties(RKSimpleNetSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
# Face recognize
|
||||
add_executable(RKFaceRecSample cluttered/rk_sample/rk_face_recognize_sample.cpp)
|
||||
target_link_libraries(RKFaceRecSample InspireFace rknn_api dl)
|
||||
|
||||
set_target_properties(RKFaceRecSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
# Tracking module
|
||||
add_executable(RKTrackerSample cluttered/rk_sample/rk_tracker_sample.cpp)
|
||||
target_link_libraries(RKTrackerSample InspireFace rknn_api dl)
|
||||
|
||||
set_target_properties(RKTrackerSample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
# Debug
|
||||
add_executable(DebugRKRec cluttered/rk_sample/debug_rk_rec.cpp)
|
||||
target_link_libraries(DebugRKRec InspireFace rknn_api dl)
|
||||
|
||||
set_target_properties(DebugRKRec PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
|
||||
add_executable(ArchTest cluttered/standard/archive_test.cpp)
|
||||
target_link_libraries(ArchTest InspireFace)
|
||||
|
||||
set_target_properties(ArchTest PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
# Tracking module
|
||||
add_executable(SQLiteTest cluttered/standard/test_sqlite_sample.cpp)
|
||||
target_link_libraries(SQLiteTest InspireFace)
|
||||
|
||||
# Tracking module
|
||||
add_executable(SQLiteTest cluttered/standard/test_sqlite_sample.cpp)
|
||||
target_link_libraries(SQLiteTest InspireFace)
|
||||
set_target_properties(SQLiteTest PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
set_target_properties(SQLiteTest PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
if (ISF_ENABLE_RKNN)
|
||||
set(DEPEND rknn_api dl)
|
||||
endif ()
|
||||
|
||||
if (ISF_ENABLE_RKNN)
|
||||
set(DEPEND rknn_api dl)
|
||||
endif ()
|
||||
# C_API Demo
|
||||
add_executable(CAPISample cluttered/standard/c_api_sample.cpp)
|
||||
target_link_libraries(CAPISample InspireFace ${DEPEND})
|
||||
|
||||
# C_API Demo
|
||||
add_executable(CAPISample cluttered/standard/c_api_sample.cpp)
|
||||
target_link_libraries(CAPISample InspireFace ${DEPEND})
|
||||
set_target_properties(CAPISample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
set_target_properties(CAPISample PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
# C_API Demo
|
||||
add_executable(LoopTracker cluttered/standard/loop_tracker.cpp)
|
||||
target_link_libraries(LoopTracker InspireFace ${DEPEND})
|
||||
|
||||
# C_API Demo
|
||||
add_executable(LoopTracker cluttered/standard/loop_tracker.cpp)
|
||||
target_link_libraries(LoopTracker InspireFace ${DEPEND})
|
||||
set_target_properties(LoopTracker PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
set_target_properties(LoopTracker PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
add_executable(ArchTracker cluttered/standard/archive_tracker.cpp)
|
||||
target_link_libraries(ArchTracker InspireFace)
|
||||
|
||||
add_executable(ArchTracker cluttered/standard/archive_tracker.cpp)
|
||||
target_link_libraries(ArchTracker InspireFace)
|
||||
set_target_properties(ArchTracker PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
|
||||
set_target_properties(ArchTracker PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
add_executable(ErrorTest cluttered/standard/error_test.cpp)
|
||||
target_link_libraries(ErrorTest InspireFace)
|
||||
|
||||
add_executable(ErrorTest cluttered/standard/error_test.cpp)
|
||||
target_link_libraries(ErrorTest InspireFace)
|
||||
set_target_properties(ErrorTest PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
endif ()
|
||||
|
||||
set_target_properties(ErrorTest PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/sample/cluttered/"
|
||||
)
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
# Print Message
|
||||
message(STATUS ">>>>>>>>>>>>>")
|
||||
message(STATUS "InspireFace Sample:")
|
||||
message(STATUS "\t ISF_BUILD_SAMPLE_CLUTTERED: ${ISF_BUILD_SAMPLE_CLUTTERED}")
|
||||
|
||||
# Install bin
|
||||
# Install c bin
|
||||
install(TARGETS Leak RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/sample)
|
||||
install(TARGETS FaceTrackSample RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/sample)
|
||||
# install(TARGETS FaceTrackSampleCost RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/sample)
|
||||
# install(TARGETS MTFaceTrackSample RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/sample)
|
||||
# install(TARGETS FaceRecognitionSample RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/sample)
|
||||
# install(TARGETS FaceSearchSample RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/sample)
|
||||
install(TARGETS FaceComparisonSample RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/sample)
|
||||
install(TARGETS FaceCrudSample RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/sample)
|
||||
|
||||
# Install cpp bin
|
||||
install(TARGETS CppSessionSample RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/sample)
|
||||
install(TARGETS CppFaceComparisonSample RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/sample)
|
||||
install(TARGETS CppFaceCrudSample RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/sample)
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
* Created by Jingyu Yan
|
||||
* @date 2024-10-01
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
char *n = new char[1024];
|
||||
char *n = malloc(1024);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include <inspireface/include/inspireface/session.h>
|
||||
#include <inspireface/include/inspireface/launch.h>
|
||||
#include <inspireface/middleware/thread/resource_pool.h>
|
||||
#include <inspireface/include/inspireface/spend_timer.h>
|
||||
#include <thread>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 5) {
|
||||
std::cerr << "Usage: " << argv[0] << " <model_path> <image_path> <loop_count> <thread_num>" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string model_path = argv[1];
|
||||
std::string image_path = argv[2];
|
||||
int loop = std::stoi(argv[3]);
|
||||
int thread_num = std::stoi(argv[4]);
|
||||
|
||||
if (thread_num > 10) {
|
||||
std::cerr << "Error: thread_num cannot be greater than 10" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
if (loop < 1000) {
|
||||
std::cerr << "Error: loop count must be at least 1000" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
INSPIREFACE_CONTEXT->Load(model_path);
|
||||
inspirecv::Image image = inspirecv::Image::Create(image_path);
|
||||
inspirecv::FrameProcess process =
|
||||
inspirecv::FrameProcess::Create(image.Data(), image.Height(), image.Width(), inspirecv::BGR, inspirecv::ROTATION_0);
|
||||
|
||||
inspire::parallel::ResourcePool<inspire::Session> sessionPool(thread_num, [](inspire::Session& session) {
|
||||
|
||||
});
|
||||
|
||||
for (int i = 0; i < thread_num; ++i) {
|
||||
inspire::CustomPipelineParameter param;
|
||||
param.enable_recognition = true;
|
||||
param.enable_liveness = true;
|
||||
param.enable_mask_detect = true;
|
||||
param.enable_face_attribute = true;
|
||||
param.enable_face_quality = true;
|
||||
inspire::Session session = inspire::Session::Create(inspire::DetectModuleMode::DETECT_MODE_ALWAYS_DETECT, 1, param);
|
||||
sessionPool.AddResource(std::move(session));
|
||||
}
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
int tasksPerThread = loop / thread_num;
|
||||
int remainingTasks = loop % thread_num;
|
||||
|
||||
// Run the task in parallel
|
||||
for (int i = 0; i < thread_num; ++i) {
|
||||
int taskCount = tasksPerThread + (i < remainingTasks ? 1 : 0);
|
||||
threads.emplace_back([&, taskCount]() {
|
||||
for (int j = 0; j < taskCount; ++j) {
|
||||
auto sessionGuard = sessionPool.AcquireResource();
|
||||
std::vector<inspire::FaceTrackWrap> results;
|
||||
int32_t ret;
|
||||
ret = sessionGuard->FaceDetectAndTrack(process, results);
|
||||
if (ret != 0) {
|
||||
std::cerr << "FaceDetectAndTrack failed" << std::endl;
|
||||
break;
|
||||
}
|
||||
if (results.size() == 0) {
|
||||
std::cerr << "Not found face" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Print basic information before starting
|
||||
std::cout << "\n=== Configuration Information ===" << std::endl;
|
||||
std::cout << "Model Path: " << model_path << std::endl;
|
||||
std::cout << "Image Path: " << image_path << std::endl;
|
||||
std::cout << "Total Loop Count: " << loop << std::endl;
|
||||
std::cout << "Number of Threads: " << thread_num << std::endl;
|
||||
std::cout << "Tasks per Thread: " << tasksPerThread << std::endl;
|
||||
std::cout << "Remaining Tasks: " << remainingTasks << std::endl;
|
||||
std::cout << "==============================\n" << std::endl;
|
||||
|
||||
inspire::SpendTimer timer("Number of threads: " + std::to_string(thread_num) + ", Number of tasks: " + std::to_string(loop));
|
||||
timer.Start();
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
timer.Stop();
|
||||
std::cout << timer << std::endl;
|
||||
|
||||
// Convert microseconds to milliseconds and print
|
||||
double milliseconds = timer.Total() / 1000.0;
|
||||
std::cout << "Total execution time: " << milliseconds << " ms" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2,113 +2,134 @@
|
||||
* Created by Jingyu Yan
|
||||
* @date 2024-10-01
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inspireface.h>
|
||||
|
||||
#define NUM_IMAGES 2
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Check whether the number of parameters is correct
|
||||
HResult ret;
|
||||
const char* packPath;
|
||||
const char* imgPath1;
|
||||
const char* imgPath2;
|
||||
HOption option;
|
||||
HFSession session;
|
||||
HFFaceFeature features[NUM_IMAGES];
|
||||
const char* imgPaths[NUM_IMAGES];
|
||||
int i;
|
||||
HFloat similarity;
|
||||
HFloat recommended_cosine_threshold;
|
||||
HFloat percentage;
|
||||
|
||||
/* Check whether the number of parameters is correct */
|
||||
if (argc != 4) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Usage: %s <pack_path> <img1_path> <img2_path>", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto packPath = argv[1];
|
||||
auto imgPath1 = argv[2];
|
||||
auto imgPath2 = argv[3];
|
||||
packPath = argv[1];
|
||||
imgPath1 = argv[2];
|
||||
imgPath2 = argv[3];
|
||||
|
||||
/* Initialize features array to NULL */
|
||||
memset(features, 0, sizeof(features));
|
||||
|
||||
/* Allocate memory for feature vectors */
|
||||
for (i = 0; i < NUM_IMAGES; i++) {
|
||||
ret = HFCreateFaceFeature(&features[i]);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Create face feature error: %d", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the image path array */
|
||||
imgPaths[0] = imgPath1;
|
||||
imgPaths[1] = imgPath2;
|
||||
|
||||
HFLogPrint(HF_LOG_INFO, "Pack file Path: %s", packPath);
|
||||
HFLogPrint(HF_LOG_INFO, "Source file Path 1: %s", imgPath1);
|
||||
HFLogPrint(HF_LOG_INFO, "Source file Path 2: %s", imgPath2);
|
||||
|
||||
HResult ret;
|
||||
// The resource file must be loaded before it can be used
|
||||
/* The resource file must be loaded before it can be used */
|
||||
ret = HFLaunchInspireFace(packPath);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Load Resource error: %d", ret);
|
||||
return ret;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Create a session for face recognition
|
||||
HOption option = HF_ENABLE_FACE_RECOGNITION;
|
||||
HFSession session;
|
||||
/* Create a session for face recognition */
|
||||
option = HF_ENABLE_FACE_RECOGNITION;
|
||||
ret = HFCreateInspireFaceSessionOptional(option, HF_DETECT_MODE_ALWAYS_DETECT, 1, -1, -1, &session);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Create session error: %d", ret);
|
||||
return ret;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
std::vector<char*> twoImg = {imgPath1, imgPath2};
|
||||
std::vector<std::vector<float>> vec(2, std::vector<float>(512));
|
||||
for (int i = 0; i < twoImg.size(); ++i) {
|
||||
/* Process two images */
|
||||
for (i = 0; i < NUM_IMAGES; i++) {
|
||||
HFImageBitmap imageBitmap = {0};
|
||||
ret = HFCreateImageBitmapFromFilePath(twoImg[i], 3, &imageBitmap);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Create image bitmap error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
// Prepare image data for processing
|
||||
|
||||
HFImageStream stream;
|
||||
ret = HFCreateImageStreamFromImageBitmap(imageBitmap, HF_CAMERA_ROTATION_0, &stream); // Create an image stream for processing
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Create stream error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Execute face tracking on the image
|
||||
HFMultipleFaceData multipleFaceData = {0};
|
||||
ret = HFExecuteFaceTrack(session, stream, &multipleFaceData); // Track faces in the image
|
||||
|
||||
ret = HFCreateImageBitmapFromFilePath(imgPaths[i], 3, &imageBitmap);
|
||||
if (ret != HSUCCEED) {
|
||||
HFReleaseImageBitmap(imageBitmap);
|
||||
HFLogPrint(HF_LOG_ERROR, "Create image bitmap error: %d", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = HFCreateImageStreamFromImageBitmap(imageBitmap, HF_CAMERA_ROTATION_0, &stream);
|
||||
if (ret != HSUCCEED) {
|
||||
HFReleaseImageStream(stream);
|
||||
HFReleaseImageBitmap(imageBitmap);
|
||||
HFLogPrint(HF_LOG_ERROR, "Create stream error: %d", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = HFExecuteFaceTrack(session, stream, &multipleFaceData);
|
||||
if (ret != HSUCCEED) {
|
||||
HFReleaseImageStream(stream);
|
||||
HFReleaseImageBitmap(imageBitmap);
|
||||
HFLogPrint(HF_LOG_ERROR, "Run face track error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
if (multipleFaceData.detectedNum == 0) { // Check if any faces were detected
|
||||
HFLogPrint(HF_LOG_ERROR, "No face was detected: %s", twoImg[i]);
|
||||
return ret;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Extract facial features from the first detected face, an interface that uses copy features in a comparison scenario
|
||||
ret = HFFaceFeatureExtractCpy(session, stream, multipleFaceData.tokens[0], vec[i].data()); // Extract features
|
||||
if (multipleFaceData.detectedNum == 0) {
|
||||
HFReleaseImageStream(stream);
|
||||
HFReleaseImageBitmap(imageBitmap);
|
||||
HFLogPrint(HF_LOG_ERROR, "No face was detected: %s", imgPaths[i]);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = HFFaceFeatureExtractTo(session, stream, multipleFaceData.tokens[0], features[i]);
|
||||
if (ret != HSUCCEED) {
|
||||
HFReleaseImageStream(stream);
|
||||
HFReleaseImageBitmap(imageBitmap);
|
||||
HFLogPrint(HF_LOG_ERROR, "Extract feature error: %d", ret);
|
||||
return ret;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = HFReleaseImageStream(stream);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Release image stream error: %d", ret);
|
||||
}
|
||||
ret = HFReleaseImageBitmap(imageBitmap);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Release image bitmap error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
HFReleaseImageStream(stream);
|
||||
HFReleaseImageBitmap(imageBitmap);
|
||||
}
|
||||
|
||||
// Make feature1
|
||||
HFFaceFeature feature1 = {0};
|
||||
feature1.data = vec[0].data();
|
||||
feature1.size = vec[0].size();
|
||||
HFFaceFeature feature1 = features[0];
|
||||
HFFaceFeature feature2 = features[1];
|
||||
|
||||
// Make feature2
|
||||
HFFaceFeature feature2 = {0};
|
||||
feature2.data = vec[1].data();
|
||||
feature2.size = vec[1].size();
|
||||
|
||||
// Run comparison
|
||||
HFloat similarity;
|
||||
/* Run comparison */
|
||||
ret = HFFaceComparison(feature1, feature2, &similarity);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Feature comparison error: %d", ret);
|
||||
return ret;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
HFloat recommended_cosine_threshold;
|
||||
ret = HFGetRecommendedCosineThreshold(&recommended_cosine_threshold);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Get recommended cosine threshold error: %d", ret);
|
||||
return ret;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (similarity > recommended_cosine_threshold) {
|
||||
@@ -118,20 +139,28 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
HFLogPrint(HF_LOG_INFO, "Similarity score: %.3f", similarity);
|
||||
|
||||
// Convert cosine similarity to percentage similarity.
|
||||
// Note: conversion parameters are not optimal and should be adjusted based on your specific use case.
|
||||
HFloat percentage;
|
||||
ret = HFCosineSimilarityConvertToPercentage(similarity, &percentage);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Convert similarity to percentage error: %d", ret);
|
||||
return ret;
|
||||
goto cleanup;
|
||||
}
|
||||
HFLogPrint(HF_LOG_INFO, "Percentage similarity: %f", percentage);
|
||||
|
||||
// The memory must be freed at the end of the program
|
||||
/* Clean up resources */
|
||||
ret = HFReleaseInspireFaceSession(session);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Release session error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/* Release the feature vector memory */
|
||||
for (i = 0; i < NUM_IMAGES; i++) {
|
||||
if (features[i].data != NULL) { // Only release features that were successfully created
|
||||
HFReleaseFaceFeature(&features[i]);
|
||||
}
|
||||
}
|
||||
|
||||
HFDeBugShowResourceStatistics();
|
||||
|
||||
return ret;
|
||||
}
|
||||
178
cpp-package/inspireface/cpp/sample/api/sample_face_crud.c
Normal file
178
cpp-package/inspireface/cpp/sample/api/sample_face_crud.c
Normal file
@@ -0,0 +1,178 @@
|
||||
#include <inspireface.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
HResult ret;
|
||||
// The resource file must be loaded before it can be used
|
||||
ret = HFLaunchInspireFace("test_res/pack/Pikachu");
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Load Resource error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *db_path = "case_crud.db";
|
||||
if (remove(db_path) != 0) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Remove database file error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
HFFeatureHubConfiguration configuration;
|
||||
configuration.primaryKeyMode = HF_PK_AUTO_INCREMENT;
|
||||
configuration.enablePersistence = 1;
|
||||
configuration.persistenceDbPath = db_path;
|
||||
configuration.searchMode = HF_SEARCH_MODE_EXHAUSTIVE;
|
||||
configuration.searchThreshold = 0.48f;
|
||||
ret = HFFeatureHubDataEnable(configuration);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Enable feature hub error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Create a session
|
||||
HFSession session;
|
||||
ret = HFCreateInspireFaceSessionOptional(HF_ENABLE_FACE_RECOGNITION, HF_DETECT_MODE_ALWAYS_DETECT, 1, 320, -1, &session);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Create session error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Prepare an image for insertion into the hub
|
||||
HFImageBitmap image;
|
||||
ret = HFCreateImageBitmapFromFilePath("test_res/data/bulk/kun.jpg", 3, &image);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Create image bitmap error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Create an image stream
|
||||
HFImageStream imageHandle;
|
||||
ret = HFCreateImageStreamFromImageBitmap(image, HF_CAMERA_ROTATION_0, &imageHandle);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Create image stream error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Detect and track
|
||||
HFMultipleFaceData multipleFaceData;
|
||||
ret = HFExecuteFaceTrack(session, imageHandle, &multipleFaceData);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Execute face track error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (multipleFaceData.detectedNum > 0) {
|
||||
HFLogPrint(HF_LOG_INFO, "Face detected: %d", multipleFaceData.detectedNum);
|
||||
}
|
||||
|
||||
HFFaceFeature feature;
|
||||
ret = HFCreateFaceFeature(&feature);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Create face feature error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = HFFaceFeatureExtractCpy(session, imageHandle, multipleFaceData.tokens[0], feature.data);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Extract feature error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Insert face feature into the hub
|
||||
HFFaceFeatureIdentity featureIdentity;
|
||||
featureIdentity.feature = &feature;
|
||||
featureIdentity.id = -1;
|
||||
HFaceId result_id;
|
||||
ret = HFFeatureHubInsertFeature(featureIdentity, &result_id);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Insert feature error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Prepare a photo of the same person for the query
|
||||
HFImageBitmap query_image;
|
||||
ret = HFCreateImageBitmapFromFilePath("test_res/data/bulk/jntm.jpg", 3, &query_image);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Create image bitmap error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Create an image stream
|
||||
HFImageStream query_imageHandle;
|
||||
ret = HFCreateImageStreamFromImageBitmap(query_image, HF_CAMERA_ROTATION_0, &query_imageHandle);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Create image stream error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Detect and track
|
||||
ret = HFExecuteFaceTrack(session, query_imageHandle, &multipleFaceData);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Execute face track error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (multipleFaceData.detectedNum > 0) {
|
||||
HFLogPrint(HF_LOG_INFO, "Face detected: %d", multipleFaceData.detectedNum);
|
||||
}
|
||||
|
||||
HFFaceFeature query_feature;
|
||||
ret = HFCreateFaceFeature(&query_feature);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Create face feature error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Extract face feature
|
||||
ret = HFFaceFeatureExtractTo(session, query_imageHandle, multipleFaceData.tokens[0], query_feature);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Extract feature error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Search face feature
|
||||
HFFaceFeatureIdentity query_featureIdentity;
|
||||
query_featureIdentity.feature = &query_feature;
|
||||
query_featureIdentity.id = -1;
|
||||
HFloat confidence;
|
||||
ret = HFFeatureHubFaceSearch(query_feature, &confidence, &query_featureIdentity);
|
||||
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Search feature error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
HFLogPrint(HF_LOG_INFO, "Search feature result: %d", query_featureIdentity.id);
|
||||
HFLogPrint(HF_LOG_INFO, "Search feature confidence: %f", confidence);
|
||||
|
||||
// Remove face feature
|
||||
ret = HFFeatureHubFaceRemove(result_id);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Remove feature error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
HFLogPrint(HF_LOG_INFO, "Remove feature result: %d", result_id);
|
||||
|
||||
// Query again
|
||||
ret = HFFeatureHubFaceSearch(query_feature, &confidence, &query_featureIdentity);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Search feature error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
HFLogPrint(HF_LOG_INFO, "Query again, search feature result: %d", query_featureIdentity.id);
|
||||
if (query_featureIdentity.id != -1) {
|
||||
HFLogPrint(HF_LOG_INFO, "Remove feature failed");
|
||||
}
|
||||
|
||||
// Release resources
|
||||
HFReleaseFaceFeature(&feature);
|
||||
HFReleaseFaceFeature(&query_feature);
|
||||
HFReleaseImageStream(imageHandle);
|
||||
HFReleaseImageStream(query_imageHandle);
|
||||
HFReleaseImageBitmap(image);
|
||||
HFReleaseImageBitmap(query_image);
|
||||
HFReleaseInspireFaceSession(session);
|
||||
|
||||
HFDeBugShowResourceStatistics();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2,30 +2,53 @@
|
||||
* Created by Jingyu Yan
|
||||
* @date 2024-10-01
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inspireface.h>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Check whether the number of parameters is correct
|
||||
HResult ret;
|
||||
const char* packPath;
|
||||
const char* sourcePath;
|
||||
int rotation;
|
||||
HFRotation rotation_enum;
|
||||
HOption option;
|
||||
HFDetectMode detMode;
|
||||
HInt32 maxDetectNum;
|
||||
HInt32 detectPixelLevel;
|
||||
HFSession session;
|
||||
HFImageBitmap image;
|
||||
HFImageStream imageHandle;
|
||||
HFMultipleFaceData multipleFaceData;
|
||||
int faceNum;
|
||||
HFImageBitmap drawImage;
|
||||
HFImageBitmapData data;
|
||||
int index;
|
||||
HFFaceMaskConfidence maskConfidence;
|
||||
HFFaceQualityConfidence qualityConfidence;
|
||||
HOption pipelineOption;
|
||||
HFFaceDetectPixelList pixelLevels;
|
||||
|
||||
/* Check whether the number of parameters is correct */
|
||||
if (argc < 3 || argc > 4) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Usage: %s <pack_path> <source_path> [rotation]", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto packPath = argv[1];
|
||||
auto sourcePath = argv[2];
|
||||
int rotation = 0;
|
||||
packPath = argv[1];
|
||||
sourcePath = argv[2];
|
||||
rotation = 0;
|
||||
|
||||
// If rotation is provided, check and set the value
|
||||
/* If rotation is provided, check and set the value */
|
||||
if (argc == 4) {
|
||||
rotation = std::atoi(argv[3]);
|
||||
rotation = atoi(argv[3]);
|
||||
if (rotation != 0 && rotation != 90 && rotation != 180 && rotation != 270) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Invalid rotation value. Allowed values are 0, 90, 180, 270.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
HFRotation rotation_enum;
|
||||
// Set rotation based on input parameter
|
||||
|
||||
/* Set rotation based on input parameter */
|
||||
switch (rotation) {
|
||||
case 90:
|
||||
rotation_enum = HF_CAMERA_ROTATION_90;
|
||||
@@ -46,28 +69,37 @@ int main(int argc, char* argv[]) {
|
||||
HFLogPrint(HF_LOG_INFO, "Source file Path: %s", sourcePath);
|
||||
HFLogPrint(HF_LOG_INFO, "Rotation: %d", rotation);
|
||||
|
||||
HFSetLogLevel(HF_LOG_INFO);
|
||||
HFSetLogLevel(HF_LOG_DEBUG);
|
||||
|
||||
HResult ret;
|
||||
// The resource file must be loaded before it can be used
|
||||
/* The resource file must be loaded before it can be used */
|
||||
ret = HFLaunchInspireFace(packPath);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Load Resource error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Enable the functions in the pipeline: mask detection, live detection, and face quality
|
||||
// detection
|
||||
HOption option = HF_ENABLE_QUALITY | HF_ENABLE_MASK_DETECT | HF_ENABLE_LIVENESS | HF_ENABLE_DETECT_MODE_LANDMARK;
|
||||
// Non-video or frame sequence mode uses IMAGE-MODE, which is always face detection without
|
||||
// tracking
|
||||
HFDetectMode detMode = HF_DETECT_MODE_ALWAYS_DETECT;
|
||||
// Maximum number of faces detected
|
||||
HInt32 maxDetectNum = 20;
|
||||
// Face detection image input level
|
||||
HInt32 detectPixelLevel = 160;
|
||||
// Handle of the current face SDK algorithm context
|
||||
HFSession session = {0};
|
||||
ret = HFQuerySupportedPixelLevelsForFaceDetection(&pixelLevels);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "HFQuerySupportedPixelLevelsForFaceDetection error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
HFLogPrint(HF_LOG_INFO, "Supported pixel levels for face detection: %d", pixelLevels.size);
|
||||
for (int i = 0; i < pixelLevels.size; i++) {
|
||||
HFLogPrint(HF_LOG_INFO, "Supported pixel level %d: %d", i + 1, pixelLevels.pixel_level[i]);
|
||||
}
|
||||
|
||||
/* Enable the functions in the pipeline: mask detection, live detection, and face quality
|
||||
* detection */
|
||||
option = HF_ENABLE_QUALITY | HF_ENABLE_MASK_DETECT | HF_ENABLE_LIVENESS;
|
||||
/* Non-video or frame sequence mode uses IMAGE-MODE, which is always face detection without
|
||||
* tracking */
|
||||
detMode = HF_DETECT_MODE_LIGHT_TRACK;
|
||||
/* Maximum number of faces detected */
|
||||
maxDetectNum = 20;
|
||||
/* Face detection image input level */
|
||||
detectPixelLevel = 160;
|
||||
/* Handle of the current face SDK algorithm context */
|
||||
session = NULL;
|
||||
ret = HFCreateInspireFaceSessionOptional(option, detMode, maxDetectNum, detectPixelLevel, -1, &session);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Create FaceContext error: %d", ret);
|
||||
@@ -77,123 +109,128 @@ int main(int argc, char* argv[]) {
|
||||
HFSessionSetTrackPreviewSize(session, detectPixelLevel);
|
||||
HFSessionSetFilterMinimumFacePixelSize(session, 4);
|
||||
|
||||
// Load a image
|
||||
HFImageBitmap image;
|
||||
/* Load a image */
|
||||
ret = HFCreateImageBitmapFromFilePath(sourcePath, 3, &image);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "The source entered is not a picture or read error.");
|
||||
return ret;
|
||||
}
|
||||
// Prepare an image parameter structure for configuration
|
||||
HFImageStream imageHandle = {0};
|
||||
/* Prepare an image parameter structure for configuration */
|
||||
ret = HFCreateImageStreamFromImageBitmap(image, rotation_enum, &imageHandle);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Create ImageStream error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Execute HF_FaceContextRunFaceTrack captures face information in an image
|
||||
HFMultipleFaceData multipleFaceData = {0};
|
||||
/* Execute HF_FaceContextRunFaceTrack captures face information in an image */
|
||||
ret = HFExecuteFaceTrack(session, imageHandle, &multipleFaceData);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Execute HFExecuteFaceTrack error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Print the number of faces detected
|
||||
auto faceNum = multipleFaceData.detectedNum;
|
||||
/* Print the number of faces detected */
|
||||
faceNum = multipleFaceData.detectedNum;
|
||||
HFLogPrint(HF_LOG_INFO, "Num of face: %d", faceNum);
|
||||
|
||||
// Copy a new image to draw
|
||||
HFImageBitmap drawImage = {0};
|
||||
/* Copy a new image to draw */
|
||||
ret = HFImageBitmapCopy(image, &drawImage);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Copy ImageBitmap error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
HFImageBitmapData data;
|
||||
ret = HFImageBitmapGetData(drawImage, &data);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Get ImageBitmap data error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
for (int index = 0; index < faceNum; ++index) {
|
||||
for (index = 0; index < faceNum; ++index) {
|
||||
HInt32 numOfLmk;
|
||||
HPoint2f* denseLandmarkPoints;
|
||||
HPoint2f fiveKeyPoints[5];
|
||||
float area;
|
||||
size_t i;
|
||||
|
||||
HFLogPrint(HF_LOG_INFO, "========================================");
|
||||
HFLogPrint(HF_LOG_INFO, "Token size: %d", multipleFaceData.tokens[index].size);
|
||||
HFLogPrint(HF_LOG_INFO, "Process face index: %d", index);
|
||||
HFLogPrint(HF_LOG_INFO, "DetConfidence: %f", multipleFaceData.detConfidence[index]);
|
||||
HFImageBitmapDrawRect(drawImage, multipleFaceData.rects[index], {0, 100, 255}, 4);
|
||||
|
||||
HFImageBitmapDrawRect(drawImage, multipleFaceData.rects[index], (HColor){0, 100, 255}, 4);
|
||||
|
||||
// Print FaceID, In IMAGE-MODE it is changing, in VIDEO-MODE it is fixed, but it may be lost
|
||||
HFLogPrint(HF_LOG_INFO, "FaceID: %d", multipleFaceData.trackIds[index]);
|
||||
|
||||
// Print Head euler angle, It can often be used to judge the quality of a face by the Angle
|
||||
// of the head
|
||||
HFLogPrint(HF_LOG_INFO, "Roll: %f, Yaw: %f, Pitch: %f", multipleFaceData.angles.roll[index], multipleFaceData.angles.yaw[index],
|
||||
multipleFaceData.angles.pitch[index]);
|
||||
|
||||
HInt32 numOfLmk;
|
||||
/* Get the number of dense landmark points */
|
||||
HFGetNumOfFaceDenseLandmark(&numOfLmk);
|
||||
HPoint2f denseLandmarkPoints[numOfLmk];
|
||||
denseLandmarkPoints = (HPoint2f*)malloc(sizeof(HPoint2f) * numOfLmk);
|
||||
if (denseLandmarkPoints == NULL) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Memory allocation failed!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = HFGetFaceDenseLandmarkFromFaceToken(multipleFaceData.tokens[index], denseLandmarkPoints, numOfLmk);
|
||||
if (ret != HSUCCEED) {
|
||||
free(denseLandmarkPoints);
|
||||
HFLogPrint(HF_LOG_ERROR, "HFGetFaceDenseLandmarkFromFaceToken error!!");
|
||||
return -1;
|
||||
}
|
||||
for (size_t i = 0; i < numOfLmk; i++) {
|
||||
HFImageBitmapDrawCircleF(drawImage, {denseLandmarkPoints[i].x, denseLandmarkPoints[i].y}, 0, {100, 100, 0}, 2);
|
||||
|
||||
/* Draw dense landmark points */
|
||||
for (i = 0; i < numOfLmk; i++) {
|
||||
HFImageBitmapDrawCircleF(drawImage,
|
||||
(HPoint2f){denseLandmarkPoints[i].x, denseLandmarkPoints[i].y},
|
||||
0,
|
||||
(HColor){100, 100, 0},
|
||||
2);
|
||||
}
|
||||
auto& rt = multipleFaceData.rects[index];
|
||||
float area = ((float)(rt.height * rt.width)) / (data.width * data.height);
|
||||
free(denseLandmarkPoints);
|
||||
|
||||
HFaceRect rt = multipleFaceData.rects[index];
|
||||
area = ((float)(rt.height * rt.width)) / (data.width * data.height);
|
||||
HFLogPrint(HF_LOG_INFO, "area: %f", area);
|
||||
|
||||
HPoint2f fiveKeyPoints[5];
|
||||
ret = HFGetFaceFiveKeyPointsFromFaceToken(multipleFaceData.tokens[index], fiveKeyPoints, 5);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "HFGetFaceFiveKeyPointsFromFaceToken error!!");
|
||||
return -1;
|
||||
}
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
HFImageBitmapDrawCircleF(drawImage, {fiveKeyPoints[i].x, fiveKeyPoints[i].y}, 0, {0, 0, 232}, 2);
|
||||
for (i = 0; i < 5; i++) {
|
||||
HFImageBitmapDrawCircleF(drawImage, (HPoint2f){fiveKeyPoints[i].x, fiveKeyPoints[i].y}, 0, (HColor){0, 0, 232}, 2);
|
||||
}
|
||||
}
|
||||
HFImageBitmapWriteToFile(drawImage, "draw_detected.jpg");
|
||||
HFLogPrint(HF_LOG_WARN, "Write to file success: %s", "draw_detected.jpg");
|
||||
|
||||
// Run pipeline function
|
||||
// Select the pipeline function that you want to execute, provided that it is already enabled
|
||||
// when FaceContext is created!
|
||||
auto pipelineOption = HF_ENABLE_QUALITY | HF_ENABLE_MASK_DETECT | HF_ENABLE_LIVENESS;
|
||||
// In this loop, all faces are processed
|
||||
/* Run pipeline function */
|
||||
/* Select the pipeline function that you want to execute, provided that it is already enabled
|
||||
* when FaceContext is created! */
|
||||
pipelineOption = HF_ENABLE_QUALITY | HF_ENABLE_MASK_DETECT | HF_ENABLE_LIVENESS;
|
||||
/* In this loop, all faces are processed */
|
||||
ret = HFMultipleFacePipelineProcessOptional(session, imageHandle, &multipleFaceData, pipelineOption);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Execute Pipeline error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get mask detection results from the pipeline cache
|
||||
HFFaceMaskConfidence maskConfidence = {0};
|
||||
/* Get mask detection results from the pipeline cache */
|
||||
ret = HFGetFaceMaskConfidence(session, &maskConfidence);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Get mask detect result error: %d", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get face quality results from the pipeline cache
|
||||
HFFaceQualityConfidence qualityConfidence = {0};
|
||||
/* Get face quality results from the pipeline cache */
|
||||
ret = HFGetFaceQualityConfidence(session, &qualityConfidence);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Get face quality result error: %d", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int index = 0; index < faceNum; ++index) {
|
||||
for (index = 0; index < faceNum; ++index) {
|
||||
HFLogPrint(HF_LOG_INFO, "========================================");
|
||||
HFLogPrint(HF_LOG_INFO, "Process face index from pipeline: %d", index);
|
||||
HFLogPrint(HF_LOG_INFO, "Mask detect result: %f", maskConfidence.confidence[index]);
|
||||
HFLogPrint(HF_LOG_INFO, "Quality predict result: %f", qualityConfidence.confidence[index]);
|
||||
// We set the threshold of wearing a mask as 0.85. If it exceeds the threshold, it will be
|
||||
// judged as wearing a mask. The threshold can be adjusted according to the scene
|
||||
/* We set the threshold of wearing a mask as 0.85. If it exceeds the threshold, it will be
|
||||
* judged as wearing a mask. The threshold can be adjusted according to the scene */
|
||||
if (maskConfidence.confidence[index] > 0.85) {
|
||||
HFLogPrint(HF_LOG_INFO, "Mask");
|
||||
} else {
|
||||
@@ -205,7 +242,7 @@ int main(int argc, char* argv[]) {
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Release image stream error: %d", ret);
|
||||
}
|
||||
// The memory must be freed at the end of the program
|
||||
/* The memory must be freed at the end of the program */
|
||||
ret = HFReleaseInspireFaceSession(session);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Release session error: %d", ret);
|
||||
@@ -224,5 +261,8 @@ int main(int argc, char* argv[]) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
HFLogPrint(HF_LOG_INFO, "");
|
||||
HFDeBugShowResourceStatistics();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,31 +1,33 @@
|
||||
/**
|
||||
/*
|
||||
* Created by Jingyu Yan
|
||||
* @date 2024-10-01
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inspireface.h>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Check whether the number of parameters is correct
|
||||
/* Check whether the number of parameters is correct */
|
||||
if (argc < 3 || argc > 4) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Usage: %s <pack_path> <source_path> [rotation]", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto packPath = argv[1];
|
||||
auto sourcePath = argv[2];
|
||||
const char* packPath = argv[1];
|
||||
const char* sourcePath = argv[2];
|
||||
int rotation = 0;
|
||||
|
||||
// If rotation is provided, check and set the value
|
||||
/* If rotation is provided, check and set the value */
|
||||
if (argc == 4) {
|
||||
rotation = std::atoi(argv[3]);
|
||||
rotation = atoi(argv[3]);
|
||||
if (rotation != 0 && rotation != 90 && rotation != 180 && rotation != 270) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Invalid rotation value. Allowed values are 0, 90, 180, 270.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
HFRotation rotation_enum;
|
||||
// Set rotation based on input parameter
|
||||
/* Set rotation based on input parameter */
|
||||
switch (rotation) {
|
||||
case 90:
|
||||
rotation_enum = HF_CAMERA_ROTATION_90;
|
||||
@@ -49,24 +51,24 @@ int main(int argc, char* argv[]) {
|
||||
HFSetLogLevel(HF_LOG_INFO);
|
||||
|
||||
HResult ret;
|
||||
// The resource file must be loaded before it can be used
|
||||
/* The resource file must be loaded before it can be used */
|
||||
ret = HFLaunchInspireFace(packPath);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Load Resource error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Enable the functions in the pipeline: mask detection, live detection, and face quality
|
||||
// detection
|
||||
HOption option = HF_ENABLE_QUALITY | HF_ENABLE_MASK_DETECT | HF_ENABLE_LIVENESS | HF_ENABLE_DETECT_MODE_LANDMARK;
|
||||
// Non-video or frame sequence mode uses IMAGE-MODE, which is always face detection without
|
||||
// tracking
|
||||
/* Enable the functions in the pipeline: mask detection, live detection, and face quality
|
||||
* detection */
|
||||
HOption option = HF_ENABLE_QUALITY | HF_ENABLE_MASK_DETECT | HF_ENABLE_LIVENESS;
|
||||
/* Non-video or frame sequence mode uses IMAGE-MODE, which is always face detection without
|
||||
* tracking */
|
||||
HFDetectMode detMode = HF_DETECT_MODE_ALWAYS_DETECT;
|
||||
// Maximum number of faces detected
|
||||
/* Maximum number of faces detected */
|
||||
HInt32 maxDetectNum = 20;
|
||||
// Face detection image input level
|
||||
/* Face detection image input level */
|
||||
HInt32 detectPixelLevel = 160;
|
||||
// Handle of the current face SDK algorithm context
|
||||
/* Handle of the current face SDK algorithm context */
|
||||
HFSession session = {0};
|
||||
ret = HFCreateInspireFaceSessionOptional(option, detMode, maxDetectNum, detectPixelLevel, -1, &session);
|
||||
if (ret != HSUCCEED) {
|
||||
@@ -77,14 +79,14 @@ int main(int argc, char* argv[]) {
|
||||
HFSessionSetTrackPreviewSize(session, detectPixelLevel);
|
||||
HFSessionSetFilterMinimumFacePixelSize(session, 4);
|
||||
|
||||
// Load a image
|
||||
/* Load a image */
|
||||
HFImageBitmap image;
|
||||
ret = HFCreateImageBitmapFromFilePath(sourcePath, 3, &image);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "The source entered is not a picture or read error.");
|
||||
return ret;
|
||||
}
|
||||
// Prepare an image parameter structure for configuration
|
||||
/* Prepare an image parameter structure for configuration */
|
||||
HFImageStream imageHandle = {0};
|
||||
ret = HFCreateImageStreamFromImageBitmap(image, rotation_enum, &imageHandle);
|
||||
if (ret != HSUCCEED) {
|
||||
@@ -94,12 +96,13 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
int loop = 100;
|
||||
|
||||
// Enable the cost spend
|
||||
/* Enable the cost spend */
|
||||
HFSessionSetEnableTrackCostSpend(session, 1);
|
||||
|
||||
// Execute HF_FaceContextRunFaceTrack captures face information in an image
|
||||
int i;
|
||||
/* Execute HF_FaceContextRunFaceTrack captures face information in an image */
|
||||
HFMultipleFaceData multipleFaceData = {0};
|
||||
for (int i = 0; i < loop; i++) {
|
||||
for (i = 0; i < loop; i++) {
|
||||
ret = HFExecuteFaceTrack(session, imageHandle, &multipleFaceData);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Execute HFExecuteFaceTrack error: %d", ret);
|
||||
@@ -113,7 +116,7 @@ int main(int argc, char* argv[]) {
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Release image stream error: %d", ret);
|
||||
}
|
||||
// The memory must be freed at the end of the program
|
||||
/* The memory must be freed at the end of the program */
|
||||
ret = HFReleaseInspireFaceSession(session);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Release session error: %d", ret);
|
||||
@@ -1,8 +1,6 @@
|
||||
#include <iostream>
|
||||
#include <inspireface.h>
|
||||
#include <vector>
|
||||
|
||||
static std::vector<float> FT = {
|
||||
static float FT[] = {
|
||||
0.0706566, 0.00640248, 0.0418103, -0.00597861, 0.0269879, 0.0187478, 0.0486305, 0.0349162, -0.0080779, -0.0550556, 0.0229963,
|
||||
-0.00683422, -0.0338589, 0.0533989, -0.0371725, 0.000972469, 0.0612415, 0.0389846, -0.00126743, -0.0128782, 0.0935529, 0.0588179,
|
||||
0.0164787, -0.00732871, -0.0458209, -0.0100137, -0.0372892, 0.000871123, 0.0245121, -0.0811471, -0.00481095, 0.0266868, 0.0712961,
|
||||
@@ -73,12 +71,10 @@ int main() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// std::vector<float> feature(512, 0.0f);
|
||||
|
||||
int64_t result_id = 0;
|
||||
HFFaceFeature feature = {0};
|
||||
feature.data = FT.data();
|
||||
feature.size = FT.size();
|
||||
feature.data = FT;
|
||||
feature.size = sizeof(FT) / sizeof(FT[0]);
|
||||
HFFaceFeatureIdentity identity = {0};
|
||||
identity.feature = &feature;
|
||||
ret = HFFeatureHubInsertFeature(identity, &result_id);
|
||||
@@ -87,10 +83,9 @@ int main() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// std::vector<float> query_feature(512, 20.0f);
|
||||
HFFaceFeature query_feature = {0};
|
||||
query_feature.data = FT.data();
|
||||
query_feature.size = FT.size();
|
||||
query_feature.data = FT;
|
||||
query_feature.size = sizeof(FT) / sizeof(FT[0]);
|
||||
HFloat confidence;
|
||||
HFFaceFeatureIdentity search_result = {0};
|
||||
ret = HFFeatureHubFaceSearch(query_feature, &confidence, &search_result);
|
||||
@@ -0,0 +1,52 @@
|
||||
#include <inspireface.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Usage: %s <pack_path>", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* packPath = argv[1];
|
||||
HResult ret;
|
||||
ret = HFLaunchInspireFace(packPath);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Load Resource error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
const char* DBFilePath = "feature.db";
|
||||
|
||||
// remove old db file
|
||||
if (access(DBFilePath, F_OK) == 0) {
|
||||
if (remove(DBFilePath) != 0) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Failed to remove old db file: %s", DBFilePath);
|
||||
return -1;
|
||||
}
|
||||
HFLogPrint(HF_LOG_INFO, "Remove old db file: %s", DBFilePath);
|
||||
}
|
||||
|
||||
HFFeatureHubConfiguration featureHubConfiguration;
|
||||
featureHubConfiguration.primaryKeyMode = HF_PK_AUTO_INCREMENT;
|
||||
featureHubConfiguration.enablePersistence = 1;
|
||||
featureHubConfiguration.persistenceDbPath = DBFilePath;
|
||||
featureHubConfiguration.searchMode = HF_SEARCH_MODE_EAGER;
|
||||
featureHubConfiguration.searchThreshold = 0.48f;
|
||||
|
||||
ret = HFFeatureHubDataEnable(featureHubConfiguration);
|
||||
if (ret != HSUCCEED)
|
||||
{
|
||||
HFLogPrint(HF_LOG_ERROR, "Enable FeatureHub failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (access(DBFilePath, F_OK) != 0) {
|
||||
HFLogPrint(HF_LOG_ERROR, "DB file not found: %s", DBFilePath);
|
||||
return -1;
|
||||
}
|
||||
HFLogPrint(HF_LOG_INFO, "DB file found: %s", DBFilePath);
|
||||
|
||||
// ....
|
||||
|
||||
HFTerminateInspireFace();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
#include <iostream>
|
||||
#include <inspireface.h>
|
||||
|
||||
int main() {
|
||||
std::string resourcePath = "test_res/pack/Pikachu";
|
||||
HResult ret = HFReloadInspireFace(resourcePath.c_str());
|
||||
const char* resourcePath = "test_res/pack/Pikachu";
|
||||
HResult ret = HFReloadInspireFace(resourcePath);
|
||||
if (ret != HSUCCEED) {
|
||||
HFLogPrint(HF_LOG_ERROR, "Failed to launch InspireFace: %d", ret);
|
||||
return 1;
|
||||
@@ -91,7 +91,7 @@ int main() {
|
||||
m_extract_ = std::make_shared<Extract>();
|
||||
InspireModel model;
|
||||
loader.LoadModel("feature", model);
|
||||
m_extract_->loadData(model, InferenceWrapper::INFER_RKNN);
|
||||
m_extract_->LoadData(model, InferenceWrapper::INFER_RKNN);
|
||||
|
||||
cv::Mat image = cv::imread(names[0]);
|
||||
// cv::Mat rgb;
|
||||
|
||||
@@ -31,7 +31,7 @@ int main() {
|
||||
|
||||
std::shared_ptr<FaceDetect> m_face_detector_;
|
||||
m_face_detector_ = std::make_shared<FaceDetect>(320);
|
||||
m_face_detector_->loadData(model, InferenceWrapper::INFER_RKNN);
|
||||
m_face_detector_->LoadData(model, InferenceWrapper::INFER_RKNN);
|
||||
|
||||
// Load a image
|
||||
cv::Mat image = cv::imread("test_res/images/face_sample.png");
|
||||
|
||||
@@ -35,7 +35,7 @@ void rec_function() {
|
||||
m_extract_ = std::make_shared<Extract>();
|
||||
InspireModel model;
|
||||
loader->LoadModel("feature", model);
|
||||
m_extract_->loadData(model, InferenceWrapper::INFER_RKNN);
|
||||
m_extract_->LoadData(model, InferenceWrapper::INFER_RKNN);
|
||||
|
||||
loader.reset();
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ void test_rnet() {
|
||||
InspireModel model;
|
||||
loader.LoadModel("refine_net", model);
|
||||
m_rnet_ = std::make_shared<RNet>();
|
||||
m_rnet_->loadData(model, InferenceWrapper::INFER_RKNN);
|
||||
m_rnet_->LoadData(model, InferenceWrapper::INFER_RKNN);
|
||||
|
||||
{
|
||||
// Load a image
|
||||
@@ -78,7 +78,7 @@ void test_mask() {
|
||||
m_mask_predict_ = std::make_shared<MaskPredict>();
|
||||
InspireModel model;
|
||||
loader.LoadModel("mask_detect", model);
|
||||
m_mask_predict_->loadData(model, InferenceWrapper::INFER_RKNN);
|
||||
m_mask_predict_->LoadData(model, InferenceWrapper::INFER_RKNN);
|
||||
|
||||
{
|
||||
// Load a image
|
||||
@@ -120,7 +120,7 @@ void test_quality() {
|
||||
m_face_quality_ = std::make_shared<FacePoseQuality>();
|
||||
InspireModel model;
|
||||
loader.LoadModel("pose_quality", model);
|
||||
m_face_quality_->loadData(model, InferenceWrapper::INFER_RKNN);
|
||||
m_face_quality_->LoadData(model, InferenceWrapper::INFER_RKNN);
|
||||
|
||||
{
|
||||
std::vector<std::string> names = {
|
||||
@@ -166,7 +166,7 @@ void test_landmark_mnn() {
|
||||
m_landmark_predictor_ = std::make_shared<FaceLandmark>(112);
|
||||
InspireModel model;
|
||||
loader.LoadModel("landmark", model);
|
||||
m_landmark_predictor_->loadData(model);
|
||||
m_landmark_predictor_->LoadData(model);
|
||||
|
||||
cv::Mat image = cv::imread("test_res/images/test_data/crop.png");
|
||||
cv::resize(image, image, cv::Size(112, 112));
|
||||
@@ -206,7 +206,7 @@ void test_landmark() {
|
||||
m_landmark_predictor_ = std::make_shared<FaceLandmark>(112);
|
||||
InspireModel model;
|
||||
loader.LoadModel("landmark", model);
|
||||
m_landmark_predictor_->loadData(model, InferenceWrapper::INFER_RKNN);
|
||||
m_landmark_predictor_->LoadData(model, InferenceWrapper::INFER_RKNN);
|
||||
|
||||
cv::Mat image = cv::imread("test_res/images/test_data/0.jpg");
|
||||
cv::resize(image, image, cv::Size(112, 112));
|
||||
@@ -248,7 +248,7 @@ void test_liveness() {
|
||||
InspireModel model;
|
||||
loader.LoadModel("rgb_anti_spoofing", model);
|
||||
m_rgb_anti_spoofing_ = std::make_shared<RBGAntiSpoofing>(80, true);
|
||||
m_rgb_anti_spoofing_->loadData(model, InferenceWrapper::INFER_RKNN);
|
||||
m_rgb_anti_spoofing_->LoadData(model, InferenceWrapper::INFER_RKNN);
|
||||
|
||||
std::vector<std::string> names = {
|
||||
"test_res/images/test_data/real.jpg", "test_res/images/test_data/fake.jpg", "test_res/images/test_data/live.jpg",
|
||||
|
||||
@@ -27,7 +27,7 @@ int main(int argc, char** argv) {
|
||||
auto m_pose_net_ = std::make_shared<FacePose>();
|
||||
InspireModel model;
|
||||
loader.LoadModel("", model);
|
||||
m_pose_net_->loadData(model);
|
||||
m_pose_net_->LoadData(model);
|
||||
|
||||
auto image = cv::imread("resource/images/crop.png");
|
||||
|
||||
|
||||
@@ -30,10 +30,10 @@ int main(int argc, char** argv) {
|
||||
stream.SetDataBuffer(rot90.data, rot90.rows, rot90.cols);
|
||||
ctx.FaceDetectAndTrack(stream);
|
||||
|
||||
std::vector<HyperFaceData> faces;
|
||||
std::vector<FaceTrackWrap> faces;
|
||||
for (int i = 0; i < ctx.GetNumberOfFacesCurrentlyDetected(); ++i) {
|
||||
// const ByteArray &byteArray = ctx.GetDetectCache()[i];
|
||||
HyperFaceData face = {0};
|
||||
FaceTrackWrap face = {0};
|
||||
// ret = DeserializeHyperFaceData(byteArray, face);
|
||||
|
||||
const FaceBasicData& faceBasic = ctx.GetFaceBasicDataCache()[i];
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include <inspireface/inspireface.hpp>
|
||||
#include "inspireface/track_module/landmark/order_of_hyper_landmark.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 3) {
|
||||
std::cout << "Usage: " << argv[0] << " <model_path> <image_path>" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string model_path = argv[1];
|
||||
std::string image_path = argv[2];
|
||||
|
||||
// Global init(only once)
|
||||
INSPIREFACE_CONTEXT->Reload(model_path);
|
||||
|
||||
// Create image and frame process
|
||||
inspirecv::Image image = inspirecv::Image::Create(image_path);
|
||||
inspirecv::FrameProcess process =
|
||||
inspirecv::FrameProcess::Create(image.Data(), image.Height(), image.Width(), inspirecv::BGR, inspirecv::ROTATION_0);
|
||||
|
||||
// Create session
|
||||
inspire::CustomPipelineParameter param;
|
||||
param.enable_recognition = true;
|
||||
param.enable_liveness = true;
|
||||
param.enable_mask_detect = true;
|
||||
param.enable_face_attribute = true;
|
||||
param.enable_face_quality = true;
|
||||
param.enable_interaction_liveness = true;
|
||||
std::shared_ptr<inspire::Session> session(inspire::Session::CreatePtr(inspire::DETECT_MODE_ALWAYS_DETECT, 1, param, 320));
|
||||
|
||||
INSPIREFACE_CHECK_MSG(session != nullptr, "Session is not valid");
|
||||
|
||||
// Detect and track
|
||||
std::vector<inspire::FaceTrackWrap> results;
|
||||
int32_t ret;
|
||||
ret = session->FaceDetectAndTrack(process, results);
|
||||
INSPIREFACE_CHECK_MSG(ret == 0, "FaceDetectAndTrack failed");
|
||||
|
||||
auto first = results[0];
|
||||
auto lmk = session->GetFaceDenseLandmark(first);
|
||||
std::cout << "lmk: " << lmk.size() << std::endl;
|
||||
for (size_t i = 0; i < lmk.size(); i++) {
|
||||
image.DrawCircle(lmk[i].As<int>(), 5, inspirecv::Color::Red);
|
||||
}
|
||||
|
||||
inspirecv::TransformMatrix rotation_mode_affine = process.GetAffineMatrix();
|
||||
|
||||
std::vector<inspirecv::Point2f> stand_lmk = ApplyTransformToPoints(lmk, rotation_mode_affine.GetInverse());
|
||||
|
||||
// Use total lmk
|
||||
auto rect = inspirecv::MinBoundingRect(stand_lmk);
|
||||
auto rect_pts = rect.As<float>().ToFourVertices();
|
||||
std::vector<inspirecv::Point2f> dst_pts = {{0, 0}, {112, 0}, {112, 112}, {0, 112}};
|
||||
std::vector<inspirecv::Point2f> camera_pts = ApplyTransformToPoints(rect_pts, rotation_mode_affine);
|
||||
|
||||
auto affine = inspirecv::SimilarityTransformEstimate(camera_pts, dst_pts);
|
||||
auto image_affine = process.ExecuteImageAffineProcessing(affine, 112, 112);
|
||||
image_affine.Write("affine.jpg");
|
||||
|
||||
// image.DrawRect(rect.As<int>(), inspirecv::Color::Red);
|
||||
// image.Write("lmk.jpg");
|
||||
|
||||
std::vector<inspirecv::Point2i> points;
|
||||
for (const auto& idx : inspire::HLMK_LEFT_EYE_POINTS_INDEX) {
|
||||
points.emplace_back(stand_lmk[idx].GetX(), stand_lmk[idx].GetY());
|
||||
}
|
||||
std::cout << "points: " << points.size() << std::endl;
|
||||
auto rect_eye = inspirecv::MinBoundingRect(points).Square(1.4f);
|
||||
// draw debug
|
||||
image.DrawRect(rect_eye.As<int>(), inspirecv::Color::Red);
|
||||
auto rect_pts_eye = rect_eye.As<float>().ToFourVertices();
|
||||
std::vector<inspirecv::Point2f> dst_pts_eye = {{0, 0}, {64, 0}, {64, 64}, {0, 64}};
|
||||
std::vector<inspirecv::Point2f> camera_pts_eye = ApplyTransformToPoints(rect_pts_eye, rotation_mode_affine);
|
||||
|
||||
auto affine_eye = inspirecv::SimilarityTransformEstimate(camera_pts_eye, dst_pts_eye);
|
||||
auto eye_affine = process.ExecuteImageAffineProcessing(affine_eye, 64, 64);
|
||||
eye_affine.Write("eye.jpg");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include <inspireface/inspireface.hpp>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 4) {
|
||||
std::cout << "Usage: " << argv[0] << " <model_path> <image_path1> <image_path2>" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string model_path = argv[1];
|
||||
std::string image_path1 = argv[2];
|
||||
std::string image_path2 = argv[3];
|
||||
|
||||
// Global init(only once)
|
||||
INSPIREFACE_CONTEXT->Reload(model_path);
|
||||
|
||||
// Create image and frame process
|
||||
inspirecv::Image image1 = inspirecv::Image::Create(image_path1);
|
||||
inspirecv::Image image2 = inspirecv::Image::Create(image_path2);
|
||||
inspirecv::FrameProcess process1 = inspirecv::FrameProcess::Create(image1.Data(), image1.Height(), image1.Width(), inspirecv::BGR, inspirecv::ROTATION_0);
|
||||
inspirecv::FrameProcess process2 = inspirecv::FrameProcess::Create(image2.Data(), image2.Height(), image2.Width(), inspirecv::BGR, inspirecv::ROTATION_0);
|
||||
|
||||
// Create session
|
||||
inspire::CustomPipelineParameter param;
|
||||
param.enable_recognition = true;
|
||||
|
||||
// Create session
|
||||
std::shared_ptr<inspire::Session> session(
|
||||
inspire::Session::CreatePtr(inspire::DETECT_MODE_ALWAYS_DETECT, 1, param, 320));
|
||||
|
||||
INSPIREFACE_CHECK_MSG(session != nullptr, "Session is not valid");
|
||||
|
||||
// Detect and track
|
||||
std::vector<inspire::FaceTrackWrap> results1;
|
||||
std::vector<inspire::FaceTrackWrap> results2;
|
||||
|
||||
// Detect and track
|
||||
session->FaceDetectAndTrack(process1, results1);
|
||||
session->FaceDetectAndTrack(process2, results2);
|
||||
|
||||
INSPIREFACE_CHECK_MSG(!results1.empty() && !results2.empty(), "No face detected");
|
||||
|
||||
// Get feature
|
||||
inspire::FaceEmbedding feature1;
|
||||
inspire::FaceEmbedding feature2;
|
||||
session->FaceFeatureExtract(process1, results1[0], feature1);
|
||||
session->FaceFeatureExtract(process2, results2[0], feature2);
|
||||
|
||||
// Compare
|
||||
float similarity;
|
||||
INSPIREFACE_FEATURE_HUB->CosineSimilarity(feature1.embedding, feature2.embedding, similarity);
|
||||
std::cout << "cosine of similarity: " << similarity << std::endl;
|
||||
std::cout << "percentage of similarity: " << SIMILARITY_CONVERTER_RUN(similarity) << std::endl;
|
||||
|
||||
std::cout << "== using alignment image ==" << std::endl;
|
||||
|
||||
// Get face alignment image
|
||||
inspirecv::Image wrapped1;
|
||||
inspirecv::Image wrapped2;
|
||||
session->GetFaceAlignmentImage(process1, results1[0], wrapped1);
|
||||
session->GetFaceAlignmentImage(process2, results2[0], wrapped2);
|
||||
wrapped1.Write("wrapped1.jpg");
|
||||
wrapped2.Write("wrapped2.jpg");
|
||||
|
||||
inspire::FaceEmbedding feature1_alignment;
|
||||
inspire::FaceEmbedding feature2_alignment;
|
||||
session->FaceFeatureExtractWithAlignmentImage(wrapped1, feature1_alignment);
|
||||
session->FaceFeatureExtractWithAlignmentImage(wrapped2, feature2_alignment);
|
||||
|
||||
INSPIREFACE_FEATURE_HUB->CosineSimilarity(feature1_alignment.embedding, feature2_alignment.embedding, similarity);
|
||||
std::cout << "cosine of similarity: " << similarity << std::endl;
|
||||
std::cout << "percentage of similarity: " << SIMILARITY_CONVERTER_RUN(similarity) << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#include <iostream>
|
||||
#include <inspireface/inspireface.hpp>
|
||||
|
||||
int main() {
|
||||
// Launch InspireFace
|
||||
std::string model_path = "test_res/pack/Pikachu";
|
||||
INSPIREFACE_CONTEXT->Reload(model_path);
|
||||
INSPIREFACE_CHECK_MSG(INSPIREFACE_CONTEXT->isMLoad(), "InspireFace is not loaded");
|
||||
|
||||
// Enable feature hub
|
||||
std::string db_path = "case_crud.db";
|
||||
// Remove the database file if it exists
|
||||
if (std::remove(db_path.c_str()) != 0) {
|
||||
std::cerr << "Error removing database file: " << db_path << std::endl;
|
||||
}
|
||||
inspire::DatabaseConfiguration db_config;
|
||||
db_config.enable_persistence = true;
|
||||
db_config.persistence_db_path = db_path;
|
||||
db_config.search_mode = inspire::SEARCH_MODE_EXHAUSTIVE;
|
||||
db_config.recognition_threshold = 0.48f;
|
||||
db_config.primary_key_mode = inspire::AUTO_INCREMENT;
|
||||
INSPIREFACE_FEATURE_HUB->EnableHub(db_config);
|
||||
|
||||
// Create a session
|
||||
auto param = inspire::CustomPipelineParameter();
|
||||
param.enable_recognition = true;
|
||||
auto session = inspire::Session::CreatePtr(inspire::DETECT_MODE_ALWAYS_DETECT, 1, param, 320);
|
||||
INSPIREFACE_CHECK_MSG(session != nullptr, "Session is not created");
|
||||
|
||||
// Prepare an image for insertion into the hub
|
||||
auto image = inspirecv::Image::Create("test_res/data/bulk/kun.jpg");
|
||||
auto image_process = inspirecv::FrameProcess::Create(image.Data(), image.Height(), image.Width(), inspirecv::BGR, inspirecv::ROTATION_0);
|
||||
|
||||
// Detect and track
|
||||
std::vector<inspire::FaceTrackWrap> results;
|
||||
session->FaceDetectAndTrack(image_process, results);
|
||||
INSPIREFACE_CHECK_MSG(results.size() > 0, "No face detected");
|
||||
|
||||
// Extract face feature
|
||||
inspire::FaceEmbedding feature;
|
||||
session->FaceFeatureExtract(image_process, results[0], feature);
|
||||
|
||||
// Insert face feature into the hub, because the id is INSPIRE_INVALID_ID, so input id is ignored
|
||||
int64_t result_id;
|
||||
INSPIREFACE_FEATURE_HUB->FaceFeatureInsert(feature.embedding, INSPIRE_INVALID_ID, result_id);
|
||||
|
||||
// Prepare a photo of the same person for the query
|
||||
auto query_image = inspirecv::Image::Create("test_res/data/bulk/jntm.jpg");
|
||||
auto query_image_process = inspirecv::FrameProcess::Create(query_image.Data(), query_image.Height(), query_image.Width(), inspirecv::BGR, inspirecv::ROTATION_0);
|
||||
|
||||
// Detect and track
|
||||
std::vector<inspire::FaceTrackWrap> query_results;
|
||||
session->FaceDetectAndTrack(query_image_process, query_results);
|
||||
INSPIREFACE_CHECK_MSG(query_results.size() > 0, "No face detected");
|
||||
|
||||
// Extract face feature
|
||||
inspire::FaceEmbedding query_feature;
|
||||
session->FaceFeatureExtract(query_image_process, query_results[0], query_feature);
|
||||
|
||||
// Search face feature
|
||||
inspire::FaceSearchResult search_result;
|
||||
INSPIREFACE_FEATURE_HUB->SearchFaceFeature(query_feature.embedding, search_result, true);
|
||||
std::cout << "Search face feature result: " << search_result.id << std::endl;
|
||||
std::cout << "Search face feature similarity: " << search_result.similarity << std::endl;
|
||||
|
||||
INSPIREFACE_CHECK_MSG(search_result.id == result_id, "Search face feature result id is not equal to the inserted id");
|
||||
|
||||
// Remove the face feature
|
||||
INSPIREFACE_FEATURE_HUB->FaceFeatureRemove(result_id);
|
||||
INSPIREFACE_CHECK_MSG(INSPIREFACE_FEATURE_HUB->GetFaceFeatureCount() == 0, "Face feature is not removed");
|
||||
|
||||
std::cout << "Remove face feature successfully" << std::endl;
|
||||
|
||||
// Query again
|
||||
INSPIREFACE_FEATURE_HUB->SearchFaceFeature(query_feature.embedding, search_result, true);
|
||||
INSPIREFACE_CHECK_MSG(search_result.id == INSPIRE_INVALID_ID, "Search face feature result id is not equal to the inserted id");
|
||||
std::cout << "Query again, search face feature result: " << search_result.id << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include <inspireface/inspireface.hpp>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 3) {
|
||||
std::cout << "Usage: " << argv[0] << " <model_path> <image_path>" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string model_path = argv[1];
|
||||
std::string image_path = argv[2];
|
||||
|
||||
// Global init(only once)
|
||||
INSPIREFACE_CONTEXT->Reload(model_path);
|
||||
|
||||
// Create image and frame process
|
||||
inspirecv::Image image = inspirecv::Image::Create(image_path);
|
||||
inspirecv::FrameProcess process =
|
||||
inspirecv::FrameProcess::Create(image.Data(), image.Height(), image.Width(), inspirecv::BGR, inspirecv::ROTATION_90);
|
||||
|
||||
// Create session
|
||||
inspire::CustomPipelineParameter param;
|
||||
param.enable_recognition = true;
|
||||
param.enable_liveness = true;
|
||||
param.enable_mask_detect = true;
|
||||
param.enable_face_attribute = true;
|
||||
param.enable_face_quality = true;
|
||||
std::shared_ptr<inspire::Session> session(inspire::Session::CreatePtr(inspire::DETECT_MODE_ALWAYS_DETECT, 100, param, 640));
|
||||
session->SetTrackPreviewSize(640);
|
||||
|
||||
INSPIREFACE_CHECK_MSG(session != nullptr, "Session is not valid");
|
||||
|
||||
// Detect and track
|
||||
std::vector<inspire::FaceTrackWrap> results;
|
||||
int32_t ret;
|
||||
ret = session->FaceDetectAndTrack(process, results);
|
||||
INSPIREFACE_CHECK_MSG(ret == 0, "FaceDetectAndTrack failed");
|
||||
|
||||
for (auto& result : results) {
|
||||
std::cout << "result: " << result.trackId << std::endl;
|
||||
std::cout << "quality: " << result.quality[0] << ", " << result.quality[1] << ", " << result.quality[2] << ", " << result.quality[3] << ", "
|
||||
<< result.quality[4] << std::endl;
|
||||
inspirecv::Rect2i rect = inspirecv::Rect2i::Create(result.rect.x, result.rect.y, result.rect.width, result.rect.height);
|
||||
std::cout << rect << std::endl;
|
||||
image.DrawRect(rect, inspirecv::Color::Red);
|
||||
inspirecv::TransformMatrix trans = inspirecv::TransformMatrix::Create(result.trans.m00, result.trans.m01, result.trans.tx, result.trans.m10, result.trans.m11, result.trans.ty);
|
||||
std::cout << "trans: " << trans.GetInverse() << std::endl;
|
||||
}
|
||||
image.Write("result.jpg");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
#include <iostream>
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include <inspireface/inspireface.hpp>
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#define CREATE_DIR(dir) _mkdir(dir)
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#define CREATE_DIR(dir) mkdir(dir, 0777)
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
// Make directory
|
||||
if (CREATE_DIR("cv") == -1) {
|
||||
// If the directory already exists, it is not an error
|
||||
if (errno != EEXIST) {
|
||||
std::cerr << "Error creating directory" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Image I/O */
|
||||
|
||||
// Load image from file
|
||||
// Load with 3 channels (BGR, like opencv)
|
||||
inspirecv::Image img = inspirecv::Image::Create("test_res/data/bulk/kun_cartoon_crop.jpg", 3);
|
||||
|
||||
// Load image from buffer
|
||||
// uint8_t* buffer = ...; // buffer is a pointer to the image data
|
||||
// bool is_alloc_mem = false; // if true, will allocate memory for the image data,
|
||||
// // false is recommended to point to the original data to avoid copying
|
||||
// inspirecv::Image img_buffer = inspirecv::Image::Create(width, height, channel, buffer, is_alloc_mem);
|
||||
|
||||
// Save image to file
|
||||
img.Write("cv/output.jpg");
|
||||
|
||||
// Show image, warning: it must depend on opencv
|
||||
// img.Show("input");
|
||||
|
||||
// Get pointer to image data
|
||||
const uint8_t* ptr = img.Data();
|
||||
|
||||
/* Image Processing */
|
||||
// Convert to grayscale
|
||||
inspirecv::Image gray = img.ToGray();
|
||||
gray.Write("cv/gray.jpg");
|
||||
|
||||
// Apply Gaussian blur
|
||||
inspirecv::Image blurred = img.GaussianBlur(3, 1.0);
|
||||
blurred.Write("cv/blurred.jpg");
|
||||
|
||||
// Geometric transformations
|
||||
auto scale = 0.35;
|
||||
bool use_bilinear = true;
|
||||
inspirecv::Image resized = img.Resize(img.Width() * scale, img.Height() * scale, use_bilinear); // Resize image
|
||||
resized.Write("cv/resized.jpg");
|
||||
|
||||
// Rotate 90 degrees clockwise
|
||||
inspirecv::Image rotated = img.Rotate90();
|
||||
rotated.Write("cv/rotated.jpg");
|
||||
|
||||
// Flip vertically
|
||||
inspirecv::Image flipped_vertical = img.FlipVertical();
|
||||
flipped_vertical.Write("cv/flipped_vertical.jpg");
|
||||
|
||||
// Flip horizontally
|
||||
inspirecv::Image flipped_horizontal = img.FlipHorizontal();
|
||||
flipped_horizontal.Write("cv/flipped_horizontal.jpg");
|
||||
|
||||
// Crop for rectangle
|
||||
inspirecv::Rect<int> rect = inspirecv::Rect<int>::Create(78, 41, 171, 171);
|
||||
inspirecv::Image cropped = img.Crop(rect);
|
||||
cropped.Write("cv/cropped.jpg");
|
||||
|
||||
// Image padding
|
||||
int top = 50, bottom = 50, left = 50, right = 50;
|
||||
inspirecv::Image padded = img.Pad(top, bottom, left, right, inspirecv::Color::Black);
|
||||
padded.Write("cv/padded.jpg");
|
||||
|
||||
// Swap red and blue channels
|
||||
inspirecv::Image swapped = img.SwapRB();
|
||||
swapped.Write("cv/swapped.jpg");
|
||||
|
||||
// Multiply image by scale factor
|
||||
double scale_factor = 0.5;
|
||||
inspirecv::Image scaled = img.Mul(scale_factor);
|
||||
scaled.Write("cv/scaled.jpg");
|
||||
|
||||
// Add value to image
|
||||
double value = -175;
|
||||
inspirecv::Image added = img.Add(value);
|
||||
added.Write("cv/added.jpg");
|
||||
|
||||
// Rotate 90 degrees clockwise(also support 270 and 180)
|
||||
inspirecv::Image rotated_90 = img.Rotate90();
|
||||
rotated_90.Write("cv/rotated_90.jpg");
|
||||
|
||||
// Affine transform
|
||||
/**
|
||||
* Create a transform matrix from the following matrix
|
||||
* [[a11, a12, tx],
|
||||
* [a21, a22, ty]]
|
||||
*
|
||||
* Face crop transform matrix
|
||||
* [[0.0, -1.37626, 261.127],
|
||||
* [1.37626, 0.0, 85.1831]]
|
||||
*/
|
||||
float a11 = 0.0f;
|
||||
float a12 = -1.37626f;
|
||||
float a21 = 1.37626f;
|
||||
float a22 = 0.0f;
|
||||
float b1 = 261.127f;
|
||||
float b2 = 85.1831f;
|
||||
|
||||
inspirecv::TransformMatrix trans = inspirecv::TransformMatrix::Create(a11, a12, b1, a21, a22, b2);
|
||||
int dst_width = 112;
|
||||
int dst_height = 112;
|
||||
inspirecv::Image affine = rotated_90.WarpAffine(trans, dst_width, dst_height);
|
||||
affine.Write("cv/affine.jpg");
|
||||
|
||||
/* Image Draw */
|
||||
inspirecv::Image draw_img = img.Clone();
|
||||
|
||||
// Draw a rectangle
|
||||
inspirecv::Rect<int> new_rect = rect.Square(1.1f); // Square and expand the rect
|
||||
int thickness = 3;
|
||||
draw_img.DrawRect(new_rect, inspirecv::Color::Green, thickness);
|
||||
draw_img.Write("cv/draw_rect.jpg");
|
||||
|
||||
// Draw a circle
|
||||
draw_img = img.Clone();
|
||||
std::vector<inspirecv::Point<int>> points = new_rect.As<int>().ToFourVertices();
|
||||
for (auto& point : points) {
|
||||
draw_img.DrawCircle(point, 1, inspirecv::Color::Red, 5);
|
||||
}
|
||||
draw_img.Write("cv/draw_circle.jpg");
|
||||
|
||||
// Draw a line
|
||||
draw_img = img.Clone();
|
||||
draw_img.DrawLine(points[0], points[1], inspirecv::Color::Cyan, 2);
|
||||
draw_img.DrawLine(points[1], points[2], inspirecv::Color::Magenta, 2);
|
||||
draw_img.DrawLine(points[2], points[3], inspirecv::Color::Pink, 2);
|
||||
draw_img.DrawLine(points[3], points[0], inspirecv::Color::Yellow, 2);
|
||||
draw_img.Write("cv/draw_line.jpg");
|
||||
|
||||
// Fill a rectangle
|
||||
draw_img = img.Clone();
|
||||
draw_img.Fill(new_rect, inspirecv::Color::Purple);
|
||||
draw_img.Write("cv/fill_rect.jpg");
|
||||
|
||||
// Reset
|
||||
std::vector<uint8_t> gray_color(img.Width() * img.Height() * 3, 128);
|
||||
img.Reset(img.Width(), img.Height(), 3, gray_color.data());
|
||||
img.Write("cv/reset.jpg");
|
||||
|
||||
/** FrameProcess */
|
||||
|
||||
// BGR888 as raw data
|
||||
inspirecv::Image raw = inspirecv::Image::Create("test_res/data/bulk/kun_cartoon_crop_r90.jpg", 3);
|
||||
const uint8_t* buffer = raw.Data();
|
||||
|
||||
// You can also use other image format, like NV21, NV12, RGBA, RGB, BGR, BGRA
|
||||
// const uint8_t* buffer = ...;
|
||||
|
||||
// Create frame process
|
||||
auto width = raw.Width();
|
||||
auto height = raw.Height();
|
||||
auto rotation_mode = inspirecv::ROTATION_90;
|
||||
auto data_format = inspirecv::BGR;
|
||||
inspirecv::FrameProcess frame_process = inspirecv::FrameProcess::Create(buffer, height, width, data_format, rotation_mode);
|
||||
|
||||
// Set preview size
|
||||
frame_process.SetPreviewSize(160);
|
||||
|
||||
// Set preview scale
|
||||
// frame_process.SetPreviewScale(0.5f);
|
||||
|
||||
// Get transform image
|
||||
inspirecv::Image transform_img = frame_process.ExecutePreviewImageProcessing(true);
|
||||
transform_img.Write("cv/transform_img.jpg");
|
||||
|
||||
// ExecuteImageAffineProcessing
|
||||
|
||||
// Face crop transform matrix
|
||||
// [[0.0, 0.726607, -61.8946],
|
||||
// [-0.726607, 0.0, 189.737]]
|
||||
a11 = 0.0f;
|
||||
a12 = 0.726607f;
|
||||
a21 = -0.726607;
|
||||
a22 = 0.0f;
|
||||
b1 = -61.8946f;
|
||||
b2 = 189.737f;
|
||||
inspirecv::TransformMatrix affine_matrix = inspirecv::TransformMatrix::Create(a11, a12, b1, a21, a22, b2);
|
||||
dst_width = 112;
|
||||
dst_height = 112;
|
||||
inspirecv::Image affine_img = frame_process.ExecuteImageAffineProcessing(affine_matrix, dst_width, dst_height);
|
||||
affine_img.Write("cv/affine_img.jpg");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include <inspireface/pipeline_module/attribute/face_attribute_adapt.h>
|
||||
#include "inspireface/initialization_module/launch.h"
|
||||
#include <inspireface/middleware/inspirecv_image_process.h>
|
||||
#include <inspirecv/time_spend.h>
|
||||
#include <inspireface/include/inspireface/launch.h>
|
||||
#include <inspireface/include/inspireface/frame_process.h>
|
||||
#include <inspireface/include/inspireface/spend_timer.h>
|
||||
#include <inspireface/include/inspireface/herror.h>
|
||||
#include <log.h>
|
||||
|
||||
using namespace inspire;
|
||||
@@ -10,8 +11,8 @@ using namespace inspire;
|
||||
int main() {
|
||||
INSPIRE_SET_LOG_LEVEL(ISF_LOG_DEBUG);
|
||||
std::string expansion_path = "";
|
||||
INSPIRE_LAUNCH->Load("test_res/pack/Gundam_RV1106");
|
||||
auto archive = INSPIRE_LAUNCH->getMArchive();
|
||||
INSPIREFACE_CONTEXT->Load("test_res/pack/Gundam_RV1106");
|
||||
auto archive = INSPIREFACE_CONTEXT->getMArchive();
|
||||
InspireModel detModel;
|
||||
auto ret = archive.LoadModel("face_attribute", detModel);
|
||||
if (ret != SARC_SUCCESS) {
|
||||
@@ -20,7 +21,7 @@ int main() {
|
||||
}
|
||||
|
||||
FaceAttributePredictAdapt face_attribute;
|
||||
face_attribute.loadData(detModel, detModel.modelType, false);
|
||||
face_attribute.LoadData(detModel, detModel.modelType, false);
|
||||
|
||||
auto img = inspirecv::Image::Create("test_res/data/crop/crop.png");
|
||||
auto result = face_attribute(img);
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include <inspireface/track_module/face_track_module.h>
|
||||
#include "inspireface/initialization_module/launch.h"
|
||||
#include <inspireface/middleware/inspirecv_image_process.h>
|
||||
#include <inspirecv/time_spend.h>
|
||||
#include <inspireface/include/inspireface/launch.h>
|
||||
#include <inspireface/include/inspireface/frame_process.h>
|
||||
#include <inspireface/include/inspireface/spend_timer.h>
|
||||
#include <inspireface/include/inspireface/herror.h>
|
||||
|
||||
using namespace inspire;
|
||||
|
||||
int main() {
|
||||
INSPIRE_SET_LOG_LEVEL(ISF_LOG_DEBUG);
|
||||
std::string expansion_path = "";
|
||||
INSPIRE_LAUNCH->Load("test_res/pack/Gundam_RV1106");
|
||||
auto archive = INSPIRE_LAUNCH->getMArchive();
|
||||
INSPIREFACE_CONTEXT->Load("test_res/pack/Gundam_RV1106");
|
||||
auto archive = INSPIREFACE_CONTEXT->getMArchive();
|
||||
InspireModel detModel;
|
||||
auto ret = archive.LoadModel("face_detect_160", detModel);
|
||||
if (ret != SARC_SUCCESS) {
|
||||
@@ -21,7 +22,7 @@ int main() {
|
||||
std::vector<int> input_size;
|
||||
input_size = detModel.Config().get<std::vector<int>>("input_size");
|
||||
|
||||
ret = face_detect.loadData(detModel, detModel.modelType, false);
|
||||
ret = face_detect.LoadData(detModel, detModel.modelType, false);
|
||||
if (ret != 0) {
|
||||
INSPIRE_LOGE("Load %s error: %d", "face_detect_160", ret);
|
||||
return HERR_ARCHIVE_LOAD_MODEL_FAILURE;
|
||||
@@ -31,7 +32,7 @@ int main() {
|
||||
|
||||
auto img = inspirecv::Image::Create("data/bulk/kun.jpg");
|
||||
|
||||
inspirecv::TimeSpend time_spend("Detect");
|
||||
inspire::SpendTimer time_spend("Detect");
|
||||
FaceLocList results;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
time_spend.Start();
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include <inspireface/middleware/nexus_processor/image_processor.h>
|
||||
#include <inspireface/image_process/nexus_processor/image_processor.h>
|
||||
#include "log.h"
|
||||
#include <inspirecv/time_spend.h>
|
||||
#include <inspireface/include/inspireface/spend_timer.h>
|
||||
#include <inspireface/include/inspireface/herror.h>
|
||||
|
||||
using namespace inspire;
|
||||
|
||||
@@ -18,7 +19,7 @@ int main() {
|
||||
uint8_t* resized_data = nullptr;
|
||||
int resized_width = 100;
|
||||
int resized_height = 100;
|
||||
inspirecv::TimeSpend time_spend("RGA resize");
|
||||
inspire::SpendTimer time_spend("RGA resize");
|
||||
for (int i = 0; i < 10; i++) {
|
||||
time_spend.Start();
|
||||
auto ret = processor->Resize(img.Data(), img.Width(), img.Height(), img.Channels(), &resized_data, resized_width, resized_height);
|
||||
@@ -37,7 +38,7 @@ int main() {
|
||||
processor->MarkDone();
|
||||
|
||||
uint8_t* swapped_data = nullptr;
|
||||
inspirecv::TimeSpend swap_time_spend("RGA swap color");
|
||||
inspire::SpendTimer swap_time_spend("RGA swap color");
|
||||
for (int i = 0; i < 10; i++) {
|
||||
swap_time_spend.Start();
|
||||
auto ret = processor->SwapColor(resized_img.Data(), resized_img.Width(), resized_img.Height(), resized_img.Channels(), &swapped_data);
|
||||
@@ -57,7 +58,7 @@ int main() {
|
||||
int bottom = 10;
|
||||
int left = 10;
|
||||
int right = 10;
|
||||
inspirecv::TimeSpend padding_time_spend("RGA padding");
|
||||
inspire::SpendTimer padding_time_spend("RGA padding");
|
||||
int padded_width = 0;
|
||||
int padded_height = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
@@ -76,7 +77,7 @@ int main() {
|
||||
|
||||
// inspirecv crop
|
||||
inspirecv::Rect2i rect(30, 30, 70, 70);
|
||||
inspirecv::TimeSpend inspirecv_crop_time_spend("InspireCV crop");
|
||||
inspire::SpendTimer inspirecv_crop_time_spend("InspireCV crop");
|
||||
inspirecv::Image inspirecv_cropped_img;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
inspirecv_crop_time_spend.Start();
|
||||
@@ -91,7 +92,7 @@ int main() {
|
||||
int dst_width = 320;
|
||||
int dst_height = 320;
|
||||
float scale = 0.0f;
|
||||
inspirecv::TimeSpend padded_crop_time_spend("RGA padded and cropped");
|
||||
inspire::SpendTimer padded_crop_time_spend("RGA padded and cropped");
|
||||
for (int i = 0; i < 10; i++) {
|
||||
padded_crop_time_spend.Start();
|
||||
auto ret = processor->ResizeAndPadding(image.Data(), image.Width(), image.Height(), image.Channels(), dst_width, dst_height,
|
||||
@@ -110,7 +111,7 @@ int main() {
|
||||
uint8_t* resized_data_2 = nullptr;
|
||||
int resized_width_2 = 512;
|
||||
int resized_height_2 = 512;
|
||||
inspirecv::TimeSpend time_spend_2("RGA resize 2");
|
||||
inspire::SpendTimer time_spend_2("RGA resize 2");
|
||||
for (int i = 0; i < 10; i++) {
|
||||
time_spend_2.Start();
|
||||
auto ret = processor->Resize(padded_cropped_img.Data(), padded_cropped_img.Width(), padded_cropped_img.Height(),
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include "inspireface/initialization_module/launch.h"
|
||||
#include <inspireface/include/inspireface/launch.h>
|
||||
#include "inspireface/middleware/model_archive/inspire_archive.h"
|
||||
#include "inspireface/track_module/face_detect/face_detect_adapt.h"
|
||||
#include "inspireface/track_module/landmark/face_landmark_adapt.h"
|
||||
#include "inspireface/track_module/quality/face_pose_quality_adapt.h"
|
||||
#include "inspireface/recognition_module/extract/extract_adapt.h"
|
||||
#include "inspireface/include/inspireface/spend_timer.h"
|
||||
|
||||
void test_face_detect() {
|
||||
inspire::InspireModel model;
|
||||
INSPIRE_LAUNCH->getMArchive().LoadModel("face_detect_160", model);
|
||||
INSPIREFACE_CONTEXT->getMArchive().LoadModel("face_detect_160", model);
|
||||
auto input_size = 160;
|
||||
inspire::FaceDetectAdapt faceDetectAdapt(input_size);
|
||||
faceDetectAdapt.loadData(model, model.modelType);
|
||||
faceDetectAdapt.LoadData(model, model.modelType);
|
||||
inspirecv::Image image = inspirecv::Image::Create("test_res/data/bulk/kun.jpg");
|
||||
inspire::FaceLocList faces;
|
||||
inspirecv::TimeSpend timeSpend("Face Detect@" + std::to_string(input_size));
|
||||
inspire::SpendTimer timeSpend("Face Detect@" + std::to_string(input_size));
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
timeSpend.Start();
|
||||
faces = faceDetectAdapt(image);
|
||||
timeSpend.Stop();
|
||||
}
|
||||
std::cout << timeSpend << std::endl;
|
||||
;
|
||||
std::cout << "faces size: " << faces.size() << std::endl;
|
||||
for (auto &face : faces) {
|
||||
inspirecv::Rect2i rect = inspirecv::Rect2i::Create(face.x1, face.y1, face.x2 - face.x1, face.y2 - face.y1);
|
||||
@@ -31,20 +33,21 @@ void test_face_detect() {
|
||||
|
||||
void test_landmark() {
|
||||
inspire::InspireModel model;
|
||||
INSPIRE_LAUNCH->getMArchive().LoadModel("landmark", model);
|
||||
INSPIREFACE_CONTEXT->getMArchive().LoadModel("landmark", model);
|
||||
auto input_size = 112;
|
||||
inspire::FaceLandmarkAdapt landmarkAdapt(input_size);
|
||||
landmarkAdapt.loadData(model, model.modelType);
|
||||
landmarkAdapt.LoadData(model, model.modelType);
|
||||
inspirecv::Image image = inspirecv::Image::Create("test_res/data/crop/crop.png");
|
||||
image = image.Resize(input_size, input_size);
|
||||
std::vector<float> lmk;
|
||||
inspirecv::TimeSpend timeSpend("Landmark@" + std::to_string(input_size));
|
||||
inspire::SpendTimer timeSpend("Landmark@" + std::to_string(input_size));
|
||||
timeSpend.Start();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
lmk = landmarkAdapt(image);
|
||||
}
|
||||
timeSpend.Stop();
|
||||
std::cout << timeSpend << std::endl;
|
||||
;
|
||||
for (int i = 0; i < inspire::FaceLandmarkAdapt::NUM_OF_LANDMARK; i++) {
|
||||
auto p = inspirecv::Point2i::Create(lmk[i * 2] * input_size, lmk[i * 2 + 1] * input_size);
|
||||
image.DrawCircle(p, 5, {0, 0, 255});
|
||||
@@ -54,20 +57,21 @@ void test_landmark() {
|
||||
|
||||
void test_quality() {
|
||||
inspire::InspireModel model;
|
||||
INSPIRE_LAUNCH->getMArchive().LoadModel("pose_quality", model);
|
||||
INSPIREFACE_CONTEXT->getMArchive().LoadModel("pose_quality", model);
|
||||
auto input_size = 96;
|
||||
inspire::FacePoseQualityAdapt poseQualityAdapt;
|
||||
poseQualityAdapt.loadData(model, model.modelType);
|
||||
poseQualityAdapt.LoadData(model, model.modelType);
|
||||
inspirecv::Image image = inspirecv::Image::Create("test_res/data/crop/crop.png");
|
||||
image = image.Resize(input_size, input_size);
|
||||
inspire::FacePoseQualityAdaptResult quality;
|
||||
inspirecv::TimeSpend timeSpend("Pose Quality@" + std::to_string(input_size));
|
||||
inspire::SpendTimer timeSpend("Pose Quality@" + std::to_string(input_size));
|
||||
timeSpend.Start();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
quality = poseQualityAdapt(image);
|
||||
}
|
||||
timeSpend.Stop();
|
||||
std::cout << timeSpend << std::endl;
|
||||
;
|
||||
std::cout << "quality: " << quality.pitch << ", " << quality.yaw << ", " << quality.roll << std::endl;
|
||||
for (int i = 0; i < quality.lmk.size(); i++) {
|
||||
std::cout << "lmk: " << quality.lmk[i].GetX() << ", " << quality.lmk[i].GetY() << std::endl;
|
||||
@@ -79,15 +83,15 @@ void test_quality() {
|
||||
|
||||
void test_feature() {
|
||||
inspire::InspireModel model;
|
||||
INSPIRE_LAUNCH->getMArchive().LoadModel("feature", model);
|
||||
INSPIREFACE_CONTEXT->getMArchive().LoadModel("feature", model);
|
||||
auto input_size = 112;
|
||||
inspire::ExtractAdapt extractAdapt;
|
||||
extractAdapt.loadData(model, model.modelType);
|
||||
extractAdapt.LoadData(model, model.modelType);
|
||||
inspirecv::Image image = inspirecv::Image::Create("test_res/data/crop/crop.png");
|
||||
image = image.Resize(input_size, input_size);
|
||||
float norm;
|
||||
bool normalize = true;
|
||||
inspirecv::TimeSpend timeSpend("Extract@" + std::to_string(input_size));
|
||||
inspire::SpendTimer timeSpend("Extract@" + std::to_string(input_size));
|
||||
timeSpend.Start();
|
||||
inspire::Embedded feature;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
@@ -95,12 +99,13 @@ void test_feature() {
|
||||
}
|
||||
timeSpend.Stop();
|
||||
std::cout << timeSpend << std::endl;
|
||||
;
|
||||
std::cout << "feature: " << feature.size() << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::string archivePath = "test_res/pack/Pikachu_Apple";
|
||||
INSPIRE_LAUNCH->Load(archivePath);
|
||||
INSPIREFACE_CONTEXT->Load(archivePath);
|
||||
// Test face detect
|
||||
test_face_detect();
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include <inspireface/track_module/face_track_module.h>
|
||||
#include "inspireface/initialization_module/launch.h"
|
||||
#include <inspireface/middleware/inspirecv_image_process.h>
|
||||
#include <inspireface/include/inspireface/launch.h>
|
||||
#include <inspireface/include/inspireface/frame_process.h>
|
||||
#include <inspireface/pipeline_module/face_pipeline_module.h>
|
||||
#include <inspireface/common/face_data/face_serialize_tools.h>
|
||||
#include <inspireface/feature_hub/feature_hub_db.h>
|
||||
#include <inspireface/include/inspireface/feature_hub_db.h>
|
||||
|
||||
using namespace inspire;
|
||||
|
||||
@@ -60,19 +60,19 @@ static std::vector<float> FT = {
|
||||
|
||||
int main() {
|
||||
std::string expansion_path = "";
|
||||
INSPIRE_LAUNCH->Load("test_res/pack/Pikachu");
|
||||
INSPIREFACE_CONTEXT->Load("test_res/pack/Pikachu");
|
||||
|
||||
DatabaseConfiguration configuration;
|
||||
configuration.primary_key_mode = PrimaryKeyMode::MANUAL_INPUT;
|
||||
configuration.enable_persistence = false;
|
||||
configuration.recognition_threshold = 0.48f;
|
||||
|
||||
FEATURE_HUB_DB->EnableHub(configuration);
|
||||
INSPIREFACE_FEATURE_HUB->EnableHub(configuration);
|
||||
|
||||
// std::vector<float> feature(512, 0.0f);
|
||||
|
||||
int64_t result_id = 0;
|
||||
auto ret = FEATURE_HUB_DB->FaceFeatureInsert(FT, 10086, result_id);
|
||||
auto ret = INSPIREFACE_FEATURE_HUB->FaceFeatureInsert(FT, 10086, result_id);
|
||||
if (ret != HSUCCEED) {
|
||||
INSPIRE_LOGE("Failed to insert face feature");
|
||||
INSPIRE_LOGI("result id: %lld", result_id);
|
||||
@@ -82,7 +82,7 @@ int main() {
|
||||
|
||||
// std::vector<float> query_feature(512, 20.0f);
|
||||
FaceSearchResult search_result;
|
||||
ret = FEATURE_HUB_DB->SearchFaceFeature(FT, search_result, true);
|
||||
ret = INSPIREFACE_FEATURE_HUB->SearchFaceFeature(FT, search_result, true);
|
||||
if (ret != HSUCCEED) {
|
||||
INSPIRE_LOGE("Failed to search face feature");
|
||||
} else {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include <iostream>
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include "inspireface/initialization_module/launch.h"
|
||||
#include <inspireface/middleware/inspirecv_image_process.h>
|
||||
#include <inspireface/include/inspireface/launch.h>
|
||||
#include <inspireface/include/inspireface/frame_process.h>
|
||||
#include "inspireface/track_module/landmark/face_landmark_adapt.h"
|
||||
int main() {
|
||||
std::string expansion_path = "";
|
||||
INSPIRE_LAUNCH->Load("test_res/pack/Pikachu-t4");
|
||||
auto archive = INSPIRE_LAUNCH->getMArchive();
|
||||
INSPIREFACE_CONTEXT->Load("test_res/pack/Pikachu-t4");
|
||||
auto archive = INSPIREFACE_CONTEXT->getMArchive();
|
||||
|
||||
inspire::InspireModel lmkModel;
|
||||
auto ret = archive.LoadModel("landmark", lmkModel);
|
||||
@@ -16,7 +16,7 @@ int main() {
|
||||
}
|
||||
|
||||
inspire::FaceLandmarkAdapt lmk;
|
||||
lmk.loadData(lmkModel, lmkModel.modelType);
|
||||
lmk.LoadData(lmkModel, lmkModel.modelType);
|
||||
|
||||
auto image = inspirecv::Image::Create("test_res/data/crop/crop.png");
|
||||
auto data = image.Resize(112, 112);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include <inspireface/track_module/face_track_module.h>
|
||||
#include "inspireface/initialization_module/launch.h"
|
||||
#include <inspireface/middleware/inspirecv_image_process.h>
|
||||
#include <inspireface/include/inspireface/launch.h>
|
||||
#include <inspireface/include/inspireface/frame_process.h>
|
||||
#include <inspireface/pipeline_module/face_pipeline_module.h>
|
||||
#include <inspireface/common/face_data/face_serialize_tools.h>
|
||||
|
||||
@@ -9,8 +9,8 @@ using namespace inspire;
|
||||
|
||||
int main() {
|
||||
std::string expansion_path = "";
|
||||
INSPIRE_LAUNCH->Load("test_res/pack/Pikachu");
|
||||
auto archive = INSPIRE_LAUNCH->getMArchive();
|
||||
INSPIREFACE_CONTEXT->Load("test_res/pack/Pikachu");
|
||||
auto archive = INSPIREFACE_CONTEXT->getMArchive();
|
||||
auto mode = inspire::DetectModuleMode::DETECT_MODE_LIGHT_TRACK;
|
||||
FaceTrackModule tracker(mode, 10, 20, 320, -1);
|
||||
tracker.Configuration(archive, expansion_path);
|
||||
@@ -18,7 +18,7 @@ int main() {
|
||||
FacePipelineModule pipe(archive, true, true, true, true);
|
||||
|
||||
auto image = inspirecv::Image::Create("test_res/data/bulk/r90.jpg");
|
||||
inspirecv::InspireImageProcess processor;
|
||||
inspirecv::FrameProcess processor;
|
||||
processor.SetDataBuffer(image.Data(), image.Height(), image.Width());
|
||||
processor.SetDataFormat(inspirecv::DATA_FORMAT::BGR);
|
||||
processor.SetRotationMode(inspirecv::ROTATION_MODE::ROTATION_90);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user