Add the inspireface project to cpp-package.

This commit is contained in:
JingyuYan
2024-05-02 01:27:29 +08:00
parent e90dacb3cf
commit 08d7e96f79
431 changed files with 370534 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
//
// Created by Tunm-Air13 on 2024/2/2.
//
#include "settings/test_settings.h"
#include "inspireface/face_context.h"
#include "common/face_data/data_tools.h"
#include "../test_helper/test_tools.h"
#include "herror.h"
using namespace inspire;
TEST_CASE("test_CameraStream", "[camera_stream") {
DRAW_SPLIT_LINE
TEST_PRINT_OUTPUT(true);
SECTION("DecodingRotatedImages") {
FaceContext ctx;
CustomPipelineParameter param;
auto ret = ctx.Configuration(DetectMode::DETECT_MODE_IMAGE, 1, param);
REQUIRE(ret == HSUCCEED);
std::vector<std::string> rotated_filename_list = {
getTestData("images/rotate/rot_0.jpg"),
getTestData("images/rotate/rot_90.jpg"),
getTestData("images/rotate/rot_180.jpg"),
getTestData("images/rotate/rot_270.jpg"),
};
std::vector<ROTATION_MODE> rotate_list = {ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270};
CHECK(rotate_list.size() == rotated_filename_list.size());
for (int i = 0; i < rotate_list.size(); ++i) {
cv::Mat image = cv::imread(rotated_filename_list[i]);
REQUIRE(!image.empty());
auto rotated = rotate_list[i];
CameraStream stream;
stream.SetDataBuffer(image.data, image.rows, image.cols);
stream.SetDataFormat(BGR);
stream.SetRotationMode(rotated);
ret = ctx.FaceDetectAndTrack(stream);
REQUIRE(ret == HSUCCEED);
const auto &faces = ctx.GetTrackingFaceList();
CHECK(faces.size() == 1);
}
}
SECTION("DecodingNV21Image") {
FaceContext ctx;
CustomPipelineParameter param;
auto ret = ctx.Configuration(DetectMode::DETECT_MODE_IMAGE, 1, param);
REQUIRE(ret == HSUCCEED);
int32_t width = 402;
int32_t height = 324;
auto rotated = ROTATION_90;
auto format = NV21;
auto nv21 = ReadNV21Data(getTestData("images/rotate/rot_90_324x402.nv21").c_str(), width, height);
REQUIRE(nv21 != nullptr);
CameraStream stream;
stream.SetDataBuffer(nv21, height, width);
stream.SetDataFormat(format);
stream.SetRotationMode(rotated);
ret = ctx.FaceDetectAndTrack(stream);
REQUIRE(ret == HSUCCEED);
const auto &faces = ctx.GetTrackingFaceList();
CHECK(faces.size() == 1);
}
}

View File

@@ -0,0 +1,50 @@
//
// Created by tunm on 2023/9/16.
//
#include "settings/test_settings.h"
#include "inspireface/face_context.h"
#include "herror.h"
using namespace inspire;
TEST_CASE("test_FaceDetectTrack", "[face_track]") {
DRAW_SPLIT_LINE
TEST_PRINT_OUTPUT(true);
SECTION("TrackBenchmark") {
// Initialize
FaceContext ctx;
CustomPipelineParameter param;
param.enable_face_quality = true;
auto ret = ctx.Configuration(DetectMode::DETECT_MODE_VIDEO, 1, param);
REQUIRE(ret == HSUCCEED);
// Prepare a picture of a face
auto image = cv::imread(GET_DATA("images/face_sample.png"));
CameraStream stream;
stream.SetDataFormat(BGR);
stream.SetRotationMode(ROTATION_0);
stream.SetDataBuffer(image.data, image.rows, image.cols);
const auto loop = 1000;
double total = 0.0f;
spdlog::info("begin {} times tracking: ", loop);
auto out = (double) cv::getTickCount();
for (int i = 0; i < loop; ++i) {
auto timeStart = (double) cv::getTickCount();
// Face detection
ctx.FaceDetectAndTrack(stream);
auto &faces = ctx.GetTrackingFaceList();
double cost = ((double) cv::getTickCount() - timeStart) / cv::getTickFrequency() * 1000;
REQUIRE(ret == HSUCCEED);
REQUIRE(faces.size() > 0);
total += cost;
}
auto end = ((double) cv::getTickCount() - out) / cv::getTickFrequency() * 1000;
spdlog::info("[Face Tracking]{} times, Total cost: {}ms, Average cost: {}ms", loop, end, total / loop);
}
}

