Merge branch 'feature/gallery-report' into feature/opencv5
This commit is contained in:
@@ -168,3 +168,96 @@ TEST_CASE("calibrate_gallery_cached treats hash=0 as always-recompute", "[calibr
|
||||
CHECK(recomputed);
|
||||
CHECK(cal.valid);
|
||||
}
|
||||
|
||||
// ── GR-003 — the build report ────────────────────────────────────────────────
|
||||
#include "gallery/gallery_report.hpp"
|
||||
|
||||
namespace {
|
||||
// A unit vector on one axis. Distinct axes are orthogonal, which is unrealistic
|
||||
// as a same-actor cluster but irrelevant here: these tests count actors, they do
|
||||
// not assess fit quality.
|
||||
Embedding unit_axis(int slot) {
|
||||
Embedding e{};
|
||||
e[slot % 512] = 1.0f;
|
||||
return e;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("report surfaces actors that can never be recognised", "[report][GR-003]") {
|
||||
// An actor with no usable image is a silent recall ceiling: the pipeline
|
||||
// will never name them, and nothing in the gallery says why. This is the
|
||||
// single most useful number in the report.
|
||||
ActorGallery g;
|
||||
for (int a = 0; a < 3; ++a) {
|
||||
ActorGallery::Actor act;
|
||||
act.name = "actor" + std::to_string(a);
|
||||
if (a != 1) // actor1 gets nothing
|
||||
for (int i = 0; i < 6; ++i) act.embeddings.push_back(unit_axis(a * 10 + i));
|
||||
g.actors.push_back(std::move(act));
|
||||
}
|
||||
|
||||
std::vector<Embedding> flat;
|
||||
std::vector<int> flat_actor;
|
||||
for (int a = 0; a < static_cast<int>(g.actors.size()); ++a)
|
||||
for (const auto& e : g.actors[a].embeddings) { flat.push_back(e); flat_actor.push_back(a); }
|
||||
|
||||
GalleryCalibrationStats stats;
|
||||
GalleryCalibration cal = calibrate_gallery(flat, flat_actor, &stats);
|
||||
GalleryReport r = build_gallery_report(g, cal, stats);
|
||||
|
||||
// An actor present in the gallery with no embeddings is counted as
|
||||
// in-gallery but contributes nothing; the zero-usable list is populated
|
||||
// from the build audit, which a stored gallery cannot supply.
|
||||
CHECK(r.actors_in_gallery == 3);
|
||||
CHECK(r.actors[1].references == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("report surfaces actors too thin to calibrate on", "[report][GR-003]") {
|
||||
// Below the positive-pair threshold an actor contributes nothing to the
|
||||
// intra-class side of the fit. They are not broken, so nothing complains —
|
||||
// they just quietly weaken every threshold downstream.
|
||||
ActorGallery g;
|
||||
for (int a = 0; a < 2; ++a) {
|
||||
ActorGallery::Actor act;
|
||||
act.name = "actor" + std::to_string(a);
|
||||
const int n = (a == 0) ? 6 : 2; // actor1 is under-referenced
|
||||
for (int i = 0; i < n; ++i) act.embeddings.push_back(unit_axis(a * 10 + i));
|
||||
g.actors.push_back(std::move(act));
|
||||
}
|
||||
|
||||
std::vector<Embedding> flat;
|
||||
std::vector<int> flat_actor;
|
||||
for (int a = 0; a < static_cast<int>(g.actors.size()); ++a)
|
||||
for (const auto& e : g.actors[a].embeddings) { flat.push_back(e); flat_actor.push_back(a); }
|
||||
|
||||
GalleryCalibrationStats stats;
|
||||
GalleryCalibration cal = calibrate_gallery(flat, flat_actor, &stats);
|
||||
GalleryReport r = build_gallery_report(g, cal, stats);
|
||||
|
||||
CHECK(r.actors_below_positive_threshold >= 1);
|
||||
}
|
||||
|
||||
TEST_CASE("report round-trips", "[report][GR-003]") {
|
||||
ActorGallery g;
|
||||
ActorGallery::Actor act;
|
||||
act.name = "solo";
|
||||
for (int i = 0; i < 6; ++i) act.embeddings.push_back(unit_axis(i));
|
||||
g.actors.push_back(std::move(act));
|
||||
|
||||
std::vector<Embedding> flat;
|
||||
std::vector<int> flat_actor;
|
||||
for (const auto& e : g.actors[0].embeddings) { flat.push_back(e); flat_actor.push_back(0); }
|
||||
|
||||
GalleryCalibrationStats stats;
|
||||
GalleryCalibration cal = calibrate_gallery(flat, flat_actor, &stats);
|
||||
GalleryReport r = build_gallery_report(g, cal, stats);
|
||||
|
||||
const std::string path = "/tmp/gr003_roundtrip.report.json";
|
||||
save_gallery_report(path, r);
|
||||
GalleryReport back = load_gallery_report(path);
|
||||
|
||||
CHECK(back.actors_in_gallery == r.actors_in_gallery);
|
||||
CHECK(back.actors_below_positive_threshold == r.actors_below_positive_threshold);
|
||||
CHECK(back.calib_a == r.calib_a);
|
||||
std::remove(path.c_str());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user