OrangePi3588Media/tests/test_face_track_association.cpp

115 lines
3.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, 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