View File

@@ -0,0 +1,55 @@
//
// Created by tunm on 2023/9/17.
//
#include "settings/test_settings.h"
#include "inspireface/common/face_data/data_tools.h"
#include "herror.h"
#include "inspireface/face_context.h"
using namespace inspire;
TEST_CASE("test_FaceData", "[face_data]") {
DRAW_SPLIT_LINE
TEST_PRINT_OUTPUT(true);
SECTION("DataConversion") {
// Initialize
FaceContext ctx;
CustomPipelineParameter param;
param.enable_face_quality = true;
auto ret = ctx.Configuration(DetectMode::DETECT_MODE_VIDEO, 1, param);
REQUIRE(ret == HSUCCEED);
// Prepare a picture of a face
auto image = cv::imread(GET_DATA("images/face_sample.png"));
CameraStream stream;
stream.SetDataFormat(BGR);
stream.SetRotationMode(ROTATION_0);
stream.SetDataBuffer(image.data, image.rows, image.cols);
ctx.FaceDetectAndTrack(stream);
auto &faces = ctx.GetTrackingFaceList();
REQUIRE(ret == HSUCCEED);
REQUIRE(faces.size() > 0);
HyperFaceData faceData = FaceObjectToHyperFaceData(faces[0], 0);
std::cout << faces[0].getTransMatrix() << std::endl;
PrintHyperFaceData(faceData);
ByteArray byteArray;
INSPIRE_LOGD("sizeof: %lu", sizeof(byteArray));
ret = SerializeHyperFaceData(faceData, byteArray);
CHECK(ret == HSUCCEED);
INSPIRE_LOGD("sizeof: %lu", sizeof(byteArray));
HyperFaceData decode;
ret = DeserializeHyperFaceData(byteArray, decode);
CHECK(ret == HSUCCEED);
PrintHyperFaceData(decode);
}
}

View File

