From 3f3df61a0596c27cfdef8bec39a96d629e0c66b6 Mon Sep 17 00:00:00 2001 From: Jingyu Date: Sun, 19 Jan 2025 22:43:57 +0800 Subject: [PATCH 01/11] Modified key point stability --- cpp/inspireface/c_api/inspireface.cc | 33 +++++++++++++++++++ cpp/inspireface/c_api/inspireface.h | 27 +++++++++++++++ .../common/face_info/face_object_internal.h | 11 +++---- cpp/inspireface/face_session.cpp | 15 +++++++++ cpp/inspireface/face_session.h | 21 ++++++++++++ .../track_module/face_track_module.cpp | 32 ++++++++++++++++-- .../track_module/face_track_module.h | 19 +++++++++++ 7 files changed, 150 insertions(+), 8 deletions(-) diff --git a/cpp/inspireface/c_api/inspireface.cc b/cpp/inspireface/c_api/inspireface.cc index 0b71ae8e..390f1274 100644 --- a/cpp/inspireface/c_api/inspireface.cc +++ b/cpp/inspireface/c_api/inspireface.cc @@ -447,6 +447,39 @@ HResult HFSessionSetFaceDetectThreshold(HFSession session, HFloat threshold) { return ctx->impl.SetFaceDetectThreshold(threshold); } +HResult HFSessionSetTrackModeSmoothRatio(HFSession session, HFloat ratio) { + if (session == nullptr) { + return HERR_INVALID_CONTEXT_HANDLE; + } + HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession *)session; + if (ctx == nullptr) { + return HERR_INVALID_CONTEXT_HANDLE; + } + return ctx->impl.SetTrackModeSmoothRatio(ratio); +} + +HResult HFSessionSetTrackModeNumSmoothCacheFrame(HFSession session, HInt32 num) { + if (session == nullptr) { + return HERR_INVALID_CONTEXT_HANDLE; + } + HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession *)session; + if (ctx == nullptr) { + return HERR_INVALID_CONTEXT_HANDLE; + } + return ctx->impl.SetTrackModeNumSmoothCacheFrame(num); +} + +HResult HFSessionSetTrackModelDetectInterval(HFSession session, HInt32 num) { + if (session == nullptr) { + return HERR_INVALID_CONTEXT_HANDLE; + } + HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession *)session; + if (ctx == nullptr) { + return HERR_INVALID_CONTEXT_HANDLE; + } + return ctx->impl.SetTrackModelDetectInterval(num); +} + HResult HFExecuteFaceTrack(HFSession session, HFImageStream streamHandle, PHFMultipleFaceData results) { if (session == nullptr) { return HERR_INVALID_CONTEXT_HANDLE; diff --git a/cpp/inspireface/c_api/inspireface.h b/cpp/inspireface/c_api/inspireface.h index 2da60dc6..de17cee9 100644 --- a/cpp/inspireface/c_api/inspireface.h +++ b/cpp/inspireface/c_api/inspireface.h @@ -397,6 +397,33 @@ HYPER_CAPI_EXPORT extern HResult HFSessionSetFilterMinimumFacePixelSize(HFSessio */ HYPER_CAPI_EXPORT extern HResult HFSessionSetFaceDetectThreshold(HFSession session, HFloat threshold); +/** + * @brief Set the track mode smooth ratio in the session. default value is 0.025 + * + * @param session Handle to the session. + * @param ratio The smooth ratio value. + * @return HResult indicating the success or failure of the operation. + */ +HYPER_CAPI_EXPORT extern HResult HFSessionSetTrackModeSmoothRatio(HFSession session, HFloat ratio); + +/** + * @brief Set the track mode num smooth cache frame in the session. default value is 15 + * + * @param session Handle to the session. + * @param num The num smooth cache frame value. + * @return HResult indicating the success or failure of the operation. + */ +HYPER_CAPI_EXPORT extern HResult HFSessionSetTrackModeNumSmoothCacheFrame(HFSession session, HInt32 num); + +/** + * @brief Set the track model detect interval in the session. default value is 1 + * + * @param session Handle to the session. + * @param num The detect interval value. + * @return HResult indicating the success or failure of the operation. + */ +HYPER_CAPI_EXPORT extern HResult HFSessionSetTrackModelDetectInterval(HFSession session, HInt32 num); + /** * @brief Run face tracking in the session. * diff --git a/cpp/inspireface/common/face_info/face_object_internal.h b/cpp/inspireface/common/face_info/face_object_internal.h index fc4a3668..cf3cc627 100755 --- a/cpp/inspireface/common/face_info/face_object_internal.h +++ b/cpp/inspireface/common/face_info/face_object_internal.h @@ -28,13 +28,14 @@ class INSPIRE_API FaceObjectInternal { face_action_ = std::make_shared(10); } - void SetLandmark(const std::vector &lmk, bool update_rect = true, bool update_matrix = true) { + void SetLandmark(const std::vector &lmk, bool update_rect = true, bool update_matrix = true, float h = 0.06f, int n = 5) { if (lmk.size() != landmark_.size()) { INSPIRE_LOGW("The SetLandmark function displays an exception indicating that the lmk number does not match"); return; } std::copy(lmk.begin(), lmk.end(), landmark_.begin()); - DynamicSmoothParamUpdate(landmark_, landmark_smooth_aux_, 106 * 2, 0.06); + DynamicSmoothParamUpdate(landmark_, landmark_smooth_aux_, 106 * 2, h, n); + // std::cout << "smooth ratio: " << h << " num smooth cache frame: " << n << std::endl; // cv::Vec3d euler_angle; // EstimateHeadPose(landmark_, euler_angle_); @@ -162,8 +163,7 @@ class INSPIRE_API FaceObjectInternal { } void DynamicSmoothParamUpdate(std::vector &landmarks, std::vector> &landmarks_lastNframes, - int lm_length, float h) { - int n = 5; + int lm_length, float h = 0.06f, int n = 5) { std::vector landmarks_temp; landmarks_temp.assign(landmarks.begin(), landmarks.end()); if (landmarks_lastNframes.size() == n) { @@ -191,7 +191,7 @@ class INSPIRE_API FaceObjectInternal { landmarks_frame.push_back(inspirecv::Point2f(landmarks[i].GetX(), landmarks[i].GetY())); } landmarks_lastNframes.push_back(landmarks_frame); - if (landmarks_lastNframes.size() > 5) + if (landmarks_lastNframes.size() > n) landmarks_lastNframes.erase(landmarks_lastNframes.begin()); } @@ -230,7 +230,6 @@ class INSPIRE_API FaceObjectInternal { return bbox_; } - void setBbox(const inspirecv::Rect2i &bbox) { bbox_ = bbox; } diff --git a/cpp/inspireface/face_session.cpp b/cpp/inspireface/face_session.cpp index a2b07467..064f95a1 100644 --- a/cpp/inspireface/face_session.cpp +++ b/cpp/inspireface/face_session.cpp @@ -395,4 +395,19 @@ int32_t FaceSession::SetTrackFaceMinimumSize(int32_t minSize) { return HSUCCEED; } +int32_t FaceSession::SetTrackModeSmoothRatio(float value) { + m_face_track_->SetTrackModeSmoothRatio(value); + return HSUCCEED; +} + +int32_t FaceSession::SetTrackModeNumSmoothCacheFrame(int value) { + m_face_track_->SetTrackModeNumSmoothCacheFrame(value); + return HSUCCEED; +} + +int32_t FaceSession::SetTrackModelDetectInterval(int value) { + m_face_track_->SetTrackModelDetectInterval(value); + return HSUCCEED; +} + } // namespace inspire \ No newline at end of file diff --git a/cpp/inspireface/face_session.h b/cpp/inspireface/face_session.h index 0b73428a..39777613 100644 --- a/cpp/inspireface/face_session.h +++ b/cpp/inspireface/face_session.h @@ -313,6 +313,27 @@ class INSPIRE_API FaceSession { */ const float GetFaceFeatureNormCache() const; + /** + * @brief Set the track mode smooth ratio + * @param value The smooth ratio value + * @return int32_t Status code of the operation. + * */ + int32_t SetTrackModeSmoothRatio(float value); + + /** + * @brief Set the track mode num smooth cache frame + * @param value The num smooth cache frame value + * @return int32_t Status code of the operation. + * */ + int32_t SetTrackModeNumSmoothCacheFrame(int value); + + /** + * @brief Set the track model detect interval + * @param value The detect interval value + * @return int32_t Status code of the operation. + * */ + int32_t SetTrackModelDetectInterval(int value); + private: // Private member variables CustomPipelineParameter m_parameter_; ///< Stores custom parameters for the pipeline diff --git a/cpp/inspireface/track_module/face_track_module.cpp b/cpp/inspireface/track_module/face_track_module.cpp index fb4c7ca4..74d999d4 100644 --- a/cpp/inspireface/track_module/face_track_module.cpp +++ b/cpp/inspireface/track_module/face_track_module.cpp @@ -186,8 +186,22 @@ bool FaceTrackModule::TrackFace(inspirecv::InspireImageProcess &image, FaceObjec // INSPIRE_LOGD("Extensive Affine Cost %f", extensive_cost_time.GetCostTimeUpdate()); } } + // Replace the landmark with the high-quality landmark + landmark_back[FaceLandmarkAdapt::LEFT_EYE_CENTER] = face.high_result.lmk[0]; + landmark_back[FaceLandmarkAdapt::RIGHT_EYE_CENTER] = face.high_result.lmk[1]; + landmark_back[FaceLandmarkAdapt::NOSE_CORNER] = face.high_result.lmk[2]; + landmark_back[FaceLandmarkAdapt::MOUTH_LEFT_CORNER] = face.high_result.lmk[3]; + landmark_back[FaceLandmarkAdapt::MOUTH_RIGHT_CORNER] = face.high_result.lmk[4]; // Update face key points - face.SetLandmark(landmark_back, true); + face.SetLandmark(landmark_back, true, true, m_track_mode_smooth_ratio_, m_track_mode_num_smooth_cache_frame_); + // 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::LEFT_EYE_CENTER]; + face.high_result.lmk[1] = landmark_smooth[FaceLandmarkAdapt::RIGHT_EYE_CENTER]; + face.high_result.lmk[2] = landmark_smooth[FaceLandmarkAdapt::NOSE_CORNER]; + face.high_result.lmk[3] = landmark_smooth[FaceLandmarkAdapt::MOUTH_LEFT_CORNER]; + face.high_result.lmk[4] = landmark_smooth[FaceLandmarkAdapt::MOUTH_RIGHT_CORNER]; } // If tracking status, update the confidence level @@ -205,7 +219,8 @@ void FaceTrackModule::UpdateStream(inspirecv::InspireImageProcess &image) { detection_index_ += 1; if (m_mode_ == DETECT_MODE_ALWAYS_DETECT || m_mode_ == DETECT_MODE_TRACK_BY_DETECT) trackingFace.clear(); - if (detection_index_ % detection_interval_ == 0 || m_mode_ == DETECT_MODE_ALWAYS_DETECT || m_mode_ == DETECT_MODE_TRACK_BY_DETECT) { + if (trackingFace.empty() || 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); @@ -469,4 +484,17 @@ std::string FaceTrackModule::ChoiceMultiLevelDetectModel(const int32_t pixel_siz bool FaceTrackModule::IsDetectModeLandmark() const { return m_detect_mode_landmark_; } + +void FaceTrackModule::SetTrackModeSmoothRatio(float value) { + m_track_mode_smooth_ratio_ = value; +} + +void FaceTrackModule::SetTrackModeNumSmoothCacheFrame(int value) { + m_track_mode_num_smooth_cache_frame_ = value; +} + +void FaceTrackModule::SetTrackModelDetectInterval(int value) { + detection_interval_ = value; +} + } // namespace inspire diff --git a/cpp/inspireface/track_module/face_track_module.h b/cpp/inspireface/track_module/face_track_module.h index 2cb86f1a..ec9c68cc 100644 --- a/cpp/inspireface/track_module/face_track_module.h +++ b/cpp/inspireface/track_module/face_track_module.h @@ -159,6 +159,21 @@ class INSPIRE_API FaceTrackModule { */ bool IsDetectModeLandmark() const; + /** + * @brief Fix detect threshold + * */ + void SetTrackModeSmoothRatio(float value); + + /** + * @brief Fix detect threshold + * */ + void SetTrackModeNumSmoothCacheFrame(int value); + + /** + * @brief Fix detect interval + * */ + void SetTrackModelDetectInterval(int value); + public: std::vector trackingFace; ///< Vector of FaceObjects currently being tracked. @@ -189,6 +204,10 @@ class INSPIRE_API FaceTrackModule { std::string m_expansion_path_{""}; bool m_detect_mode_landmark_{true}; + + int m_track_mode_num_smooth_cache_frame_ = 15; + + float m_track_mode_smooth_ratio_ = 0.025; }; } // namespace inspire From f34a648753343219e2f6c8d6ab77c064bd0451fe Mon Sep 17 00:00:00 2001 From: Jingyu Date: Sun, 19 Jan 2025 23:27:02 +0800 Subject: [PATCH 02/11] Modified key point stability --- cpp/inspireface/CMakeLists.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cpp/inspireface/CMakeLists.txt b/cpp/inspireface/CMakeLists.txt index e8c52f2a..22c4ab1a 100644 --- a/cpp/inspireface/CMakeLists.txt +++ b/cpp/inspireface/CMakeLists.txt @@ -206,3 +206,16 @@ endif () if (ISF_RK_COMPILER_TYPE STREQUAL "aarch64") install(FILES ${ISF_RKNN_API_LIB}/librknnrt.so DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/lib) endif() + +if (NOT ISF_BUILD_SHARED_LIBS) + if(MNN_BUILD_SHARED_LIBS) + install(FILES ${CMAKE_BINARY_DIR}/3rdparty/MNN/libMNN.so DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/lib) + else() + install(FILES ${CMAKE_BINARY_DIR}/3rdparty/MNN/libMNN.a DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/lib) + endif() + if() + # To be added: The compilation of the RK series needs to be added + endif() + +endif() + From 2165d3a5243cc199845b82e6ea8f5606f2c077f3 Mon Sep 17 00:00:00 2001 From: Jingyu Date: Mon, 20 Jan 2025 00:20:55 +0800 Subject: [PATCH 03/11] Modified eyes corp --- .../pipeline_module/face_pipeline_module.cpp | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/cpp/inspireface/pipeline_module/face_pipeline_module.cpp b/cpp/inspireface/pipeline_module/face_pipeline_module.cpp index 19f9f0fe..18a3d75c 100644 --- a/cpp/inspireface/pipeline_module/face_pipeline_module.cpp +++ b/cpp/inspireface/pipeline_module/face_pipeline_module.cpp @@ -137,18 +137,33 @@ int32_t FacePipelineModule::Process(inspirecv::InspireImageProcess &processor, c new_rect.SetX(cx - new_rect.GetWidth() / 2); new_rect.SetY(cy - new_rect.GetHeight() / 2); - // Ensure rect stays within image bounds + // 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); } - if (new_rect.GetX() + new_rect.GetWidth() > originImage.Width()) { - new_rect.SetWidth(originImage.Width() - new_rect.GetX()); + + float rightOverflow = (new_rect.GetX() + new_rect.GetWidth()) - originImage.Width(); + if (rightOverflow > 0) { + new_rect.SetWidth(new_rect.GetWidth() - rightOverflow); } - if (new_rect.GetY() + new_rect.GetHeight() > originImage.Height()) { - new_rect.SetHeight(originImage.Height() - new_rect.GetY()); + + 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 pixels) + 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); From 0098eff3dfdf2f5b3baee1cf0df10c8951bed72f Mon Sep 17 00:00:00 2001 From: Jingyu Date: Mon, 20 Jan 2025 00:28:57 +0800 Subject: [PATCH 04/11] Modified eyes corp --- cpp/inspireface/pipeline_module/face_pipeline_module.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/inspireface/pipeline_module/face_pipeline_module.cpp b/cpp/inspireface/pipeline_module/face_pipeline_module.cpp index 18a3d75c..db781c73 100644 --- a/cpp/inspireface/pipeline_module/face_pipeline_module.cpp +++ b/cpp/inspireface/pipeline_module/face_pipeline_module.cpp @@ -160,7 +160,7 @@ int32_t FacePipelineModule::Process(inspirecv::InspireImageProcess &processor, c new_rect.SetHeight(new_rect.GetHeight() - bottomOverflow); } - // Maintain minimum size (e.g., 20x20 pixels) + // 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 From 934640a677248d1ce5f3c07928e47cb2733bb77f Mon Sep 17 00:00:00 2001 From: tunm Date: Mon, 20 Jan 2025 17:33:11 +0800 Subject: [PATCH 05/11] Add a more flexible ImageStream interface --- cpp/inspireface/CMakeLists.txt | 4 +- cpp/inspireface/c_api/inspireface.cc | 78 +++++++++++++++++++ cpp/inspireface/c_api/inspireface.h | 65 +++++++++++++++- cpp/inspireface/c_api/intypedef.h | 1 + cpp/inspireface/feature_hub/feature_hub_db.h | 8 +- .../track_module/face_track_module.h | 12 +-- 6 files changed, 156 insertions(+), 12 deletions(-) diff --git a/cpp/inspireface/CMakeLists.txt b/cpp/inspireface/CMakeLists.txt index 22c4ab1a..e56a6683 100644 --- a/cpp/inspireface/CMakeLists.txt +++ b/cpp/inspireface/CMakeLists.txt @@ -40,6 +40,7 @@ if (ISF_ENABLE_RKNN) # For rknpu2 with armv7, we recommend linking static libraries by default set(ISF_RKNN_API_LIB ${ISF_THIRD_PARTY_DIR}/inspireface-precompile-lite/rknn/${ISF_RKNPU_MAJOR}/runtime/${RK_PLATFORM}/librknn_api/${ISF_RK_COMPILER_TYPE}/librknnmrt.a) set(RKNN_LINKED ${ISF_RKNN_API_LIB}) + set(RKNN_USE_STATIC_LIBS TRUE) endif() endif() @@ -213,8 +214,9 @@ if (NOT ISF_BUILD_SHARED_LIBS) else() install(FILES ${CMAKE_BINARY_DIR}/3rdparty/MNN/libMNN.a DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/lib) endif() - if() + if(RKNN_USE_STATIC_LIBS) # To be added: The compilation of the RK series needs to be added + install(FILES ${ISF_RKNN_API_LIB} DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/lib) endif() endif() diff --git a/cpp/inspireface/c_api/inspireface.cc b/cpp/inspireface/c_api/inspireface.cc index 390f1274..729d252f 100644 --- a/cpp/inspireface/c_api/inspireface.cc +++ b/cpp/inspireface/c_api/inspireface.cc @@ -66,6 +66,74 @@ HYPER_CAPI_EXPORT extern HResult HFCreateImageStream(PHFImageData data, HFImageS return HSUCCEED; } +HYPER_CAPI_EXPORT extern HResult HFCreateImageStreamEmpty(HFImageStream *handle) { + if (handle == nullptr) { + return HERR_INVALID_IMAGE_STREAM_HANDLE; + } + auto stream = new HF_CameraStream(); + *handle = (HFImageStream)stream; + return HSUCCEED; +} + +HYPER_CAPI_EXPORT extern HResult HFImageStreamSetBuffer(HFImageStream handle, HPUInt8 buffer, HInt32 width, HInt32 height) { + if (handle == nullptr) { + return HERR_INVALID_IMAGE_STREAM_HANDLE; + } + ((HF_CameraStream *)handle)->impl.SetDataBuffer(buffer, width, height); + return HSUCCEED; +} + +HYPER_CAPI_EXPORT extern HResult HFImageStreamSetRotation(HFImageStream handle, HFRotation rotation) { + if (handle == nullptr) { + return HERR_INVALID_IMAGE_STREAM_HANDLE; + } + switch (rotation) { + case HF_CAMERA_ROTATION_90: + ((HF_CameraStream *)handle)->impl.SetRotationMode(inspirecv::ROTATION_90); + break; + case HF_CAMERA_ROTATION_180: + ((HF_CameraStream *)handle)->impl.SetRotationMode(inspirecv::ROTATION_180); + break; + case HF_CAMERA_ROTATION_270: + ((HF_CameraStream *)handle)->impl.SetRotationMode(inspirecv::ROTATION_270); + break; + default: + ((HF_CameraStream *)handle)->impl.SetRotationMode(inspirecv::ROTATION_0); + break; + } + return HSUCCEED; +} + +HYPER_CAPI_EXPORT extern HResult HFImageStreamSetFormat(HFImageStream handle, HFImageFormat format) { + if (handle == nullptr) { + return HERR_INVALID_IMAGE_STREAM_HANDLE; + } + switch (format) { + case HF_STREAM_RGB: + ((HF_CameraStream *)handle)->impl.SetDataFormat(inspirecv::RGB); + break; + case HF_STREAM_BGR: + ((HF_CameraStream *)handle)->impl.SetDataFormat(inspirecv::BGR); + break; + case HF_STREAM_RGBA: + ((HF_CameraStream *)handle)->impl.SetDataFormat(inspirecv::RGBA); + break; + case HF_STREAM_BGRA: + ((HF_CameraStream *)handle)->impl.SetDataFormat(inspirecv::BGRA); + break; + case HF_STREAM_YUV_NV12: + ((HF_CameraStream *)handle)->impl.SetDataFormat(inspirecv::NV12); + break; + case HF_STREAM_YUV_NV21: + ((HF_CameraStream *)handle)->impl.SetDataFormat(inspirecv::NV21); + break; + default: + return HERR_INVALID_IMAGE_STREAM_PARAM; // Assume there's a return code for unsupported + // formats + } + return HSUCCEED; +} + HYPER_CAPI_EXPORT extern HResult HFReleaseImageStream(HFImageStream streamHandle) { if (streamHandle == nullptr) { return HERR_INVALID_IMAGE_STREAM_HANDLE; @@ -372,6 +440,16 @@ HResult HFQueryExpansiveHardwareRockchipDmaHeapPath(HString path) { return HSUCCEED; } +HResult HFSetExpansiveHardwareAppleCoreMLModelPath(HString path) { + // TODO: Implement this function + return HSUCCEED; +} + +HResult HFQueryExpansiveHardwareAppleCoreMLModelPath(HString path) { + // TODO: Implement this function + return HSUCCEED; +} + HResult HFFeatureHubDataEnable(HFFeatureHubConfiguration configuration) { inspire::DatabaseConfiguration param; if (configuration.primaryKeyMode != HF_PK_AUTO_INCREMENT && configuration.primaryKeyMode != HF_PK_MANUAL_INPUT) { diff --git a/cpp/inspireface/c_api/inspireface.h b/cpp/inspireface/c_api/inspireface.h index de17cee9..df86e066 100644 --- a/cpp/inspireface/c_api/inspireface.h +++ b/cpp/inspireface/c_api/inspireface.h @@ -64,7 +64,7 @@ typedef enum HFRotation { * Defines the structure for image data stream. */ typedef struct HFImageData { - uint8_t *data; ///< Pointer to the image data stream. + HPUInt8 data; ///< Pointer to the image data stream. HInt32 width; ///< Width of the image. HInt32 height; ///< Height of the image. HFImageFormat format; ///< Format of the image, indicating the data stream format to be parsed. @@ -82,6 +82,45 @@ typedef struct HFImageData { */ HYPER_CAPI_EXPORT extern HResult HFCreateImageStream(PHFImageData data, HFImageStream *handle); +/** + * @brief Create an empty image stream instance. + * + * This function is used to create an instance of a data buffer stream with the given image data. + * + * @param handle Pointer to the stream handle that will be returned. + * @return HResult indicating the success or failure of the operation. + */ +HYPER_CAPI_EXPORT extern HResult HFCreateImageStreamEmpty(HFImageStream *handle); + +/** + * @brief Set the buffer of the image stream. + * + * @param handle Pointer to the stream handle. + * @param buffer Pointer to the buffer. + * @param width Width of the image. + * @param height Height of the image. + * @return HResult indicating the success or failure of the operation. + */ +HYPER_CAPI_EXPORT extern HResult HFImageStreamSetBuffer(HFImageStream handle, HPUInt8 buffer, HInt32 width, HInt32 height); + +/** + * @brief Set the rotation of the image stream. + * + * @param handle Pointer to the stream handle. + * @param rotation Rotation angle of the image. + * @return HResult indicating the success or failure of the operation. + */ +HYPER_CAPI_EXPORT extern HResult HFImageStreamSetRotation(HFImageStream handle, HFRotation rotation); + +/** + * @brief Set the format of the image stream. + * + * @param handle Pointer to the stream handle. + * @param format Format of the image. + * @return HResult indicating the success or failure of the operation. + */ +HYPER_CAPI_EXPORT extern HResult HFImageStreamSetFormat(HFImageStream handle, HFImageFormat format); + /** * @brief Release the instantiated DataBuffer object. * @@ -238,6 +277,15 @@ HYPER_CAPI_EXPORT extern HResult HFTerminateInspireFace(); * */ HYPER_CAPI_EXPORT extern HResult HFQueryInspireFaceLaunchStatus(HInt32 *status); +/************************************************************************ + * Extended Interface Based on Third-party Hardware Devices + * + * According to different manufacturers' devices, manufacturers typically perform deep customization and optimization, such as neural network + * inference computation, geometric image acceleration computation, and deeply customized device interfaces, etc. These types of functionalities are + * usually difficult to abstract, so they are placed in extension module APIs, involving hybrid computing, heterogeneous computing, multi-device + * computing, and other features. + ************************************************************************/ + /** * @brief Set the rockchip dma heap path * By default, we have already configured the DMA Heap address used by RGA on RK devices. @@ -255,6 +303,21 @@ HYPER_CAPI_EXPORT extern HResult HFSetExpansiveHardwareRockchipDmaHeapPath(HPath * */ HYPER_CAPI_EXPORT extern HResult HFQueryExpansiveHardwareRockchipDmaHeapPath(HString path); +/** + * @brief Set the Apple CoreML model path. In normal circumstances, manual modification is not needed. + * @param path The path to the apple coreml model + * @return HResult indicating the success or failure of the operation. + * */ +HYPER_CAPI_EXPORT extern HResult HFSetExpansiveHardwareAppleCoreMLModelPath(HString path); + +/** + * @brief Query the Apple CoreML model path. After executing HFLaunchInspireFace, it's typically your input filename plus the suffix '.mlmodelc', for + * example: Pikachu and Pikachu.mlmodelc + * @param path Query the apple coreml model path + * @return HResult indicating the success or failure of the operation. + * */ +HYPER_CAPI_EXPORT extern HResult HFQueryExpansiveHardwareAppleCoreMLModelPath(HString path); + /************************************************************************ * FaceSession ************************************************************************/ diff --git a/cpp/inspireface/c_api/intypedef.h b/cpp/inspireface/c_api/intypedef.h index d7a1525c..66ca0b01 100644 --- a/cpp/inspireface/c_api/intypedef.h +++ b/cpp/inspireface/c_api/intypedef.h @@ -17,6 +17,7 @@ typedef float HFloat; ///< Single-precisi typedef float* HPFloat; ///< Pointer to Single-precision floating point. typedef double HDouble; ///< Double-precision floating point. typedef unsigned char HUInt8; ///< Unsigned 8-bit integer. +typedef unsigned char* HPUInt8; ///< Pointer to unsigned 8-bit integer. typedef signed int HInt32; ///< Signed 32-bit integer. typedef signed int HOption; ///< Signed 32-bit integer option. typedef signed int* HPInt32; ///< Pointer to signed 32-bit integer. diff --git a/cpp/inspireface/feature_hub/feature_hub_db.h b/cpp/inspireface/feature_hub/feature_hub_db.h index 8e6c74e4..102d5b6b 100644 --- a/cpp/inspireface/feature_hub/feature_hub_db.h +++ b/cpp/inspireface/feature_hub/feature_hub_db.h @@ -255,11 +255,11 @@ class INSPIRE_API FeatureHubDB { Embedded m_getter_face_feature_cache_; ///< Cache for face feature data used in search operations std::shared_ptr m_face_feature_ptr_cache_; ///< Shared pointer to cache of face feature pointers - std::vector m_search_top_k_cache_; - std::vector m_top_k_confidence_; - std::vector m_top_k_custom_ids_cache_; + std::vector m_search_top_k_cache_; ///< Cache for top k search results + std::vector m_top_k_confidence_; ///< Cache for top k confidence scores + std::vector m_top_k_custom_ids_cache_; ///< Cache for top k custom ids - std::vector m_all_ids_; + std::vector m_all_ids_; ///< Cache for all ids private: DatabaseConfiguration m_db_configuration_; ///< Configuration settings for the database diff --git a/cpp/inspireface/track_module/face_track_module.h b/cpp/inspireface/track_module/face_track_module.h index ec9c68cc..33cbc4ae 100644 --- a/cpp/inspireface/track_module/face_track_module.h +++ b/cpp/inspireface/track_module/face_track_module.h @@ -196,18 +196,18 @@ class INSPIRE_API FaceTrackModule { std::shared_ptr m_TbD_tracker_; ///< Shared pointer to the Bytetrack. int m_dynamic_detection_input_level_ = -1; ///< Detector size class for dynamic input. - float m_crop_extensive_ratio_ = 1.8f; - int m_crop_extensive_size_ = 96; + float m_crop_extensive_ratio_ = 1.8f; ///< Crop extensive ratio + int m_crop_extensive_size_ = 96; ///< Crop extensive size DetectModuleMode m_mode_; ///< Detect mode - std::string m_expansion_path_{""}; + std::string m_expansion_path_{""}; ///< Expand the path if you need it. - bool m_detect_mode_landmark_{true}; + bool m_detect_mode_landmark_{true}; ///< Detect mode landmark - int m_track_mode_num_smooth_cache_frame_ = 15; + int m_track_mode_num_smooth_cache_frame_ = 15; ///< Track mode number of smooth cache frame - float m_track_mode_smooth_ratio_ = 0.025; + float m_track_mode_smooth_ratio_ = 0.025; ///< Track mode smooth ratio }; } // namespace inspire From 5d529f4aba4932fe8693d100ac986bc7d1987cfb Mon Sep 17 00:00:00 2001 From: tunm Date: Mon, 20 Jan 2025 18:04:06 +0800 Subject: [PATCH 06/11] Add a more flexible ImageStream interface --- tools/transform_similarity_testing.py | 69 +++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 tools/transform_similarity_testing.py diff --git a/tools/transform_similarity_testing.py b/tools/transform_similarity_testing.py new file mode 100644 index 00000000..daee90fa --- /dev/null +++ b/tools/transform_similarity_testing.py @@ -0,0 +1,69 @@ +import numpy as np +import matplotlib.pyplot as plt + +def transform_similarity(cosine_sim, threshold=0.48, target_score=0.6, steepness=15): + """ + Transform cosine similarity to a percentage score between 0-1 + + Parameters: + cosine_sim (float): Input cosine similarity value (between -1 and 1) + threshold (float): Cosine threshold considered as passing grade (default 0.48) + target_score (float): Target score for threshold value (default 0.6) + steepness (float): Steepness of the sigmoid curve (default 15) + + Returns: + float: Transformed score between 0-1 + """ + # Map cosine value to sigmoid domain (typically between -6 and 6) + x = steepness * (cosine_sim - threshold) + + # Apply base sigmoid function + base_sigmoid = 1 / (1 + np.exp(-x)) + + # Linear transform to make output equal target_score when cosine_sim = threshold + # Base sigmoid output value at threshold + threshold_base = 0.5 # because sigmoid(0) = 0.5 + + # Linear transform parameters + scale = (1.0 - target_score) / (1.0 - threshold_base) + + # Apply linear transform + final_score = target_score + scale * (base_sigmoid - threshold_base) + + # Ensure result is between 0-1 + return np.clip(final_score, 0, 1) + +if __name__ == "__main__": + # Generate test values + values1 = np.arange(-1.0, 0.0, 0.25) # From -1 to 0, step 0.25 + values2 = np.arange(0.0, 1.01, 0.05) # From 0 to 1, step 0.05 + test_values = np.concatenate([values1, values2]) + + # Calculate scores for each value + scores = [transform_similarity(val) for val in test_values] + + # Create plot + plt.figure(figsize=(10, 6)) + plt.plot(test_values, scores, 'b-', label='Transformation curve') + + # Mark threshold point + threshold = 0.48 + threshold_score = transform_similarity(threshold) + plt.plot(threshold, threshold_score, 'ro', label=f'Threshold ({threshold}, {threshold_score:.2f})') + plt.annotate(f'({threshold}, {threshold_score:.2f})', + xy=(threshold, threshold_score), + xytext=(threshold-0.2, threshold_score+0.1), + arrowprops=dict(facecolor='red', shrink=0.05)) + + # Customize plot + plt.grid(True, linestyle='--', alpha=0.7) + plt.xlabel('Cosine Similarity') + plt.ylabel('Transformed Score') + plt.title('Cosine Similarity Transformation Curve') + plt.legend() + + # Add reference lines + plt.axvline(x=threshold, color='r', linestyle='--', alpha=0.3) + plt.axhline(y=threshold_score, color='r', linestyle='--', alpha=0.3) + + plt.show() \ No newline at end of file From 2da412927627b384e25fd22264529206e7714e38 Mon Sep 17 00:00:00 2001 From: tunm Date: Mon, 20 Jan 2025 18:18:56 +0800 Subject: [PATCH 07/11] Add a more flexible ImageStream interface --- tools/transform_similarity_testing.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/transform_similarity_testing.py b/tools/transform_similarity_testing.py index daee90fa..d2f55212 100644 --- a/tools/transform_similarity_testing.py +++ b/tools/transform_similarity_testing.py @@ -1,7 +1,7 @@ import numpy as np import matplotlib.pyplot as plt -def transform_similarity(cosine_sim, threshold=0.48, target_score=0.6, steepness=15): +def transform_similarity(cosine_sim, threshold=0.48, target_score=0.6, steepness=10): """ Transform cosine similarity to a percentage score between 0-1 @@ -14,21 +14,26 @@ def transform_similarity(cosine_sim, threshold=0.48, target_score=0.6, steepness Returns: float: Transformed score between 0-1 """ - # Map cosine value to sigmoid domain (typically between -6 and 6) + # Map cosine value to sigmoid domain x = steepness * (cosine_sim - threshold) # Apply base sigmoid function base_sigmoid = 1 / (1 + np.exp(-x)) + # Scale the sigmoid output to start from 0 instead of 0.5 + shifted_sigmoid = 2 * base_sigmoid - 1 + + # Now shifted_sigmoid ranges from -1 to 1, scale it to 0 to 1 + normalized = (shifted_sigmoid + 1) / 2 + # Linear transform to make output equal target_score when cosine_sim = threshold - # Base sigmoid output value at threshold - threshold_base = 0.5 # because sigmoid(0) = 0.5 + threshold_base = 0.5 # the value of normalized when cosine_sim = threshold # Linear transform parameters scale = (1.0 - target_score) / (1.0 - threshold_base) # Apply linear transform - final_score = target_score + scale * (base_sigmoid - threshold_base) + final_score = target_score + scale * (normalized - threshold_base) # Ensure result is between 0-1 return np.clip(final_score, 0, 1) From b9ed6373949551c483432aa852fb04b7cc1388a0 Mon Sep 17 00:00:00 2001 From: Jingyu Date: Tue, 21 Jan 2025 00:27:39 +0800 Subject: [PATCH 08/11] Add Similarity Converter --- .../model_archive/inspire_archive.h | 20 +++ .../similarity_converter.cpp | 9 + .../recognition_module/similarity_converter.h | 96 +++++++++++ cpp/test/settings/enviro.h | 2 +- .../unit/api/test_similarity_converter.cpp | 51 ++++++ python/test/test_settings.py | 2 +- tools/transform_similarity_testing.py | 156 +++++++++++------- 7 files changed, 273 insertions(+), 63 deletions(-) create mode 100644 cpp/inspireface/recognition_module/similarity_converter.cpp create mode 100644 cpp/inspireface/recognition_module/similarity_converter.h create mode 100644 cpp/test/unit/api/test_similarity_converter.cpp diff --git a/cpp/inspireface/middleware/model_archive/inspire_archive.h b/cpp/inspireface/middleware/model_archive/inspire_archive.h index 64b20aea..8e574773 100644 --- a/cpp/inspireface/middleware/model_archive/inspire_archive.h +++ b/cpp/inspireface/middleware/model_archive/inspire_archive.h @@ -9,6 +9,7 @@ #include "inspire_model/inspire_model.h" #include "yaml-cpp/yaml.h" #include "fstream" +#include "recognition_module/similarity_converter.h" namespace inspire { @@ -89,6 +90,25 @@ class INSPIRE_API InspireArchive : SimpleArchive { m_tag_ = m_config_["tag"].as(); m_version_ = m_config_["version"].as(); INSPIRE_LOGI("== %s %s ==", m_tag_.c_str(), m_version_.c_str()); + // Load similarity converter config + if (m_config_["similarity_converter"]) { + SimilarityConverterConfig config; + config.threshold = m_config_["similarity_converter"]["threshold"].as(); + config.middleScore = m_config_["similarity_converter"]["middle_score"].as(); + config.steepness = m_config_["similarity_converter"]["steepness"].as(); + config.outputMin = m_config_["similarity_converter"]["output_min"].as(); + config.outputMax = m_config_["similarity_converter"]["output_max"].as(); + SIMILARITY_CONVERTER_UPDATE_CONFIG(config); + INSPIRE_LOGI( + "Successfully loaded similarity converter config: \n \t threshold: %f \n \t middle_score: %f \n \t steepness: %f \n \t output_min: " + "%f \n \t output_max: %f", + config.threshold, config.middleScore, config.steepness, config.outputMin, config.outputMax); + } else { + INSPIRE_LOGW("No similarity converter config found, use default config: "); + auto config = SIMILARITY_CONVERTER_GET_CONFIG(); + INSPIRE_LOGI("threshold: %f \n \t middle_score: %f \n \t steepness: %f \n \t output_min: %f \n \t output_max: %f", config.threshold, + config.middleScore, config.steepness, config.outputMin, config.outputMax); + } } return 0; } diff --git a/cpp/inspireface/recognition_module/similarity_converter.cpp b/cpp/inspireface/recognition_module/similarity_converter.cpp new file mode 100644 index 00000000..d1f972ee --- /dev/null +++ b/cpp/inspireface/recognition_module/similarity_converter.cpp @@ -0,0 +1,9 @@ +#include +#include "similarity_converter.h" + +namespace inspire { + +SimilarityConverter* SimilarityConverter::instance = nullptr; +std::mutex SimilarityConverter::instanceMutex; + +} // namespace inspire diff --git a/cpp/inspireface/recognition_module/similarity_converter.h b/cpp/inspireface/recognition_module/similarity_converter.h new file mode 100644 index 00000000..ab9e0847 --- /dev/null +++ b/cpp/inspireface/recognition_module/similarity_converter.h @@ -0,0 +1,96 @@ +#ifndef SIMILARITY_CONVERTER_H +#define SIMILARITY_CONVERTER_H + +#include +#include +#include + +#define SIMILARITY_CONVERTER_UPDATE_CONFIG(config) inspire::SimilarityConverter::getInstance().updateConfig(config) +#define SIMILARITY_CONVERTER_RUN(cosine) inspire::SimilarityConverter::getInstance().convert(cosine) +#define SIMILARITY_CONVERTER_GET_CONFIG() inspire::SimilarityConverter::getInstance().getConfig() + +namespace inspire { + +struct SimilarityConverterConfig { + double threshold = 0.42; // Similarity threshold (e.g. 0.48 or 0.32) + double middleScore = 0.6; // Target score at threshold (e.g. 0.6) + double steepness = 8.0; // Steepness of the curve + double outputMin = 0.01; // Minimum value of output range + double outputMax = 1.0; // Maximum value of output range +}; + +class SimilarityConverter { +private: + SimilarityConverterConfig config; + double outputScale; // Scale of output range + double bias; // Sigmoid bias + mutable std::mutex configMutex; // Mutex for protecting config updates + + static SimilarityConverter* instance; + static std::mutex instanceMutex; + + // Update internal calculation parameters + void updateParameters() { + outputScale = config.outputMax - config.outputMin; + bias = -std::log((config.outputMax - config.middleScore) / (config.middleScore - config.outputMin)); + } + +public: + // Get global singleton instance + static SimilarityConverter& getInstance() { + std::lock_guard lock(instanceMutex); + if (instance == nullptr) { + instance = new SimilarityConverter(); + } + return *instance; + } + + // Allow external creation of new instances + explicit SimilarityConverter(const SimilarityConverterConfig& config = SimilarityConverterConfig()) : config(config) { + updateParameters(); + } + + // Prevent copying + SimilarityConverter(const SimilarityConverter&) = delete; + SimilarityConverter& operator=(const SimilarityConverter&) = delete; + + // Update configuration (thread-safe) + void updateConfig(const SimilarityConverterConfig& newConfig) { + std::lock_guard lock(configMutex); + config = newConfig; + updateParameters(); + } + + // Get current configuration (thread-safe) + SimilarityConverterConfig getConfig() const { + std::lock_guard lock(configMutex); + return config; + } + + // Convert similarity (thread-safe) + template + double convert(T cosine) { + std::lock_guard lock(configMutex); + // Calculate shifted input + double shiftedInput = config.steepness * (static_cast(cosine) - config.threshold); + // Apply sigmoid function + double sigmoid = 1.0 / (1.0 + std::exp(-shiftedInput - bias)); + // Map to output range + return sigmoid * outputScale + config.outputMin; + } + + // Clean up singleton instance + static void destroyInstance() { + std::lock_guard lock(instanceMutex); + if (instance != nullptr) { + delete instance; + instance = nullptr; + } + } + + ~SimilarityConverter() = default; +}; // class SimilarityConverter + +} // namespace inspire + +#endif // SIMILARITY_CONVERTER_H \ No newline at end of file diff --git a/cpp/test/settings/enviro.h b/cpp/test/settings/enviro.h index 339f9784..6ee472fd 100644 --- a/cpp/test/settings/enviro.h +++ b/cpp/test/settings/enviro.h @@ -52,7 +52,7 @@ class Enviro { private: Enviro() {} - std::string packName{"Pikachu"}; + std::string packName{"Pikachu-t3"}; std::string testResDir{"test_res"}; std::string runtimeFullPath; }; diff --git a/cpp/test/unit/api/test_similarity_converter.cpp b/cpp/test/unit/api/test_similarity_converter.cpp new file mode 100644 index 00000000..f83d01a2 --- /dev/null +++ b/cpp/test/unit/api/test_similarity_converter.cpp @@ -0,0 +1,51 @@ +/** + * Created by Jingyu Yan + * @date 2025-01-20 + */ +#include +#include "settings/test_settings.h" +#include "unit/test_helper/test_help.h" +#include "inspireface/recognition_module/similarity_converter.h" + +TEST_CASE("test_similarity_converter", "[similarity_converter]") { + DRAW_SPLIT_LINE + TEST_PRINT_OUTPUT(true); + + SECTION("test_similarity_converter_0.42") { + inspire::SimilarityConverterConfig config; + config.threshold = 0.42; + config.middleScore = 0.6; + config.steepness = 8.0; + config.outputMin = 0.01; + config.outputMax = 1.0; + inspire::SimilarityConverter similarity_converter(config); + std::vector test_points = {-0.80, -0.20, 0.02, 0.10, 0.25, 0.30, 0.48, 0.70, 0.80, 0.90, 1.00}; + std::vector expected_scores = {0.0101, 0.0201, 0.0661, 0.1113, 0.2819, 0.3673, 0.7074, 0.9334, 0.9689, 0.9858, 0.9936}; + REQUIRE(test_points.size() == expected_scores.size()); + + for (size_t i = 0; i < test_points.size(); ++i) { + double cosine = test_points[i]; + double similarity = similarity_converter.convert(cosine); + REQUIRE(similarity == Approx(expected_scores[i]).epsilon(0.01)); + } + } + + SECTION("test_similarity_converter_0.32") { + inspire::SimilarityConverterConfig config; + config.threshold = 0.32; + config.middleScore = 0.6; + config.steepness = 10.0; + config.outputMin = 0.02; + config.outputMax = 1.0; + inspire::SimilarityConverter similarity_converter(config); + std::vector test_points = {-0.80, -0.20, 0.02, 0.10, 0.25, 0.32, 0.50, 0.70, 0.80, 0.90, 1.00}; + std::vector expected_scores = {0.0200, 0.0278, 0.0860, 0.1557, 0.4302, 0.6000, 0.8997, 0.9851, 0.9945, 0.9980, 0.9992}; + REQUIRE(test_points.size() == expected_scores.size()); + + for (size_t i = 0; i < test_points.size(); ++i) { + double cosine = test_points[i]; + double similarity = similarity_converter.convert(cosine); + REQUIRE(similarity == Approx(expected_scores[i]).epsilon(0.01)); + } + } +} \ No newline at end of file diff --git a/python/test/test_settings.py b/python/test/test_settings.py index 22cd279f..4c764bbc 100644 --- a/python/test/test_settings.py +++ b/python/test/test_settings.py @@ -18,7 +18,7 @@ ENABLE_LFW_PRECISION_TEST = False # Testing model name -TEST_MODEL_NAME = "Pikachu" +TEST_MODEL_NAME = "Pikachu-t3" # TEST_MODEL_NAME = "Megatron" # Testing length of face feature diff --git a/tools/transform_similarity_testing.py b/tools/transform_similarity_testing.py index daee90fa..db17866b 100644 --- a/tools/transform_similarity_testing.py +++ b/tools/transform_similarity_testing.py @@ -1,69 +1,103 @@ import numpy as np import matplotlib.pyplot as plt -def transform_similarity(cosine_sim, threshold=0.48, target_score=0.6, steepness=15): - """ - Transform cosine similarity to a percentage score between 0-1 +class SimilarityConverter: + def __init__(self, + threshold=0.48, + middle_score=0.6, + steepness=8.0, + output_range=(0.01, 0.99)): + self.threshold = threshold + self.middle_score = middle_score + self.steepness = steepness + self.output_min, self.output_max = output_range + self.output_scale = self.output_max - self.output_min + + self.bias = -np.log((self.output_max - self.middle_score)/(self.middle_score - self.output_min)) + + def convert(self, cosine): + shifted_input = self.steepness * (cosine - self.threshold) + sigmoid = 1 / (1 + np.exp(-shifted_input - self.bias)) + return sigmoid * self.output_scale + self.output_min - Parameters: - cosine_sim (float): Input cosine similarity value (between -1 and 1) - threshold (float): Cosine threshold considered as passing grade (default 0.48) - target_score (float): Target score for threshold value (default 0.6) - steepness (float): Steepness of the sigmoid curve (default 15) - - Returns: - float: Transformed score between 0-1 - """ - # Map cosine value to sigmoid domain (typically between -6 and 6) - x = steepness * (cosine_sim - threshold) - - # Apply base sigmoid function - base_sigmoid = 1 / (1 + np.exp(-x)) - - # Linear transform to make output equal target_score when cosine_sim = threshold - # Base sigmoid output value at threshold - threshold_base = 0.5 # because sigmoid(0) = 0.5 - - # Linear transform parameters - scale = (1.0 - target_score) / (1.0 - threshold_base) - - # Apply linear transform - final_score = target_score + scale * (base_sigmoid - threshold_base) - - # Ensure result is between 0-1 - return np.clip(final_score, 0, 1) + def plot(self, test_points=None): + x = np.linspace(-1, 1, 200) + y = self.convert(x) + + plt.figure(figsize=(12, 6)) + plt.plot(x, y, '-', label='Conversion Function', color='blue') + + if test_points is not None: + test_scores = self.convert(test_points) + plt.plot(test_points, test_scores, 'ro', label='Test Points') + + for point, score in zip(test_points, test_scores): + plt.annotate(f'({point:.2f}, {score:.3f})', + xy=(point, score), + xytext=(10, 10), + textcoords='offset points') + + plt.axvline(x=self.threshold, color='gray', linestyle='--', alpha=0.5, + label=f'Threshold ({self.threshold:.2f})') + plt.axhline(y=self.middle_score, color='gray', linestyle='--', alpha=0.5) + + plt.plot(self.threshold, self.middle_score, 'r*', markersize=15, + label='Passing Point', color='red', zorder=5) + + plt.annotate(f'Passing Point\n({self.threshold:.2f}, {self.middle_score:.2f})', + xy=(self.threshold, self.middle_score), + xytext=(30, 20), + textcoords='offset points', + bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5), + arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0', + color='red', lw=2)) + + + plt.fill_between(x, y, 0, + where=(x >= self.threshold), + alpha=0.1, color='green', + label='Passing Region') + + plt.grid(True, alpha=0.3) + plt.xlabel('Cosine Similarity') + plt.ylabel('Converted Score') + plt.title('Similarity Score Conversion') + plt.legend() + plt.xlim(-1.1, 1.1) + plt.ylim(-0.1, 1.1) + plt.tight_layout() + plt.show() if __name__ == "__main__": - # Generate test values - values1 = np.arange(-1.0, 0.0, 0.25) # From -1 to 0, step 0.25 - values2 = np.arange(0.0, 1.01, 0.05) # From 0 to 1, step 0.05 - test_values = np.concatenate([values1, values2]) - - # Calculate scores for each value - scores = [transform_similarity(val) for val in test_values] - - # Create plot - plt.figure(figsize=(10, 6)) - plt.plot(test_values, scores, 'b-', label='Transformation curve') - - # Mark threshold point - threshold = 0.48 - threshold_score = transform_similarity(threshold) - plt.plot(threshold, threshold_score, 'ro', label=f'Threshold ({threshold}, {threshold_score:.2f})') - plt.annotate(f'({threshold}, {threshold_score:.2f})', - xy=(threshold, threshold_score), - xytext=(threshold-0.2, threshold_score+0.1), - arrowprops=dict(facecolor='red', shrink=0.05)) - - # Customize plot - plt.grid(True, linestyle='--', alpha=0.7) - plt.xlabel('Cosine Similarity') - plt.ylabel('Transformed Score') - plt.title('Cosine Similarity Transformation Curve') - plt.legend() + # Set the threshold to 0.42 + converter1 = SimilarityConverter( + threshold=0.42, + middle_score=0.6, + steepness=8.0, + output_range=(0.01, 1.0) + ) + test_points1 = np.array([-0.8, -0.2, 0.02, 0.1, 0.25, 0.3, 0.48, 0.7, 0.8, 0.9, 1.0]) + print("\nModel 1 (Threshold = 0.48):") + converter1.plot(test_points1) - # Add reference lines - plt.axvline(x=threshold, color='r', linestyle='--', alpha=0.3) - plt.axhline(y=threshold_score, color='r', linestyle='--', alpha=0.3) + # Set the threshold to 0.32 + converter2 = SimilarityConverter( + threshold=0.32, + middle_score=0.6, + steepness=10.0, + output_range=(0.02, 1.0) + ) + test_points2 = np.array([-0.8, -0.2, 0.02, 0.1, 0.25,0.32, 0.5, 0.7, 0.8, 0.9, 1.0]) + print("\nModel 2 (Threshold = 0.32):") + converter2.plot(test_points2) - plt.show() \ No newline at end of file + # Print the results + print("\nTest Results for Model 1 (threshold=0.48):") + for point in test_points1: + score = converter1.convert(point) + print(f"Cosine: {point:6.2f} -> Score: {score:.4f}") + + print("\nTest Results for Model 2 (threshold=0.32):") + for point in test_points2: + score = converter2.convert(point) + print(f"Cosine: {point:6.2f} -> Score: {score:.4f}") \ No newline at end of file From 9a9b981e043c11a6ff91db7d1f6c92be1acc53cc Mon Sep 17 00:00:00 2001 From: tunm Date: Tue, 21 Jan 2025 13:59:02 +0800 Subject: [PATCH 09/11] Add some threshold tools --- .../sdk/inspireface/InspireFace.java | 42 ++++++++++ .../base/SimilarityConverterConfig.java | 9 +++ cpp/inspireface/c_api/inspireface.cc | 2 +- cpp/inspireface/c_api/inspireface.h | 6 +- .../platform/jni/android/inspireface_jni.cpp | 78 +++++++++++++++++++ cpp/sample/CMakeLists.txt | 1 + cpp/sample/api/sample_face_comparison.cpp | 12 +-- cpp/sample/api/sample_face_track.cpp | 2 +- cpp/sample/api/sample_feature_hub.cpp | 2 +- cpp/sample/api/sample_load_reload.cpp | 2 +- 10 files changed, 144 insertions(+), 12 deletions(-) create mode 100644 android/InspireFaceExample/inspireface/src/main/java/com/insightface/sdk/inspireface/base/SimilarityConverterConfig.java diff --git a/android/InspireFaceExample/inspireface/src/main/java/com/insightface/sdk/inspireface/InspireFace.java b/android/InspireFaceExample/inspireface/src/main/java/com/insightface/sdk/inspireface/InspireFace.java index 7ed91cdc..77eba29e 100644 --- a/android/InspireFaceExample/inspireface/src/main/java/com/insightface/sdk/inspireface/InspireFace.java +++ b/android/InspireFaceExample/inspireface/src/main/java/com/insightface/sdk/inspireface/InspireFace.java @@ -20,6 +20,7 @@ import com.insightface.sdk.inspireface.base.RGBLivenessConfidence; import com.insightface.sdk.inspireface.base.SearchTopKResults; import com.insightface.sdk.inspireface.base.Session; +import com.insightface.sdk.inspireface.base.SimilarityConverterConfig; import com.insightface.sdk.inspireface.base.TypeDefine; import com.insightface.sdk.inspireface.utils.SDKUtils; @@ -214,6 +215,27 @@ public static CustomParameter CreateCustomParameter(boolean enableRecognition, b */ public static native void SetFaceDetectThreshold(Session session, float threshold); + /** + * Set track mode smooth ratio, default value is 0.025 + * @param session Session object + * @param ratio Smooth ratio + */ + public static native void SetTrackModeSmoothRatio(Session session, float ratio); + + /** + * Set track mode num smooth cache frame, default value is 15 + * @param session Session object + * @param num Num smooth cache frame + */ + public static native void SetTrackModeNumSmoothCacheFrame(Session session, int num); + + /** + * Set track mode detect interval, default value is 20 + * @param session Session object + * @param interval Detect interval + */ + public static native void SetTrackModeDetectInterval(Session session, int interval); + /** * Enable feature hub data * @param configuration FeatureHubConfiguration object @@ -288,6 +310,26 @@ public static CustomParameter CreateCustomParameter(boolean enableRecognition, b */ public static native int GetFeatureLength(); + + /** + * Get cosine similarity converter + * @return SimilarityConverterConfig object + */ + public static native SimilarityConverterConfig GetCosineSimilarityConverter(); + + /** + * Update cosine similarity converter + * @param config SimilarityConverterConfig object + */ + public static native void UpdateCosineSimilarityConverter(SimilarityConverterConfig config); + + /** + * Convert cosine similarity to percentage + * @param similarity Cosine similarity + * @return Percentage similarity + */ + public static native float CosineSimilarityConvertToPercentage(float similarity); + /** * Face comparison * @param feature1 FaceFeature object diff --git a/android/InspireFaceExample/inspireface/src/main/java/com/insightface/sdk/inspireface/base/SimilarityConverterConfig.java b/android/InspireFaceExample/inspireface/src/main/java/com/insightface/sdk/inspireface/base/SimilarityConverterConfig.java new file mode 100644 index 00000000..d4517d72 --- /dev/null +++ b/android/InspireFaceExample/inspireface/src/main/java/com/insightface/sdk/inspireface/base/SimilarityConverterConfig.java @@ -0,0 +1,9 @@ +package com.insightface.sdk.inspireface.base; + +public class SimilarityConverterConfig { + public float threshold; + public float middleScore; + public float steepness; + public float outputMin; + public float outputMax; +} diff --git a/cpp/inspireface/c_api/inspireface.cc b/cpp/inspireface/c_api/inspireface.cc index 0221eba0..63d7d9ad 100644 --- a/cpp/inspireface/c_api/inspireface.cc +++ b/cpp/inspireface/c_api/inspireface.cc @@ -548,7 +548,7 @@ HResult HFSessionSetTrackModeNumSmoothCacheFrame(HFSession session, HInt32 num) return ctx->impl.SetTrackModeNumSmoothCacheFrame(num); } -HResult HFSessionSetTrackModelDetectInterval(HFSession session, HInt32 num) { +HResult HFSessionSetTrackModeDetectInterval(HFSession session, HInt32 num) { if (session == nullptr) { return HERR_INVALID_CONTEXT_HANDLE; } diff --git a/cpp/inspireface/c_api/inspireface.h b/cpp/inspireface/c_api/inspireface.h index a3125ef3..3135488d 100644 --- a/cpp/inspireface/c_api/inspireface.h +++ b/cpp/inspireface/c_api/inspireface.h @@ -485,7 +485,7 @@ HYPER_CAPI_EXPORT extern HResult HFSessionSetTrackModeNumSmoothCacheFrame(HFSess * @param num The detect interval value. * @return HResult indicating the success or failure of the operation. */ -HYPER_CAPI_EXPORT extern HResult HFSessionSetTrackModelDetectInterval(HFSession session, HInt32 num); +HYPER_CAPI_EXPORT extern HResult HFSessionSetTrackModeDetectInterval(HFSession session, HInt32 num); /** * @brief Run face tracking in the session. @@ -702,13 +702,15 @@ HYPER_CAPI_EXPORT extern HResult HFFeatureHubFaceSearchThresholdSetting(float th HYPER_CAPI_EXPORT extern HResult HFFaceComparison(HFFaceFeature feature1, HFFaceFeature feature2, HPFloat result); /** - * @brief Get the recommended cosine threshold. + * @brief Get recommended cosine threshold from loaded resource. + * Use it to determine face similarity. Note: it's just a reference and may not be optimal for your task. * @return HResult indicating the success or failure of the operation. */ HYPER_CAPI_EXPORT extern HResult HFGetRecommendedCosineThreshold(HPFloat threshold); /** * @brief Convert cosine similarity to percentage similarity. + * This is a nonlinear transformation function. You can adjust curve parameters to map the similarity distribution you need. * @note The conversion parameters are primarily read from the Resource file configuration, as different models * have different conversion parameters. The parameters provided in the Resource file are only reference * values. If they do not meet your specific use case requirements, you can implement your own conversion diff --git a/cpp/inspireface/platform/jni/android/inspireface_jni.cpp b/cpp/inspireface/platform/jni/android/inspireface_jni.cpp index b02b86c0..2c1eec0d 100644 --- a/cpp/inspireface/platform/jni/android/inspireface_jni.cpp +++ b/cpp/inspireface/platform/jni/android/inspireface_jni.cpp @@ -492,6 +492,37 @@ JNIEXPORT void INSPIRE_FACE_JNI(InspireFace_SetFaceDetectThreshold)(JNIEnv *env, INSPIRE_LOGE("Failed to set face detect threshold, error code: %d", result); } } + +JNIEXPORT void INSPIRE_FACE_JNI(InspireFace_SetTrackModeSmoothRatio)(JNIEnv *env, jobject thiz, jobject session, jfloat ratio) { + jclass sessionClass = env->GetObjectClass(session); + jfieldID sessionHandleField = env->GetFieldID(sessionClass, "handle", "J"); + jlong sessionHandle = env->GetLongField(session, sessionHandleField); + auto result = HFSessionSetTrackModeSmoothRatio((HFSession)sessionHandle, ratio); + if (result != HSUCCEED) { + INSPIRE_LOGE("Failed to set track mode smooth ratio, error code: %d", result); + } +} + +JNIEXPORT void INSPIRE_FACE_JNI(InspireFace_SetTrackModeNumSmoothCacheFrame)(JNIEnv *env, jobject thiz, jobject session, jint num) { + jclass sessionClass = env->GetObjectClass(session); + jfieldID sessionHandleField = env->GetFieldID(sessionClass, "handle", "J"); + jlong sessionHandle = env->GetLongField(session, sessionHandleField); + auto result = HFSessionSetTrackModeNumSmoothCacheFrame((HFSession)sessionHandle, num); + if (result != HSUCCEED) { + INSPIRE_LOGE("Failed to set track mode num smooth cache frame, error code: %d", result); + } +} + +JNIEXPORT void INSPIRE_FACE_JNI(InspireFace_SetTrackModeDetectInterval)(JNIEnv *env, jobject thiz, jobject session, jint interval) { + jclass sessionClass = env->GetObjectClass(session); + jfieldID sessionHandleField = env->GetFieldID(sessionClass, "handle", "J"); + jlong sessionHandle = env->GetLongField(session, sessionHandleField); + auto result = HFSessionSetTrackModeDetectInterval((HFSession)sessionHandle, interval); + if (result != HSUCCEED) { + INSPIRE_LOGE("Failed to set track mode detect interval, error code: %d", result); + } +} + JNIEXPORT jboolean INSPIRE_FACE_JNI(InspireFace_FeatureHubDataEnable)(JNIEnv *env, jobject thiz, jobject configuration) { jclass configClass = env->GetObjectClass(configuration); @@ -816,6 +847,53 @@ JNIEXPORT jint INSPIRE_FACE_JNI(InspireFace_GetFeatureLength)(JNIEnv *env, jobje return length; } +JNIEXPORT void INSPIRE_FACE_JNI(InspireFace_UpdateCosineSimilarityConverter)(JNIEnv *env, jobject thiz, jobject config) { + jclass configClass = env->GetObjectClass(config); + jfieldID thresholdField = env->GetFieldID(configClass, "threshold", "F"); + jfieldID middleScoreField = env->GetFieldID(configClass, "middleScore", "F"); + jfieldID steepnessField = env->GetFieldID(configClass, "steepness", "F"); + jfieldID outputMinField = env->GetFieldID(configClass, "outputMin", "F"); + jfieldID outputMaxField = env->GetFieldID(configClass, "outputMax", "F"); + + HFSimilarityConverterConfig converterConfig; + converterConfig.threshold = env->GetFloatField(config, thresholdField); + converterConfig.middleScore = env->GetFloatField(config, middleScoreField); + converterConfig.steepness = env->GetFloatField(config, steepnessField); + converterConfig.outputMin = env->GetFloatField(config, outputMinField); + converterConfig.outputMax = env->GetFloatField(config, outputMaxField); + HFUpdateCosineSimilarityConverter(converterConfig); +} + +JNIEXPORT jobject INSPIRE_FACE_JNI(InspireFace_GetCosineSimilarityConverter)(JNIEnv *env, jobject thiz) { + HFSimilarityConverterConfig converterConfig; + HFGetCosineSimilarityConverter(&converterConfig); + jclass configClass = env->FindClass("com/insightface/sdk/inspireface/base/SimilarityConverterConfig"); + jmethodID constructor = env->GetMethodID(configClass, "", "()V"); + jobject configObj = env->NewObject(configClass, constructor); + + // Get field IDs + jfieldID thresholdField = env->GetFieldID(configClass, "threshold", "F"); + jfieldID middleScoreField = env->GetFieldID(configClass, "middleScore", "F"); + jfieldID steepnessField = env->GetFieldID(configClass, "steepness", "F"); + jfieldID outputMinField = env->GetFieldID(configClass, "outputMin", "F"); + jfieldID outputMaxField = env->GetFieldID(configClass, "outputMax", "F"); + + // Set fields + env->SetFloatField(configObj, thresholdField, converterConfig.threshold); + env->SetFloatField(configObj, middleScoreField, converterConfig.middleScore); + env->SetFloatField(configObj, steepnessField, converterConfig.steepness); + env->SetFloatField(configObj, outputMinField, converterConfig.outputMin); + env->SetFloatField(configObj, outputMaxField, converterConfig.outputMax); + + return configObj; +} + +JNIEXPORT jfloat INSPIRE_FACE_JNI(InspireFace_CosineSimilarityConvertToPercentage)(JNIEnv *env, jobject thiz, jfloat similarity) { + HFloat result; + HFCosineSimilarityConvertToPercentage(similarity, &result); + return result; +} + JNIEXPORT jfloat INSPIRE_FACE_JNI(InspireFace_FaceComparison)(JNIEnv *env, jobject thiz, jobject feature1, jobject feature2) { if (feature1 == nullptr || feature2 == nullptr) { return -1.0f; diff --git a/cpp/sample/CMakeLists.txt b/cpp/sample/CMakeLists.txt index a97d04a9..e9d23ec0 100644 --- a/cpp/sample/CMakeLists.txt +++ b/cpp/sample/CMakeLists.txt @@ -4,6 +4,7 @@ project(InspireFaceSample) option(ISF_BUILD_SAMPLE_CLUTTERED "Whether to compile the cluttered sample program (debug code during development)" OFF) include_directories(${SRC_DIR}) +include_directories(${SRC_DIR}/inspireface/c_api) 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}/) diff --git a/cpp/sample/api/sample_face_comparison.cpp b/cpp/sample/api/sample_face_comparison.cpp index 158aacc8..ce835198 100644 --- a/cpp/sample/api/sample_face_comparison.cpp +++ b/cpp/sample/api/sample_face_comparison.cpp @@ -4,7 +4,7 @@ */ #include #include -#include "inspireface/c_api/inspireface.h" +#include int main(int argc, char* argv[]) { // Check whether the number of parameters is correct @@ -112,14 +112,14 @@ int main(int argc, char* argv[]) { } if (similarity > recommended_cosine_threshold) { - HFLogPrint(HF_LOG_INFO, "Cosine similarity %.3f is greater than recommended threshold %.3f - Same person", similarity, - recommended_cosine_threshold); + HFLogPrint(HF_LOG_INFO, "%.3f > %.3f ✓ Same face", similarity, recommended_cosine_threshold); } else { - HFLogPrint(HF_LOG_WARN, "Cosine similarity %.3f is less than recommended threshold %.3f - Different person", similarity, - recommended_cosine_threshold); + HFLogPrint(HF_LOG_WARN, "%.3f < %.3f ✗ Different face", similarity, recommended_cosine_threshold); } + HFLogPrint(HF_LOG_INFO, "Similarity score: %.3f", similarity); - HFLogPrint(HF_LOG_INFO, "Similarity: %f", 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) { diff --git a/cpp/sample/api/sample_face_track.cpp b/cpp/sample/api/sample_face_track.cpp index 85eabc1f..ee4650e1 100644 --- a/cpp/sample/api/sample_face_track.cpp +++ b/cpp/sample/api/sample_face_track.cpp @@ -3,7 +3,7 @@ * @date 2024-10-01 */ #include -#include "inspireface/c_api/inspireface.h" +#include int main(int argc, char* argv[]) { // Check whether the number of parameters is correct diff --git a/cpp/sample/api/sample_feature_hub.cpp b/cpp/sample/api/sample_feature_hub.cpp index 90ff257b..72f8f9e9 100644 --- a/cpp/sample/api/sample_feature_hub.cpp +++ b/cpp/sample/api/sample_feature_hub.cpp @@ -1,5 +1,5 @@ #include -#include "inspireface/c_api/inspireface.h" +#include #include static std::vector FT = { diff --git a/cpp/sample/api/sample_load_reload.cpp b/cpp/sample/api/sample_load_reload.cpp index a4815f09..c62a1745 100644 --- a/cpp/sample/api/sample_load_reload.cpp +++ b/cpp/sample/api/sample_load_reload.cpp @@ -1,5 +1,5 @@ #include -#include "inspireface/c_api/inspireface.h" +#include int main() { std::string resourcePath = "test_res/pack/Pikachu"; From f8baa52d3b4ad9625e3d9bac1b66162f72504230 Mon Sep 17 00:00:00 2001 From: tunm Date: Tue, 21 Jan 2025 14:07:27 +0800 Subject: [PATCH 10/11] Add some threshold tools --- python/inspireface/modules/__init__.py | 2 +- python/inspireface/modules/inspireface.py | 5 +++++ python/pull_models.py | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 python/pull_models.py diff --git a/python/inspireface/modules/__init__.py b/python/inspireface/modules/__init__.py index cdc71155..c1f57a99 100644 --- a/python/inspireface/modules/__init__.py +++ b/python/inspireface/modules/__init__.py @@ -4,5 +4,5 @@ feature_hub_face_search, feature_hub_face_search_top_k, feature_hub_face_update, feature_hub_face_remove, \ feature_hub_get_face_identity, feature_hub_get_face_count, view_table_in_terminal, version, query_launch_status, reload, \ set_logging_level, disable_logging, show_system_resource_statistics, get_recommended_cosine_threshold, cosine_similarity_convert_to_percentage, \ - get_similarity_converter_config, set_similarity_converter_config, \ + get_similarity_converter_config, set_similarity_converter_config, pull_latest_model, \ HF_PK_AUTO_INCREMENT, HF_PK_MANUAL_INPUT, HF_SEARCH_MODE_EAGER, HF_SEARCH_MODE_EXHAUSTIVE \ No newline at end of file diff --git a/python/inspireface/modules/inspireface.py b/python/inspireface/modules/inspireface.py index 0d912912..c3193619 100644 --- a/python/inspireface/modules/inspireface.py +++ b/python/inspireface/modules/inspireface.py @@ -619,6 +619,11 @@ def launch(model_name: str = "Pikachu", resource_path: str = None) -> bool: return False return True +def pull_latest_model(model_name: str = "Pikachu") -> str: + sm = ResourceManager() + resource_path = sm.get_model(model_name, re_download=True) + return resource_path + def reload(model_name: str = "Pikachu", resource_path: str = None) -> bool: if resource_path is None: sm = ResourceManager() diff --git a/python/pull_models.py b/python/pull_models.py new file mode 100644 index 00000000..5e9e4e68 --- /dev/null +++ b/python/pull_models.py @@ -0,0 +1,4 @@ +import inspireface + +for model in ["Pikachu", "Megatron"]: + inspireface.pull_latest_model(model) From 44532d411cf1ab962daa45e8fc11d9bd937353a5 Mon Sep 17 00:00:00 2001 From: tunm Date: Tue, 21 Jan 2025 14:31:33 +0800 Subject: [PATCH 11/11] Add some threshold tools --- cpp/inspireface/c_api/inspireface.cc | 2 +- cpp/inspireface/face_session.cpp | 4 ++-- cpp/inspireface/face_session.h | 2 +- .../track_module/face_track_module.cpp | 2 +- .../track_module/face_track_module.h | 21 +++++++++++-------- python/inspireface/modules/core/native.py | 8 +++---- python/inspireface/modules/inspireface.py | 2 +- 7 files changed, 22 insertions(+), 19 deletions(-) diff --git a/cpp/inspireface/c_api/inspireface.cc b/cpp/inspireface/c_api/inspireface.cc index 63d7d9ad..21dc766f 100644 --- a/cpp/inspireface/c_api/inspireface.cc +++ b/cpp/inspireface/c_api/inspireface.cc @@ -556,7 +556,7 @@ HResult HFSessionSetTrackModeDetectInterval(HFSession session, HInt32 num) { if (ctx == nullptr) { return HERR_INVALID_CONTEXT_HANDLE; } - return ctx->impl.SetTrackModelDetectInterval(num); + return ctx->impl.SetTrackModeDetectInterval(num); } HResult HFExecuteFaceTrack(HFSession session, HFImageStream streamHandle, PHFMultipleFaceData results) { diff --git a/cpp/inspireface/face_session.cpp b/cpp/inspireface/face_session.cpp index 064f95a1..ccda723c 100644 --- a/cpp/inspireface/face_session.cpp +++ b/cpp/inspireface/face_session.cpp @@ -405,8 +405,8 @@ int32_t FaceSession::SetTrackModeNumSmoothCacheFrame(int value) { return HSUCCEED; } -int32_t FaceSession::SetTrackModelDetectInterval(int value) { - m_face_track_->SetTrackModelDetectInterval(value); +int32_t FaceSession::SetTrackModeDetectInterval(int value) { + m_face_track_->SetTrackModeDetectInterval(value); return HSUCCEED; } diff --git a/cpp/inspireface/face_session.h b/cpp/inspireface/face_session.h index 39777613..5b3d8c84 100644 --- a/cpp/inspireface/face_session.h +++ b/cpp/inspireface/face_session.h @@ -332,7 +332,7 @@ class INSPIRE_API FaceSession { * @param value The detect interval value * @return int32_t Status code of the operation. * */ - int32_t SetTrackModelDetectInterval(int value); + int32_t SetTrackModeDetectInterval(int value); private: // Private member variables diff --git a/cpp/inspireface/track_module/face_track_module.cpp b/cpp/inspireface/track_module/face_track_module.cpp index 74d999d4..a590bf44 100644 --- a/cpp/inspireface/track_module/face_track_module.cpp +++ b/cpp/inspireface/track_module/face_track_module.cpp @@ -493,7 +493,7 @@ void FaceTrackModule::SetTrackModeNumSmoothCacheFrame(int value) { m_track_mode_num_smooth_cache_frame_ = value; } -void FaceTrackModule::SetTrackModelDetectInterval(int value) { +void FaceTrackModule::SetTrackModeDetectInterval(int value) { detection_interval_ = value; } diff --git a/cpp/inspireface/track_module/face_track_module.h b/cpp/inspireface/track_module/face_track_module.h index 33cbc4ae..6fdee1f9 100644 --- a/cpp/inspireface/track_module/face_track_module.h +++ b/cpp/inspireface/track_module/face_track_module.h @@ -144,12 +144,12 @@ class INSPIRE_API FaceTrackModule { public: /** - * @brief Fix detect threshold + * @brief Set the detect threshold * */ void SetDetectThreshold(float value); /** - * @brief Fix detect threshold + * @brief Set the minimum face size * */ void SetMinimumFacePxSize(float value); @@ -160,19 +160,22 @@ class INSPIRE_API FaceTrackModule { bool IsDetectModeLandmark() const; /** - * @brief Fix detect threshold - * */ + * @brief Sets the smoothing ratio for landmark tracking + * @param value Smoothing ratio between 0 and 1, smaller values mean stronger smoothing + */ void SetTrackModeSmoothRatio(float value); /** - * @brief Fix detect threshold - * */ + * @brief Set the number of smooth cache frame + * @param value Number of frames to cache for smoothing + */ void SetTrackModeNumSmoothCacheFrame(int value); /** - * @brief Fix detect interval - * */ - void SetTrackModelDetectInterval(int value); + * @brief Set the detect interval + * @param value Interval between detections + */ + void SetTrackModeDetectInterval(int value); public: std::vector trackingFace; ///< Vector of FaceObjects currently being tracked. diff --git a/python/inspireface/modules/core/native.py b/python/inspireface/modules/core/native.py index c86ea5eb..86e6d356 100644 --- a/python/inspireface/modules/core/native.py +++ b/python/inspireface/modules/core/native.py @@ -1415,10 +1415,10 @@ class struct_HFMultipleFaceData(Structure): HFSessionSetTrackModeNumSmoothCacheFrame.restype = HResult # /Users/tunm/work/InspireFace/cpp/inspireface/c_api/inspireface.h: 488 -if _libs[_LIBRARY_FILENAME].has("HFSessionSetTrackModelDetectInterval", "cdecl"): - HFSessionSetTrackModelDetectInterval = _libs[_LIBRARY_FILENAME].get("HFSessionSetTrackModelDetectInterval", "cdecl") - HFSessionSetTrackModelDetectInterval.argtypes = [HFSession, HInt32] - HFSessionSetTrackModelDetectInterval.restype = HResult +if _libs[_LIBRARY_FILENAME].has("HFSessionSetTrackModeDetectInterval", "cdecl"): + HFSessionSetTrackModeDetectInterval = _libs[_LIBRARY_FILENAME].get("HFSessionSetTrackModeDetectInterval", "cdecl") + HFSessionSetTrackModeDetectInterval.argtypes = [HFSession, HInt32] + HFSessionSetTrackModeDetectInterval.restype = HResult # /Users/tunm/work/InspireFace/cpp/inspireface/c_api/inspireface.h: 498 if _libs[_LIBRARY_FILENAME].has("HFExecuteFaceTrack", "cdecl"): diff --git a/python/inspireface/modules/inspireface.py b/python/inspireface/modules/inspireface.py index c3193619..cd3c835d 100644 --- a/python/inspireface/modules/inspireface.py +++ b/python/inspireface/modules/inspireface.py @@ -395,7 +395,7 @@ def set_track_mode_num_smooth_cache_frame(self, num=15): logger.error(f"Set track mode num smooth cache frame error: {ret}") def set_track_model_detect_interval(self, num=20): - ret = HFSessionSetTrackModelDetectInterval(self._sess, num) + ret = HFSessionSetTrackModeDetectInterval(self._sess, num) if ret != 0: logger.error(f"Set track model detect interval error: {ret}")