mirror of
https://github.com/deepinsight/insightface.git
synced 2025-12-30 08:02:27 +00:00
update to 1.1.7
This commit is contained in:
@@ -10,7 +10,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
|
||||
# Current version
|
||||
set(INSPIRE_FACE_VERSION_MAJOR 1)
|
||||
set(INSPIRE_FACE_VERSION_MINOR 1)
|
||||
set(INSPIRE_FACE_VERSION_PATCH 6)
|
||||
set(INSPIRE_FACE_VERSION_PATCH 7)
|
||||
|
||||
# Converts the version number to a string
|
||||
string(CONCAT INSPIRE_FACE_VERSION_MAJOR_STR ${INSPIRE_FACE_VERSION_MAJOR})
|
||||
|
||||
@@ -13,6 +13,8 @@ Please contact [contact@insightface.ai](mailto:contact@insightface.ai?subject=In
|
||||
|
||||
## Change Logs
|
||||
|
||||
**`2024-09-30`** Fixed some bugs in the feature hub.
|
||||
|
||||
**`2024-08-18`** Updating [Benchmark](doc/Benchmark-Remark(Updating).md): Using CoreML with Apple's Neural Engine (ANE) on the iPhone 13, the combined processes of **Face Detection** + **Alignment** + **Feature Extraction** take less than **2ms**.
|
||||
|
||||
**`2024-07-17`** Add global resource statistics monitoring to prevent memory leaks.
|
||||
|
||||
@@ -242,7 +242,7 @@ HYPER_CAPI_EXPORT extern HResult HFSessionSetTrackPreviewSize(HFSession session,
|
||||
* this number will be filtered.
|
||||
*
|
||||
* @param session Handle to the session.
|
||||
* @param minSize The minimum pixel value, default value is 24.
|
||||
* @param minSize The minimum pixel value, default value is 0.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFSessionSetFilterMinimumFacePixelSize(HFSession session,
|
||||
|
||||
@@ -176,7 +176,7 @@ private:
|
||||
double det_use_time_; ///< Time used for detection.
|
||||
double track_total_use_time_; ///< Total time used for tracking.
|
||||
int track_preview_size_; ///< Size of the tracking preview.
|
||||
int filter_minimum_face_px_size = 24; ///< Minimum face pixel allowed to be retained (take the edge with the smallest Rect).
|
||||
int filter_minimum_face_px_size = 0; ///< Minimum face pixel allowed to be retained (take the edge with the smallest Rect).
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -37,9 +37,11 @@ int main(int argc, char* argv[]) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Enable the functions in the pipeline: mask detection, live detection, and face quality detection
|
||||
// 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
|
||||
// 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;
|
||||
@@ -47,7 +49,8 @@ int main(int argc, char* argv[]) {
|
||||
HInt32 detectPixelLevel = 160;
|
||||
// Handle of the current face SDK algorithm context
|
||||
HFSession session = {0};
|
||||
ret = HFCreateInspireFaceSessionOptional(option, detMode, maxDetectNum, detectPixelLevel, -1, &session);
|
||||
ret = HFCreateInspireFaceSessionOptional(option, detMode, maxDetectNum, detectPixelLevel, -1,
|
||||
&session);
|
||||
if (ret != HSUCCEED) {
|
||||
std::cout << "Create FaceContext error: " << ret << std::endl;
|
||||
return ret;
|
||||
@@ -55,7 +58,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
HFSessionSetTrackPreviewSize(session, detectPixelLevel);
|
||||
HFSessionSetFilterMinimumFacePixelSize(session, 32);
|
||||
|
||||
|
||||
// Load a image
|
||||
cv::Mat image = cv::imread(sourcePath);
|
||||
if (image.empty()) {
|
||||
@@ -64,9 +67,9 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
// Prepare an image parameter structure for configuration
|
||||
HFImageData imageParam = {0};
|
||||
imageParam.data = image.data; // Data buffer
|
||||
imageParam.width = image.cols; // Target view width
|
||||
imageParam.height = image.rows; // Target view width
|
||||
imageParam.data = image.data; // Data buffer
|
||||
imageParam.width = image.cols; // Target view width
|
||||
imageParam.height = image.rows; // Target view width
|
||||
|
||||
// Set rotation based on input parameter
|
||||
switch (rotation) {
|
||||
@@ -113,22 +116,25 @@ int main(int argc, char* argv[]) {
|
||||
std::cout << "Token size: " << multipleFaceData.tokens[index].size << std::endl;
|
||||
std::cout << "Process face index: " << index << std::endl;
|
||||
// Use OpenCV's Rect to receive face bounding boxes
|
||||
auto rect = cv::Rect(multipleFaceData.rects[index].x, multipleFaceData.rects[index].y,
|
||||
multipleFaceData.rects[index].width, multipleFaceData.rects[index].height);
|
||||
auto rect =
|
||||
cv::Rect(multipleFaceData.rects[index].x, multipleFaceData.rects[index].y,
|
||||
multipleFaceData.rects[index].width, multipleFaceData.rects[index].height);
|
||||
cv::rectangle(draw, rect, cv::Scalar(0, 100, 255), 4);
|
||||
|
||||
// Print FaceID, In IMAGE-MODE it is changing, in VIDEO-MODE it is fixed, but it may be lost
|
||||
std::cout << "FaceID: " << multipleFaceData.trackIds[index] << std::endl;
|
||||
|
||||
// Print Head euler angle, It can often be used to judge the quality of a face by the Angle of the head
|
||||
// Print Head euler angle, It can often be used to judge the quality of a face by the Angle
|
||||
// of the head
|
||||
std::cout << "Roll: " << multipleFaceData.angles.roll[index]
|
||||
<< ", Yaw: " << multipleFaceData.angles.roll[index]
|
||||
<< ", Yaw: " << multipleFaceData.angles.yaw[index]
|
||||
<< ", Pitch: " << multipleFaceData.angles.pitch[index] << std::endl;
|
||||
|
||||
HInt32 numOfLmk;
|
||||
HFGetNumOfFaceDenseLandmark(&numOfLmk);
|
||||
HPoint2f denseLandmarkPoints[numOfLmk];
|
||||
ret = HFGetFaceDenseLandmarkFromFaceToken(multipleFaceData.tokens[index], denseLandmarkPoints, numOfLmk);
|
||||
ret = HFGetFaceDenseLandmarkFromFaceToken(multipleFaceData.tokens[index],
|
||||
denseLandmarkPoints, numOfLmk);
|
||||
if (ret != HSUCCEED) {
|
||||
std::cerr << "HFGetFaceDenseLandmarkFromFaceToken error!!" << std::endl;
|
||||
return -1;
|
||||
@@ -137,14 +143,19 @@ int main(int argc, char* argv[]) {
|
||||
cv::Point2f p(denseLandmarkPoints[i].x, denseLandmarkPoints[i].y);
|
||||
cv::circle(draw, p, 0, (0, 0, 255), 2);
|
||||
}
|
||||
auto& rt = multipleFaceData.rects[index];
|
||||
float area = ((float)(rt.height * rt.width)) / (imageParam.width * imageParam.height);
|
||||
std::cout << "area: " << area << std::endl;
|
||||
}
|
||||
cv::imwrite("draw_detected.jpg", draw);
|
||||
|
||||
// Run pipeline function
|
||||
// Select the pipeline function that you want to execute, provided that it is already enabled when FaceContext is created!
|
||||
// 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
|
||||
ret = HFMultipleFacePipelineProcessOptional(session, imageHandle, &multipleFaceData, pipelineOption);
|
||||
ret = HFMultipleFacePipelineProcessOptional(session, imageHandle, &multipleFaceData,
|
||||
pipelineOption);
|
||||
if (ret != HSUCCEED) {
|
||||
std::cout << "Execute Pipeline error: " << ret << std::endl;
|
||||
return ret;
|
||||
@@ -171,14 +182,13 @@ int main(int argc, char* argv[]) {
|
||||
std::cout << "Process face index from pipeline: " << index << std::endl;
|
||||
std::cout << "Mask detect result: " << maskConfidence.confidence[index] << std::endl;
|
||||
std::cout << "Quality predict result: " << qualityConfidence.confidence[index] << std::endl;
|
||||
// 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) {
|
||||
std::cout << "Mask" << std::endl;
|
||||
} else {
|
||||
std::cout << "Non Mask" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ret = HFReleaseImageStream(imageHandle);
|
||||
|
||||
@@ -32,7 +32,7 @@ TEST_CASE("test_FeatureHubBase", "[FeatureHub][BasicFunction]") {
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
delete []dbPathStr;
|
||||
delete[] dbPathStr;
|
||||
}
|
||||
|
||||
SECTION("FeatureHub search top-k") {
|
||||
@@ -115,13 +115,14 @@ TEST_CASE("test_FeatureHubBase", "[FeatureHub][BasicFunction]") {
|
||||
|
||||
REQUIRE(coverIds.size() == results.size);
|
||||
for (int i = 0; i < results.size; ++i) {
|
||||
REQUIRE(std::find(coverIds.begin(), coverIds.end(), results.customIds[i]) != coverIds.end());
|
||||
REQUIRE(std::find(coverIds.begin(), coverIds.end(), results.customIds[i]) !=
|
||||
coverIds.end());
|
||||
}
|
||||
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
delete []dbPathStr;
|
||||
delete[] dbPathStr;
|
||||
}
|
||||
|
||||
SECTION("Repeat the enable and disable tests") {
|
||||
@@ -135,7 +136,6 @@ TEST_CASE("test_FeatureHubBase", "[FeatureHub][BasicFunction]") {
|
||||
configuration.searchMode = HF_SEARCH_MODE_EXHAUSTIVE;
|
||||
configuration.searchThreshold = 0.48f;
|
||||
|
||||
|
||||
ret = HFFeatureHubDataEnable(configuration);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
@@ -148,7 +148,7 @@ TEST_CASE("test_FeatureHubBase", "[FeatureHub][BasicFunction]") {
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HERR_FT_HUB_DISABLE_REPETITION);
|
||||
|
||||
delete []dbPathStr;
|
||||
delete[] dbPathStr;
|
||||
}
|
||||
|
||||
SECTION("Only memory storage is used") {
|
||||
@@ -162,9 +162,7 @@ TEST_CASE("test_FeatureHubBase", "[FeatureHub][BasicFunction]") {
|
||||
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("test_ConcurrencyInsertion", "[FeatureHub][Concurrency]") {
|
||||
@@ -212,7 +210,8 @@ TEST_CASE("test_ConcurrencyInsertion", "[FeatureHub][Concurrency]") {
|
||||
feature.data = feat.data();
|
||||
HFFaceFeatureIdentity featureIdentity = {0};
|
||||
featureIdentity.feature = &feature;
|
||||
featureIdentity.customId = beginGenId + j + i * insertsPerThread; // 确保 customId 唯一
|
||||
featureIdentity.customId =
|
||||
beginGenId + j + i * insertsPerThread; // 确保 customId 唯一
|
||||
featureIdentity.tag = nameBuffer.data();
|
||||
auto ret = HFFeatureHubInsertFeature(featureIdentity);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
@@ -227,15 +226,16 @@ TEST_CASE("test_ConcurrencyInsertion", "[FeatureHub][Concurrency]") {
|
||||
HInt32 count;
|
||||
ret = HFFeatureHubGetFaceCount(&count);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
REQUIRE(count == baseNum + numThreads * insertsPerThread); // Ensure that the previous base data is added to the newly inserted data
|
||||
REQUIRE(count ==
|
||||
baseNum + numThreads * insertsPerThread); // Ensure that the previous base data is
|
||||
// added to the newly inserted data
|
||||
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
delete []dbPathStr;
|
||||
delete[] dbPathStr;
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("test_ConcurrencyRemove", "[FeatureHub][Concurrency]") {
|
||||
DRAW_SPLIT_LINE
|
||||
TEST_PRINT_OUTPUT(true);
|
||||
@@ -311,8 +311,7 @@ TEST_CASE("test_ConcurrencyRemove", "[FeatureHub][Concurrency]") {
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
delete []dbPathStr;
|
||||
|
||||
delete[] dbPathStr;
|
||||
}
|
||||
|
||||
TEST_CASE("test_ConcurrencySearch", "[FeatureHub][Concurrency]") {
|
||||
@@ -375,7 +374,8 @@ TEST_CASE("test_ConcurrencySearch", "[FeatureHub][Concurrency]") {
|
||||
HFFaceFeatureIdentity identity = {0};
|
||||
ret = HFFeatureHubGetFaceIdentity(index, &identity);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
std::vector<HFloat> feature(identity.feature->data, identity.feature->data + identity.feature->size);
|
||||
std::vector<HFloat> feature(identity.feature->data,
|
||||
identity.feature->data + identity.feature->size);
|
||||
auto simFeat = SimulateSimilarVector(feature);
|
||||
HFFaceFeature simFeature = {0};
|
||||
simFeature.data = simFeat.data();
|
||||
@@ -388,7 +388,6 @@ TEST_CASE("test_ConcurrencySearch", "[FeatureHub][Concurrency]") {
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
REQUIRE(cosine > 0.80f);
|
||||
similarFeatures.push_back(feature);
|
||||
|
||||
}
|
||||
REQUIRE(similarFeatures.size() == numberOfSimilar);
|
||||
|
||||
@@ -419,7 +418,7 @@ TEST_CASE("test_ConcurrencySearch", "[FeatureHub][Concurrency]") {
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> dis(0, preDataSample - 1);
|
||||
for (int j = 0; j < 50; ++j) { // Each thread performs 50 similar searches
|
||||
for (int j = 0; j < 50; ++j) { // Each thread performs 50 similar searches
|
||||
int idx = dis(gen);
|
||||
auto targetId = targetIds[idx];
|
||||
HFFaceFeature feature = {0};
|
||||
@@ -449,11 +448,9 @@ TEST_CASE("test_ConcurrencySearch", "[FeatureHub][Concurrency]") {
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
|
||||
delete []dbPathStr;
|
||||
delete[] dbPathStr;
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("test_FeatureCache", "[FeatureHub][Concurrency]") {
|
||||
DRAW_SPLIT_LINE
|
||||
TEST_PRINT_OUTPUT(true);
|
||||
@@ -492,7 +489,6 @@ TEST_CASE("test_FeatureCache", "[FeatureHub][Concurrency]") {
|
||||
simFeature.data = simVec.data();
|
||||
simFeature.size = simVec.size();
|
||||
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
HFFaceFeatureIdentity capture = {0};
|
||||
ret = HFFeatureHubGetFaceIdentity(12, &capture);
|
||||
@@ -506,12 +502,116 @@ TEST_CASE("test_FeatureCache", "[FeatureHub][Concurrency]") {
|
||||
ret = HFFaceComparison(target, simFeature, &cosine);
|
||||
REQUIRE(cosine > 0.8f);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
}
|
||||
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
delete []dbPathStr;
|
||||
delete[] dbPathStr;
|
||||
}
|
||||
|
||||
}
|
||||
TEST_CASE("test_DataPersistence", "[feature_manage]") {
|
||||
DRAW_SPLIT_LINE
|
||||
TEST_PRINT_OUTPUT(true);
|
||||
|
||||
// Generate 10 random feature
|
||||
std::vector<std::vector<HFloat>> features;
|
||||
std::vector<std::string> identities;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
auto feat = GenerateRandomFeature(512);
|
||||
features.push_back(feat);
|
||||
identities.push_back("id_" + std::to_string(i));
|
||||
}
|
||||
|
||||
SECTION("Insert") {
|
||||
HResult ret;
|
||||
HFFeatureHubConfiguration configuration = {0};
|
||||
auto dbPath = GET_SAVE_DATA(".test");
|
||||
HString dbPathStr = new char[dbPath.size() + 1];
|
||||
std::strcpy(dbPathStr, dbPath.c_str());
|
||||
configuration.enablePersistence = 1;
|
||||
configuration.dbPath = dbPathStr;
|
||||
configuration.featureBlockNum = 20;
|
||||
configuration.searchMode = HF_SEARCH_MODE_EXHAUSTIVE;
|
||||
configuration.searchThreshold = 0.48f;
|
||||
|
||||
if (std::remove(configuration.dbPath) != 0) {
|
||||
spdlog::trace("Maybe the file does not exist");
|
||||
}
|
||||
|
||||
ret = HFFeatureHubDataEnable(configuration);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
for (size_t i = 0; i < features.size(); i++) {
|
||||
HFFaceFeature feature = {0};
|
||||
feature.data = features[i].data();
|
||||
feature.size = features[i].size();
|
||||
HFFaceFeatureIdentity identity = {0};
|
||||
identity.feature = &feature;
|
||||
identity.tag = const_cast<char *>(identities[i].c_str());
|
||||
identity.customId = i;
|
||||
|
||||
ret = HFFeatureHubInsertFeature(identity);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
// Get the feature from the database
|
||||
HFFaceFeatureIdentity capture = {0};
|
||||
ret = HFFeatureHubGetFaceIdentity(i, &capture);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
// Check the feature
|
||||
HFFaceFeature target = {0};
|
||||
target.data = capture.feature->data;
|
||||
target.size = capture.feature->size;
|
||||
HFloat cosine;
|
||||
ret = HFFaceComparison(target, feature, &cosine);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
REQUIRE(cosine > 0.99f);
|
||||
}
|
||||
// Check number of faces
|
||||
HInt32 count;
|
||||
ret = HFFeatureHubGetFaceCount(&count);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
REQUIRE(count == features.size());
|
||||
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
delete[] dbPathStr;
|
||||
}
|
||||
|
||||
SECTION("Check") {
|
||||
HResult ret;
|
||||
HFFeatureHubConfiguration configuration = {0};
|
||||
auto dbPath = GET_SAVE_DATA(".test");
|
||||
HString dbPathStr = new char[dbPath.size() + 1];
|
||||
std::strcpy(dbPathStr, dbPath.c_str());
|
||||
configuration.enablePersistence = 1;
|
||||
configuration.dbPath = dbPathStr;
|
||||
configuration.featureBlockNum = 20;
|
||||
|
||||
ret = HFFeatureHubDataEnable(configuration);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
// Check number of faces
|
||||
HInt32 count;
|
||||
ret = HFFeatureHubGetFaceCount(&count);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
REQUIRE(count == features.size());
|
||||
|
||||
// Check every face vector
|
||||
for (size_t i = 0; i < features.size(); i++) {
|
||||
HFFaceFeatureIdentity identity = {0};
|
||||
ret = HFFeatureHubGetFaceIdentity(i, &identity);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
REQUIRE(identity.customId == i);
|
||||
REQUIRE(std::string(identity.tag) == identities[i]);
|
||||
REQUIRE(identity.feature->size == features[i].size());
|
||||
}
|
||||
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
delete[] dbPathStr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,18 +102,16 @@ TEST_CASE("test_FeatureManage", "[feature_manage]") {
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
CHECK(num == 0);
|
||||
|
||||
|
||||
// Finish
|
||||
ret = HFReleaseInspireFaceSession(session);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
|
||||
ret = HFReleaseImageStream(imgHandle);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
delete[]dbPathStr;
|
||||
delete[] dbPathStr;
|
||||
}
|
||||
|
||||
SECTION("Import a large faces data") {
|
||||
@@ -151,12 +149,11 @@ TEST_CASE("test_FeatureManage", "[feature_manage]") {
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
CHECK(count == numOfNeedImport);
|
||||
|
||||
|
||||
// Finish
|
||||
ret = HFReleaseInspireFaceSession(session);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
delete[]dbPathStr;
|
||||
delete[] dbPathStr;
|
||||
|
||||
#else
|
||||
TEST_PRINT("The test case that uses LFW is not enabled, so it will be skipped.");
|
||||
@@ -165,7 +162,8 @@ TEST_CASE("test_FeatureManage", "[feature_manage]") {
|
||||
|
||||
SECTION("Faces feature CURD") {
|
||||
#ifdef ISF_ENABLE_USE_LFW_DATA
|
||||
// This section needs to be connected to the "Import a large faces data" section before it can be executed
|
||||
// This section needs to be connected to the "Import a large faces data" section before it
|
||||
// can be executed
|
||||
HResult ret;
|
||||
HFSessionCustomParameter parameter = {0};
|
||||
parameter.enable_recognition = 1;
|
||||
@@ -213,7 +211,7 @@ TEST_CASE("test_FeatureManage", "[feature_manage]") {
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
// Search again
|
||||
ret = HFFeatureHubFaceSearch(feature, &confidence, &searchedIdentity);
|
||||
// spdlog::info("{}", confidence);
|
||||
// spdlog::info("{}", confidence);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
CHECK(searchedIdentity.customId == -1);
|
||||
|
||||
@@ -225,7 +223,6 @@ TEST_CASE("test_FeatureManage", "[feature_manage]") {
|
||||
ret = HFFeatureHubInsertFeature(againIdentity);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
|
||||
// Search again
|
||||
HFFaceFeatureIdentity searchedAgainIdentity = {0};
|
||||
ret = HFFeatureHubFaceSearch(feature, &confidence, &searchedAgainIdentity);
|
||||
@@ -267,7 +264,7 @@ TEST_CASE("test_FeatureManage", "[feature_manage]") {
|
||||
ret = HFFeatureHubFaceUpdate(updateIdentity);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
//
|
||||
//
|
||||
// Prepare a zy query image
|
||||
cv::Mat zyImageQuery = cv::imread(GET_DATA("data/bulk/woman_search.jpeg"));
|
||||
HFImageData imageDataZyQuery = {0};
|
||||
@@ -279,16 +276,17 @@ TEST_CASE("test_FeatureManage", "[feature_manage]") {
|
||||
HFImageStream imgHandleZyQuery;
|
||||
ret = HFCreateImageStream(&imageDataZyQuery, &imgHandleZyQuery);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
//
|
||||
//
|
||||
// Extract basic face information from photos
|
||||
HFMultipleFaceData multipleFaceDataZyQuery = {0};
|
||||
ret = HFExecuteFaceTrack(session, imgHandleZyQuery, &multipleFaceDataZyQuery);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
REQUIRE(multipleFaceDataZyQuery.detectedNum > 0);
|
||||
//
|
||||
//
|
||||
// Extract face feature
|
||||
HFFaceFeature featureZyQuery = {0};
|
||||
ret = HFFaceFeatureExtract(session, imgHandleZyQuery, multipleFaceDataZyQuery.tokens[0], &featureZyQuery);
|
||||
ret = HFFaceFeatureExtract(session, imgHandleZyQuery, multipleFaceDataZyQuery.tokens[0],
|
||||
&featureZyQuery);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
ret = HFReleaseImageStream(imgHandleZyQuery);
|
||||
@@ -311,7 +309,6 @@ TEST_CASE("test_FeatureManage", "[feature_manage]") {
|
||||
TEST_PRINT("The test case that uses LFW is not enabled, so it will be skipped.");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("test_SearchTopK", "[feature_search_top_k]") {
|
||||
@@ -356,16 +353,22 @@ TEST_CASE("test_SearchTopK", "[feature_search_top_k]") {
|
||||
|
||||
// Prepare multiple photos of a person
|
||||
std::vector<std::string> photos = {
|
||||
GET_DATA("data/RD/d1.jpeg"),
|
||||
GET_DATA("data/RD/d2.jpeg"),
|
||||
GET_DATA("data/RD/d3.jpeg"),
|
||||
GET_DATA("data/RD/d4.jpeg"),
|
||||
GET_DATA("data/RD/d1.jpeg"),
|
||||
GET_DATA("data/RD/d2.jpeg"),
|
||||
GET_DATA("data/RD/d3.jpeg"),
|
||||
GET_DATA("data/RD/d4.jpeg"),
|
||||
};
|
||||
std::vector<std::string> tags = {
|
||||
"d1", "d2", "d3", "d4",
|
||||
"d1",
|
||||
"d2",
|
||||
"d3",
|
||||
"d4",
|
||||
};
|
||||
std::vector<HInt32> updateIds = {
|
||||
5, 163, 670, 971,
|
||||
5,
|
||||
163,
|
||||
670,
|
||||
971,
|
||||
};
|
||||
REQUIRE(photos.size() == tags.size());
|
||||
REQUIRE(updateIds.size() == tags.size());
|
||||
@@ -395,8 +398,8 @@ TEST_CASE("test_SearchTopK", "[feature_search_top_k]") {
|
||||
ret = HFFaceFeatureExtract(session, imgHandle, multipleFaceData.tokens[0], &feature);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
char* cstr = new char[tags[i].size() + 1]; // Dynamically allocate memory for the name
|
||||
strcpy(cstr, tags[i].c_str()); // Copy the name into the allocated memory
|
||||
char* cstr = new char[tags[i].size() + 1]; // Dynamically allocate memory for the name
|
||||
strcpy(cstr, tags[i].c_str()); // Copy the name into the allocated memory
|
||||
|
||||
// Create identity
|
||||
HFFaceFeatureIdentity identity = {0};
|
||||
@@ -410,7 +413,7 @@ TEST_CASE("test_SearchTopK", "[feature_search_top_k]") {
|
||||
|
||||
ret = HFReleaseImageStream(imgHandle);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
delete[] cstr; // Clean up the dynamically allocated memory
|
||||
delete[] cstr; // Clean up the dynamically allocated memory
|
||||
}
|
||||
|
||||
// Prepare a target photo for a face top-k search
|
||||
@@ -443,7 +446,8 @@ TEST_CASE("test_SearchTopK", "[feature_search_top_k]") {
|
||||
CHECK(topk.size == photos.size());
|
||||
for (int i = 0; i < topk.size; ++i) {
|
||||
TEST_PRINT("Top-{} -> id: {}, {}", i + 1, topk.customIds[i], topk.confidence[i]);
|
||||
CHECK(std::find(updateIds.begin(), updateIds.end(), topk.customIds[i]) != updateIds.end());
|
||||
CHECK(std::find(updateIds.begin(), updateIds.end(), topk.customIds[i]) !=
|
||||
updateIds.end());
|
||||
}
|
||||
|
||||
ret = HFReleaseImageStream(imgHandle);
|
||||
@@ -455,13 +459,12 @@ TEST_CASE("test_SearchTopK", "[feature_search_top_k]") {
|
||||
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
delete[]dbPathStr;
|
||||
delete[] dbPathStr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("test_FeatureBenchmark", "[feature_benchmark]") {
|
||||
|
||||
// Test the search time at 1k, 5k and 10k of the face library (the target face is at the back).
|
||||
SECTION("Search face benchmark from 1k") {
|
||||
#if defined(ISF_ENABLE_BENCHMARK) && defined(ISF_ENABLE_USE_LFW_DATA)
|
||||
@@ -492,7 +495,7 @@ TEST_CASE("test_FeatureBenchmark", "[feature_benchmark]") {
|
||||
|
||||
auto lfwDir = getLFWFunneledDir();
|
||||
auto dataList = LoadLFWFunneledValidData(lfwDir, getTestLFWFunneledTxt());
|
||||
// TEST_PRINT("{}", dataList.size());
|
||||
// TEST_PRINT("{}", dataList.size());
|
||||
auto importStatus = ImportLFWFunneledValidData(session, dataList, numOfNeedImport);
|
||||
REQUIRE(importStatus);
|
||||
HInt32 count;
|
||||
@@ -526,17 +529,20 @@ TEST_CASE("test_FeatureBenchmark", "[feature_benchmark]") {
|
||||
// Search for a face
|
||||
HFloat confidence;
|
||||
HFFaceFeatureIdentity searchedIdentity = {0};
|
||||
auto start = (double) cv::getTickCount();
|
||||
auto start = (double)cv::getTickCount();
|
||||
for (int i = 0; i < loop; ++i) {
|
||||
ret = HFFeatureHubFaceSearch(feature, &confidence, &searchedIdentity);
|
||||
}
|
||||
auto cost = ((double) cv::getTickCount() - start) / cv::getTickFrequency() * 1000;
|
||||
auto cost = ((double)cv::getTickCount() - start) / cv::getTickFrequency() * 1000;
|
||||
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
REQUIRE(searchedIdentity.customId == 999);
|
||||
REQUIRE(std::string(searchedIdentity.tag) == "Teresa_Williams");
|
||||
|
||||
TEST_PRINT("<Benchmark> Search Face from 1k -> Loop: {}, Total Time: {:.5f}ms, Average Time: {:.5f}ms", loop, cost, cost / loop);
|
||||
TEST_PRINT(
|
||||
"<Benchmark> Search Face from 1k -> Loop: {}, Total Time: {:.5f}ms, Average Time: "
|
||||
"{:.5f}ms",
|
||||
loop, cost, cost / loop);
|
||||
|
||||
BenchmarkRecord record(getBenchmarkRecordFile());
|
||||
record.insertBenchmarkData("Search Face from 1k", loop, cost, cost / loop);
|
||||
@@ -544,15 +550,15 @@ TEST_CASE("test_FeatureBenchmark", "[feature_benchmark]") {
|
||||
ret = HFReleaseInspireFaceSession(session);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
|
||||
ret = HFReleaseImageStream(imgHandle);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
delete []dbPathStr;
|
||||
delete[] dbPathStr;
|
||||
#else
|
||||
TEST_PRINT("Skip face search benchmark test, you need to enable both lfw and benchmark test.");
|
||||
TEST_PRINT(
|
||||
"Skip face search benchmark test, you need to enable both lfw and benchmark test.");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -620,17 +626,20 @@ TEST_CASE("test_FeatureBenchmark", "[feature_benchmark]") {
|
||||
// Search for a face
|
||||
HFloat confidence;
|
||||
HFFaceFeatureIdentity searchedIdentity = {0};
|
||||
auto start = (double) cv::getTickCount();
|
||||
auto start = (double)cv::getTickCount();
|
||||
for (int i = 0; i < loop; ++i) {
|
||||
ret = HFFeatureHubFaceSearch(feature, &confidence, &searchedIdentity);
|
||||
}
|
||||
auto cost = ((double) cv::getTickCount() - start) / cv::getTickFrequency() * 1000;
|
||||
auto cost = ((double)cv::getTickCount() - start) / cv::getTickFrequency() * 1000;
|
||||
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
REQUIRE(searchedIdentity.customId == 4998);
|
||||
REQUIRE(std::string(searchedIdentity.tag) == "Mary_Katherine_Smart");
|
||||
|
||||
TEST_PRINT("<Benchmark> Search Face from 5k -> Loop: {}, Total Time: {:.5f}ms, Average Time: {:.5f}ms", loop, cost, cost / loop);
|
||||
TEST_PRINT(
|
||||
"<Benchmark> Search Face from 5k -> Loop: {}, Total Time: {:.5f}ms, Average Time: "
|
||||
"{:.5f}ms",
|
||||
loop, cost, cost / loop);
|
||||
|
||||
BenchmarkRecord record(getBenchmarkRecordFile());
|
||||
record.insertBenchmarkData("Search Face from 5k", loop, cost, cost / loop);
|
||||
@@ -643,9 +652,10 @@ TEST_CASE("test_FeatureBenchmark", "[feature_benchmark]") {
|
||||
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
delete []dbPathStr;
|
||||
delete[] dbPathStr;
|
||||
#else
|
||||
TEST_PRINT("Skip face search benchmark test, you need to enable both lfw and benchmark test.");
|
||||
TEST_PRINT(
|
||||
"Skip face search benchmark test, you need to enable both lfw and benchmark test.");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -680,7 +690,7 @@ TEST_CASE("test_FeatureBenchmark", "[feature_benchmark]") {
|
||||
|
||||
auto lfwDir = getLFWFunneledDir();
|
||||
auto dataList = LoadLFWFunneledValidData(lfwDir, getTestLFWFunneledTxt());
|
||||
// TEST_PRINT("{}", dataList.size());
|
||||
// TEST_PRINT("{}", dataList.size());
|
||||
auto importStatus = ImportLFWFunneledValidData(session, dataList, numOfNeedImport);
|
||||
REQUIRE(importStatus);
|
||||
HInt32 count;
|
||||
@@ -748,17 +758,20 @@ TEST_CASE("test_FeatureBenchmark", "[feature_benchmark]") {
|
||||
// Search for a face
|
||||
HFloat confidence;
|
||||
HFFaceFeatureIdentity searchedIdentity = {0};
|
||||
auto start = (double) cv::getTickCount();
|
||||
auto start = (double)cv::getTickCount();
|
||||
for (int i = 0; i < loop; ++i) {
|
||||
ret = HFFeatureHubFaceSearch(feature, &confidence, &searchedIdentity);
|
||||
}
|
||||
auto cost = ((double) cv::getTickCount() - start) / cv::getTickFrequency() * 1000;
|
||||
auto cost = ((double)cv::getTickCount() - start) / cv::getTickFrequency() * 1000;
|
||||
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
REQUIRE(searchedIdentity.customId == updateId);
|
||||
REQUIRE(std::string(searchedIdentity.tag) == "ZY");
|
||||
|
||||
TEST_PRINT("<Benchmark> Search Face from 10k -> Loop: {}, Total Time: {:.5f}ms, Average Time: {:.5f}ms", loop, cost, cost / loop);
|
||||
TEST_PRINT(
|
||||
"<Benchmark> Search Face from 10k -> Loop: {}, Total Time: {:.5f}ms, Average Time: "
|
||||
"{:.5f}ms",
|
||||
loop, cost, cost / loop);
|
||||
|
||||
BenchmarkRecord record(getBenchmarkRecordFile());
|
||||
record.insertBenchmarkData("Search Face from 10k", loop, cost, cost / loop);
|
||||
@@ -767,15 +780,15 @@ TEST_CASE("test_FeatureBenchmark", "[feature_benchmark]") {
|
||||
ret = HFReleaseInspireFaceSession(session);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
|
||||
ret = HFReleaseImageStream(imgHandle);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
delete []dbPathStr;
|
||||
delete[] dbPathStr;
|
||||
#else
|
||||
TEST_PRINT("Skip face search benchmark test, you need to enable both lfw and benchmark test.");
|
||||
TEST_PRINT(
|
||||
"Skip face search benchmark test, you need to enable both lfw and benchmark test.");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -789,7 +802,7 @@ TEST_CASE("test_FeatureBenchmark", "[feature_benchmark]") {
|
||||
parameter.enable_recognition = 1;
|
||||
HFDetectMode detMode = HF_DETECT_MODE_ALWAYS_DETECT;
|
||||
HFSession session;
|
||||
ret = HFCreateInspireFaceSession(parameter, detMode, 3, -1, -1, &session);
|
||||
ret = HFCreateInspireFaceSession(parameter, detMode, 3, -1, -1, &session);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
HFFeatureHubConfiguration configuration = {0};
|
||||
auto dbPath = GET_SAVE_DATA(".test");
|
||||
@@ -829,7 +842,8 @@ TEST_CASE("test_FeatureBenchmark", "[feature_benchmark]") {
|
||||
|
||||
// Extract face feature
|
||||
HFloat featureCacheZy[featureNum];
|
||||
ret = HFFaceFeatureExtractCpy(session, imgHandleZy, multipleFaceDataZy.tokens[0], featureCacheZy);
|
||||
ret = HFFaceFeatureExtractCpy(session, imgHandleZy, multipleFaceDataZy.tokens[0],
|
||||
featureCacheZy);
|
||||
HFFaceFeature featureZy = {0};
|
||||
featureZy.size = featureNum;
|
||||
featureZy.data = featureCacheZy;
|
||||
@@ -845,29 +859,32 @@ TEST_CASE("test_FeatureBenchmark", "[feature_benchmark]") {
|
||||
HFImageStream imgHandleZyQuery;
|
||||
ret = HFCreateImageStream(&imageDataZyQuery, &imgHandleZyQuery);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
//
|
||||
//
|
||||
// Extract basic face information from photos
|
||||
HFMultipleFaceData multipleFaceDataZyQuery = {0};
|
||||
ret = HFExecuteFaceTrack(session, imgHandleZyQuery, &multipleFaceDataZyQuery);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
REQUIRE(multipleFaceDataZyQuery.detectedNum > 0);
|
||||
//
|
||||
//
|
||||
// Extract face feature
|
||||
HFloat featureCacheZyQuery[featureNum];
|
||||
ret = HFFaceFeatureExtractCpy(session, imgHandleZyQuery, multipleFaceDataZyQuery.tokens[0], featureCacheZyQuery);
|
||||
ret = HFFaceFeatureExtractCpy(session, imgHandleZyQuery, multipleFaceDataZyQuery.tokens[0],
|
||||
featureCacheZyQuery);
|
||||
HFFaceFeature featureZyQuery = {0};
|
||||
featureZyQuery.data = featureCacheZyQuery;
|
||||
featureZyQuery.size = featureNum;
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
|
||||
auto start = (double) cv::getTickCount();
|
||||
auto start = (double)cv::getTickCount();
|
||||
for (int i = 0; i < loop; ++i) {
|
||||
HFloat compRes;
|
||||
ret = HFFaceComparison(featureZy, featureZyQuery, &compRes);
|
||||
}
|
||||
auto cost = ((double) cv::getTickCount() - start) / cv::getTickFrequency() * 1000;
|
||||
auto cost = ((double)cv::getTickCount() - start) / cv::getTickFrequency() * 1000;
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
TEST_PRINT("<Benchmark> Face Comparison -> Loop: {}, Total Time: {:.5f}ms, Average Time: {:.5f}ms", loop, cost, cost / loop);
|
||||
TEST_PRINT(
|
||||
"<Benchmark> Face Comparison -> Loop: {}, Total Time: {:.5f}ms, Average Time: {:.5f}ms",
|
||||
loop, cost, cost / loop);
|
||||
|
||||
BenchmarkRecord record(getBenchmarkRecordFile());
|
||||
record.insertBenchmarkData("Face Comparison", loop, cost, cost / loop);
|
||||
@@ -880,7 +897,7 @@ TEST_CASE("test_FeatureBenchmark", "[feature_benchmark]") {
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
delete []dbPathStr;
|
||||
delete[] dbPathStr;
|
||||
#else
|
||||
TEST_PRINT("The benchmark is not enabled, so all relevant test cases are skipped.");
|
||||
#endif
|
||||
@@ -896,7 +913,7 @@ TEST_CASE("test_FeatureBenchmark", "[feature_benchmark]") {
|
||||
parameter.enable_recognition = 1;
|
||||
HFDetectMode detMode = HF_DETECT_MODE_ALWAYS_DETECT;
|
||||
HFSession session;
|
||||
ret = HFCreateInspireFaceSession(parameter, detMode, 3,-1, -1, &session);
|
||||
ret = HFCreateInspireFaceSession(parameter, detMode, 3, -1, -1, &session);
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
HFFeatureHubConfiguration configuration = {0};
|
||||
auto dbPath = GET_SAVE_DATA(".test");
|
||||
@@ -934,13 +951,15 @@ TEST_CASE("test_FeatureBenchmark", "[feature_benchmark]") {
|
||||
|
||||
// Extract face feature
|
||||
HFFaceFeature feature = {0};
|
||||
auto start = (double) cv::getTickCount();
|
||||
auto start = (double)cv::getTickCount();
|
||||
for (int i = 0; i < loop; ++i) {
|
||||
ret = HFFaceFeatureExtract(session, imgHandle, multipleFaceData.tokens[0], &feature);
|
||||
}
|
||||
auto cost = ((double) cv::getTickCount() - start) / cv::getTickFrequency() * 1000;
|
||||
auto cost = ((double)cv::getTickCount() - start) / cv::getTickFrequency() * 1000;
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
TEST_PRINT("<Benchmark> Face Extract -> Loop: {}, Total Time: {:.5f}ms, Average Time: {:.5f}ms", loop, cost, cost / loop);
|
||||
TEST_PRINT(
|
||||
"<Benchmark> Face Extract -> Loop: {}, Total Time: {:.5f}ms, Average Time: {:.5f}ms",
|
||||
loop, cost, cost / loop);
|
||||
|
||||
BenchmarkRecord record(getBenchmarkRecordFile());
|
||||
record.insertBenchmarkData("Face Extract", loop, cost, cost / loop);
|
||||
@@ -951,9 +970,11 @@ TEST_CASE("test_FeatureBenchmark", "[feature_benchmark]") {
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
ret = HFFeatureHubDataDisable();
|
||||
REQUIRE(ret == HSUCCEED);
|
||||
delete []dbPathStr;
|
||||
delete[] dbPathStr;
|
||||
#else
|
||||
TEST_PRINT("Skip the face feature extraction benchmark test. To run it, you need to turn on the benchmark test.");
|
||||
TEST_PRINT(
|
||||
"Skip the face feature extraction benchmark test. To run it, you need to turn on the "
|
||||
"benchmark test.");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user