@@ -0,0 +1,185 @@
//
// Created by Tunm-Air13 on 2023/9/12.
//
#include "settings/test_settings.h"
#include "inspireface/face_context.h"
#include "herror.h"
#include "../test_helper/test_help.h"
#include "feature_hub/feature_hub.h"
using namespace inspire;
TEST_CASE("test_FaceFeatureManagement", "[face_feature]") {
DRAW_SPLIT_LINE
TEST_PRINT_OUTPUT(true);
SECTION("FeatureCURD") {
DRAW_SPLIT_LINE
// Initialize
FaceContext ctx;
CustomPipelineParameter param;
param.enable_recognition = true;
auto ret = ctx.Configuration(DetectMode::DETECT_MODE_IMAGE, 1, param);
REQUIRE(ret == HSUCCEED);
FEATURE_HUB->PrintFeatureMatrixInfo();
// Know the location of 'kunkun' in advance
int32_t KunkunIndex = 795;
// Prepare a face photo in advance and extract the features
auto image = cv::imread(GET_DATA("images/kun.jpg"));
CameraStream stream;
stream.SetDataFormat(BGR);
stream.SetRotationMode(ROTATION_0);
stream.SetDataBuffer(image.data, image.rows, image.cols);
ret = ctx.FaceDetectAndTrack(stream);
REQUIRE(ret == HSUCCEED);
// Face detection
ctx.FaceDetectAndTrack(stream);
const auto &faces = ctx.GetTrackingFaceList();
REQUIRE(faces.size() > 0);
// Feature extraction of "Kunkun" was carried out
Embedded feature;
ret = ctx.FaceRecognitionModule()->FaceExtract(stream, faces[0], feature);
CHECK(ret == HSUCCEED);
// Import face feature vectors in batches
String mat_path = GET_DATA("test_faceset/test_faces_A1.npy");
String tags_path = GET_DATA("test_faceset/test_faces_A1.txt");
auto result = LoadMatrixAndTags(mat_path, tags_path);
// Gets the feature matrix and label names
EmbeddedList featureMatrix = result.first;
std::vector<std::string> tagNames = result.second;
REQUIRE(featureMatrix.size() == 3000);
REQUIRE(tagNames.size() == 3000);
REQUIRE(featureMatrix[0].size() == 512);
for (int i = 0; i < featureMatrix.size(); ++i) {
auto &feat = featureMatrix[i];
auto ret = FEATURE_HUB->RegisterFaceFeature(feat, i, tagNames[i], i);
CHECK(ret == HSUCCEED);
}
std::cout << std::endl;
REQUIRE(FEATURE_HUB->GetFaceFeatureCount() == 3000);
spdlog::trace("All 3000 Faces embedded vector are loaded");
// Prepare a face photo to search through the library
SearchResult searchResult;
ret = FEATURE_HUB->SearchFaceFeature(feature, searchResult, 0.5f);
REQUIRE(ret == HSUCCEED);
CHECK(searchResult.index != -1);
CHECK(searchResult.index == KunkunIndex);
CHECK(searchResult.tag == "Kunkun");
CHECK(searchResult.score == Approx(0.76096).epsilon(1e-3));
spdlog::info("Find Kunkun -> Location ID: {}, Confidence: {}, Tag: {}", searchResult.index, searchResult.score, searchResult.tag.c_str());
// Save "Kunkun"'s library features and so on
Embedded KunkunFeature;
ret = FEATURE_HUB->GetFaceFeature(KunkunIndex, KunkunFeature);
REQUIRE(ret == HSUCCEED);
// The features of "Kunkun" library corresponding to those found above are deleted from the face library
ret = FEATURE_HUB->DeleteFaceFeature(searchResult.index);
CHECK(ret == HSUCCEED);
// In search once
SearchResult secondSearchResult;
ret = FEATURE_HUB->SearchFaceFeature(feature, secondSearchResult, 0.5f);
REQUIRE(ret == HSUCCEED);
CHECK(secondSearchResult.index == -1);
spdlog::info("Kunkun被删除了无法找到: {}, {}", secondSearchResult.index, secondSearchResult.tag);
// Just take a random place and change the eigenvector for that place and put "Kunkun" back in there
auto newIndex = 2888;
// Try inserting an unused location first
ret = FEATURE_HUB->UpdateFaceFeature(KunkunFeature, 3001, "Chicken", 3001);
REQUIRE(ret == HERR_SESS_REC_BLOCK_UPDATE_FAILURE);
ret = FEATURE_HUB->UpdateFaceFeature(KunkunFeature, newIndex, "Chicken", 3001);
REQUIRE(ret == HSUCCEED);
SearchResult thirdlySearchResult;
ret = FEATURE_HUB->SearchFaceFeature(feature, thirdlySearchResult, 0.5f);
REQUIRE(ret == HSUCCEED);
CHECK(thirdlySearchResult.index != -1);
CHECK(thirdlySearchResult.index == newIndex);
CHECK(thirdlySearchResult.tag == "Chicken");
spdlog::info("Find Kunkun again -> New Location ID: {}, Confidence: {}, Tag: {}", thirdlySearchResult.index, thirdlySearchResult.score, thirdlySearchResult.tag.c_str());
}
#if ENABLE_BENCHMARK
SECTION("FeatureSearchBenchmark") {
DRAW_SPLIT_LINE
// Initialize
FaceContext ctx;
CustomPipelineParameter param;
param.enable_recognition = true;
auto ret = ctx.Configuration(DetectMode::DETECT_MODE_IMAGE, 1, param);
REQUIRE(ret == HSUCCEED);
FEATURE_HUB->PrintFeatureMatrixInfo();
// Import face feature vectors in batches
String mat_path = GET_DATA("test_faceset/test_faces_A1.npy");
String tags_path = GET_DATA("test_faceset/test_faces_A1.txt");
auto result = LoadMatrixAndTags(mat_path, tags_path);
// Gets the feature matrix and label names
EmbeddedList featureMatrix = result.first;
std::vector<std::string> tagNames = result.second;
REQUIRE(featureMatrix.size() == 3000);
REQUIRE(tagNames.size() == 3000);
REQUIRE(featureMatrix[0].size() == 512);
for (int i = 0; i < featureMatrix.size(); ++i) {
auto &feat = featureMatrix[i];
auto ret = FEATURE_HUB->RegisterFaceFeature(feat, i, tagNames[i], i);
CHECK(ret == HSUCCEED);
}
std::cout << std::endl;
REQUIRE(FEATURE_HUB->GetFaceFeatureCount() == 3000);
spdlog::trace("3000个特征向量全部载入");
// Prepare a picture of a face
auto image = cv::imread(GET_DATA("images/face_sample.png"));
CameraStream stream;
stream.SetDataFormat(BGR);
stream.SetRotationMode(ROTATION_0);
stream.SetDataBuffer(image.data, image.rows, image.cols);
ret = ctx.FaceDetectAndTrack(stream);
REQUIRE(ret == HSUCCEED);
// Face detection
ctx.FaceDetectAndTrack(stream);
const auto &faces = ctx.GetTrackingFaceList();
REQUIRE(faces.size() > 0);
// Feature extraction of "kunkun" was carried out
Embedded feature;
ret = ctx.FaceRecognitionModule()->FaceExtract(stream, faces[0], feature);
CHECK(ret == HSUCCEED);
// Insert the face further back
auto regIndex = 4000;
ret = FEATURE_HUB->RegisterFaceFeature(feature, regIndex, "test", 4000);
REQUIRE(ret == HSUCCEED);
const auto loop = 1000;
double total = 0.0f;
spdlog::info("Start performing {} searches: ", loop);
auto out = (double) cv::getTickCount();
for (int i = 0; i < loop; ++i) {
// Prepare a face photo to look it up from the library
SearchResult searchResult;
auto timeStart = (double) cv::getTickCount();
ret = FEATURE_HUB->SearchFaceFeature(feature, searchResult, 0.5f);
double cost = ((double) cv::getTickCount() - timeStart) / cv::getTickFrequency() * 1000;
REQUIRE(ret == HSUCCEED);
CHECK(searchResult.index == regIndex);
total += cost;
}
auto end = ((double) cv::getTickCount() - out) / cv::getTickFrequency() * 1000;
spdlog::info("Execute {} times Total Cost: {}ms, Average Cost: {}ms", loop, end, total / loop);
}
#endif
}

