142 lines
4.5 KiB
C++
142 lines
4.5 KiB
C++
#include <gtest/gtest.h>
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "face/face_recog_debug.h"
|
|
#include "utils/shared_state.h"
|
|
|
|
#include "../plugins/ai_face_recog/ai_face_recog_node.cpp"
|
|
|
|
namespace rk3588 {
|
|
namespace {
|
|
|
|
Detection MakeDetection(int cls_id, int track_id, float x, float y, float w, float h) {
|
|
Detection det;
|
|
det.cls_id = cls_id;
|
|
det.track_id = track_id;
|
|
det.score = 0.95f;
|
|
det.bbox = Rect{x, y, w, h};
|
|
return det;
|
|
}
|
|
|
|
Detection MakePersonDetection(int track_id, float x, float y, float w, float h) {
|
|
return MakeDetection(0, track_id, x, y, w, h);
|
|
}
|
|
|
|
TEST(FaceTrackAssociationTest, PicksContainingTrackedPerson) {
|
|
const Rect face{50.0f, 50.0f, 20.0f, 20.0f};
|
|
const std::vector<Detection> dets = {
|
|
MakePersonDetection(101, 45.0f, 45.0f, 20.0f, 20.0f),
|
|
MakePersonDetection(202, 40.0f, 40.0f, 40.0f, 40.0f),
|
|
MakePersonDetection(303, 10.0f, 10.0f, 15.0f, 15.0f),
|
|
};
|
|
|
|
EXPECT_EQ(AssociateFaceToPersonTrack(face, dets, 0), 202);
|
|
}
|
|
|
|
TEST(FaceTrackAssociationTest, RejectsWhenNoTrackedPersonMatches) {
|
|
const Rect face{50.0f, 50.0f, 20.0f, 20.0f};
|
|
const std::vector<Detection> dets = {
|
|
MakePersonDetection(-1, 45.0f, 45.0f, 20.0f, 20.0f),
|
|
MakePersonDetection(404, 200.0f, 200.0f, 20.0f, 20.0f),
|
|
};
|
|
|
|
EXPECT_EQ(AssociateFaceToPersonTrack(face, dets, 0), -1);
|
|
}
|
|
|
|
TEST(FaceTrackAssociationTest, RejectsNonPersonDetections) {
|
|
const Rect face{50.0f, 50.0f, 20.0f, 20.0f};
|
|
const std::vector<Detection> dets = {
|
|
MakeDetection(1, 909, 40.0f, 40.0f, 40.0f, 40.0f),
|
|
};
|
|
|
|
EXPECT_EQ(AssociateFaceToPersonTrack(face, dets, 0), -1);
|
|
}
|
|
|
|
TEST(FaceTrackAssociationTest, HonorsConfiguredPersonClassId) {
|
|
const Rect face{50.0f, 50.0f, 20.0f, 20.0f};
|
|
const std::vector<Detection> dets = {
|
|
MakeDetection(1, 808, 40.0f, 40.0f, 40.0f, 40.0f),
|
|
};
|
|
|
|
EXPECT_EQ(AssociateFaceToPersonTrack(face, dets, 1), 808);
|
|
}
|
|
|
|
TEST(FaceTrackAssociationTest, FallsBackToSharedTrackedPersonsWhenFrameDetectionsMissing) {
|
|
const std::string state_key = "face_track_assoc_test";
|
|
SharedState::Instance().ClearTargets(state_key);
|
|
|
|
TargetsSnapshot snap;
|
|
snap.img_w = 1920;
|
|
snap.img_h = 1080;
|
|
snap.model_name = "person_det";
|
|
TrackedObject obj;
|
|
obj.cls_id = 0;
|
|
obj.track_id = 321;
|
|
obj.score = 0.0f;
|
|
obj.bbox = Rect{40.0f, 40.0f, 60.0f, 80.0f};
|
|
obj.confirmed = true;
|
|
snap.objects.push_back(obj);
|
|
SharedState::Instance().SetTargets(state_key, std::move(snap));
|
|
|
|
const Rect face{50.0f, 50.0f, 20.0f, 20.0f};
|
|
FaceTrackAssociationDiag diag;
|
|
const int track_id = AssociateFaceToPersonTrackWithFallback(face, nullptr, 0, state_key, 1000, &diag);
|
|
|
|
EXPECT_EQ(track_id, 321);
|
|
EXPECT_EQ(diag.source, "shared_state");
|
|
EXPECT_EQ(diag.total_dets, 1);
|
|
EXPECT_EQ(diag.person_dets, 1);
|
|
EXPECT_EQ(diag.tracked_person_dets, 1);
|
|
EXPECT_EQ(diag.containing_tracked_person_dets, 1);
|
|
EXPECT_EQ(diag.best_track_id, 321);
|
|
|
|
SharedState::Instance().ClearTargets(state_key);
|
|
}
|
|
|
|
TEST(FaceTrackAssociationTest, UsesGraphDefaultSharedTargetKey) {
|
|
EXPECT_EQ(DefaultTrackedTargetsKey("cam1_full_pipeline"),
|
|
"graph:cam1_full_pipeline:tracked_targets");
|
|
EXPECT_EQ(DefaultTrackedTargetsKey(""), "graph:default:tracked_targets");
|
|
}
|
|
|
|
TEST(FaceTrackAssociationTest, FaceRecogConfigUsesInternalDefaultsForTrackStateAndGalleryDim) {
|
|
const std::string cfg_text = R"({
|
|
"id": "face_recog",
|
|
"track_state_key": "user_should_not_control_this",
|
|
"gallery": {
|
|
"backend": "sqlite",
|
|
"path": "./models/face_gallery.db",
|
|
"expected_dim": 999
|
|
}
|
|
})";
|
|
SimpleJson cfg;
|
|
std::string err;
|
|
ASSERT_TRUE(ParseSimpleJson(cfg_text, cfg, err)) << err;
|
|
|
|
std::shared_ptr<const FaceRecogConfigSnapshot> snap;
|
|
ASSERT_TRUE(BuildFaceRecogConfigSnapshot(cfg, nullptr, snap));
|
|
|
|
EXPECT_TRUE(snap->track_state_key.empty());
|
|
EXPECT_EQ(snap->gallery_expected_dim, 0);
|
|
}
|
|
|
|
TEST(FaceTrackAssociationTest, DebugLineIncludesPersonTrackId) {
|
|
FaceRecogItem item;
|
|
item.person_track_id = 88;
|
|
item.candidate_person_id = 7;
|
|
item.candidate_name = "alice";
|
|
item.best_sim = 0.89f;
|
|
item.second_sim = 0.74f;
|
|
item.state = FaceRecogState::Known;
|
|
|
|
const std::string line = BuildFaceRecogDebugSummaryLine("face_recog", 42, item);
|
|
|
|
EXPECT_NE(line.find("person_track_id=88"), std::string::npos);
|
|
EXPECT_NE(line.find("candidate=alice"), std::string::npos);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace rk3588
|