This commit is contained in:
tunm
2025-05-22 16:07:26 +08:00
parent efb5639ec6
commit 7e25e4e482
168 changed files with 6434 additions and 2527 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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() {

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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
};

View File

@@ -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

View File

@@ -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("================================================================");
}
};

View 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

View File

@@ -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

View File

@@ -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.

View File

@@ -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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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_;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -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

View File

@@ -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;

View File

@@ -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 {

View File

@@ -1 +1 @@
InspireFace Version: 1.2.0
InspireFace Version: 1.2.1

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View 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;
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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");

View File

@@ -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();

View File

@@ -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",

View File

@@ -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");

View File

@@ -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];

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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();

View File

@@ -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(),

View File

@@ -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();

View File

@@ -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 {

View File

@@ -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);

View File

@@ -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