View File

@@ -0,0 +1,112 @@
//
// Created by tunm on 2023/9/13.
//
#include "settings/test_settings.h"
#include "inspireface/face_context.h"
#include "herror.h"
using namespace inspire;
TEST_CASE("test_FacePipeline", "[face_pipe") {
DRAW_SPLIT_LINE
TEST_PRINT_OUTPUT(true);
SECTION("FaceContextInit") {
FaceContext ctx;
CustomPipelineParameter param;
auto ret = ctx.Configuration(DetectMode::DETECT_MODE_IMAGE, 1, param);
REQUIRE(ret == HSUCCEED);
}
SECTION("FaceContextMaskPredict") {
FaceContext ctx;
CustomPipelineParameter param;
param.enable_mask_detect = true;
auto ret = ctx.Configuration(DetectMode::DETECT_MODE_IMAGE, 1, param);
REQUIRE(ret == HSUCCEED);
{
// Prepare a photo of your face without a mask
auto image = cv::imread(GET_DATA("images/kun.jpg"));
CameraStream stream;
stream.SetDataFormat(BGR);
stream.SetRotationMode(ROTATION_0);
stream.SetDataBuffer(image.data, image.rows, image.cols);
ret = ctx.FaceDetectAndTrack(stream);
REQUIRE(ret == HSUCCEED);
// Face detection
ctx.FaceDetectAndTrack(stream);
auto &faces = ctx.GetTrackingFaceList();
REQUIRE(faces.size() > 0);
auto &face = faces[0];
ctx.FacePipelineModule()->Process(stream, face);
CHECK(face.faceProcess.maskInfo == MaskInfo::UNMASKED);
}
{
// Prepare a face picture with a mask in advance
auto image = cv::imread(GET_DATA("images/mask.png"));
CameraStream stream;
stream.SetDataFormat(BGR);
stream.SetRotationMode(ROTATION_0);
stream.SetDataBuffer(image.data, image.rows, image.cols);
ret = ctx.FaceDetectAndTrack(stream);
REQUIRE(ret == HSUCCEED);
// Face detection
ctx.FaceDetectAndTrack(stream);
auto &faces = ctx.GetTrackingFaceList();
REQUIRE(faces.size() > 0);
auto &face = faces[0];
ctx.FacePipelineModule()->Process(stream, face);
CHECK(face.faceProcess.maskInfo == MaskInfo::MASKED);
}
SECTION("FaceContextLiveness") {
FaceContext ctx;
CustomPipelineParameter param;
param.enable_liveness = true;
auto ret = ctx.Configuration(DetectMode::DETECT_MODE_IMAGE, 1, param);
REQUIRE(ret == HSUCCEED);
{
// Prepare realistic face images
auto image = cv::imread(GET_DATA("images/face_sample.png"));
CameraStream stream;
stream.SetDataFormat(BGR);
stream.SetRotationMode(ROTATION_0);
stream.SetDataBuffer(image.data, image.rows, image.cols);
ret = ctx.FaceDetectAndTrack(stream);
REQUIRE(ret == HSUCCEED);
// Face detection
ctx.FaceDetectAndTrack(stream);
auto &faces = ctx.GetTrackingFaceList();
REQUIRE(faces.size() > 0);
auto &face = faces[0];
ctx.FacePipelineModule()->Process(stream, face);
CHECK(face.faceProcess.rgbLivenessInfo == RGBLivenessInfo::LIVENESS_REAL);
}
{
// Prepare a fake photo that wasn't actually taken
auto image = cv::imread(GET_DATA("images/rgb_fake.jpg"));
CameraStream stream;
stream.SetDataFormat(BGR);
stream.SetRotationMode(ROTATION_0);
stream.SetDataBuffer(image.data, image.rows, image.cols);
ret = ctx.FaceDetectAndTrack(stream);
REQUIRE(ret == HSUCCEED);
// Face detection
ctx.FaceDetectAndTrack(stream);
auto &faces = ctx.GetTrackingFaceList();
REQUIRE(faces.size() > 0);
auto &face = faces[0];
ctx.FacePipelineModule()->Process(stream, face);
CHECK(face.faceProcess.rgbLivenessInfo == RGBLivenessInfo::LIVENESS_FAKE);
}
}
}
}

View File

@@ -0,0 +1,87 @@
//
// Created by Tunm-Air13 on 2023/9/12.
//
#include "settings/test_settings.h"
#include "inspireface/face_context.h"
#include "herror.h"
#include "common/face_data/data_tools.h"
#include "feature_hub/feature_hub.h"
using namespace inspire;
TEST_CASE("test_FaceRecognition", "[face_rec]") {
DRAW_SPLIT_LINE
TEST_PRINT_OUTPUT(true);
SECTION("FaceContextInit") {
FaceContext ctx;
CustomPipelineParameter param;
param.enable_recognition = true;
auto ret = ctx.Configuration(DetectMode::DETECT_MODE_IMAGE, 1, param);
REQUIRE(ret == HSUCCEED);
}
SECTION("FaceRecognitionOption") {
FaceContext ctx;
CustomPipelineParameter param;
param.enable_recognition = false; // Disable the face recognition function
auto ret = ctx.Configuration(DetectMode::DETECT_MODE_IMAGE, 1, param);
REQUIRE(ret == HSUCCEED);
auto image = cv::imread(GET_DATA("images/cxk.jpg"));
CameraStream stream;
stream.SetDataFormat(BGR);
stream.SetRotationMode(ROTATION_0);
stream.SetDataBuffer(image.data, image.rows, image.cols);
ret = ctx.FaceDetectAndTrack(stream);
REQUIRE(ret == HSUCCEED);
ctx.FaceDetectAndTrack(stream);
const auto &faces = ctx.GetTrackingFaceList();
REQUIRE(faces.size() > 0);
Embedded feature;
ret = ctx.FaceRecognitionModule()->FaceExtract(stream, faces[0], feature);
CHECK(ret == HERR_SESS_REC_EXTRACT_FAILURE);
}
SECTION("FaceRecognition1v1") {
FaceContext ctx;
CustomPipelineParameter param;
param.enable_recognition = true;
auto ret = ctx.Configuration(DetectMode::DETECT_MODE_IMAGE, 1, param);
REQUIRE(ret == HSUCCEED);
std::vector<std::string> list = {
GET_DATA("images/kun.jpg"),
GET_DATA("images/Kunkun.jpg"),
};
EmbeddedList vectors;
for (int i = 0; i < 2; ++i) {
auto image = cv::imread(list[i]);
REQUIRE(!image.empty());
CameraStream stream;
stream.SetDataFormat(BGR);
stream.SetRotationMode(ROTATION_0);
stream.SetDataBuffer(image.data, image.rows, image.cols);
ret = ctx.FaceDetectAndTrack(stream);
REQUIRE(ret == HSUCCEED);
ctx.FaceDetectAndTrack(stream);
const auto &faces = ctx.GetTrackingFaceList();
REQUIRE(faces.size() > 0);
Embedded feature;
HyperFaceData data = FaceObjectToHyperFaceData(faces[0]);
ret = ctx.FaceRecognitionModule()->FaceExtract(stream, data, feature);
REQUIRE(ret == HSUCCEED);
vectors.push_back(feature);
}
float score;
ret = FEATURE_HUB->CosineSimilarity(vectors[1], vectors[0], score);
REQUIRE(ret == HSUCCEED);
// spdlog::info("score: {}", score);
CHECK(0.7623623013 == Approx(score).epsilon(1e-2));
}
}