Gallery format switches from JSON to HDF5 exclusively (JSON read-only kept for back-compat): save_gallery always writes HDF5, and the fitted Platt-sigmoid calibration (a, b, valid, hash) is now embedded directly in the gallery file instead of a sidecar .calib_cache.json — identity_matcher reads it from the loaded gallery and writes back only when the embeddings actually changed (hash mismatch), skipping the O(n^2) refit otherwise. Also includes: TensorRT inference backend support (ort_backend.cpp, trt_backend.cpp), gemm_backend improvements, TransNetV2-based scene-boundary detection wired through frame_source/face_tracker/main, and CMake build target updates for the new sources. Bumps the KPN submodule to feature/persistent-pipeline-reuse (push_blocking backpressure, node_ptr/node_stats introspection, ObjectVariantNodeWrapper for stateful functors) — needed by the optimizer's sae_kpn Python bindings.
103 lines
3.6 KiB
C++
103 lines
3.6 KiB
C++
#pragma once
|
|
#include "types.hpp"
|
|
#include "config.hpp"
|
|
|
|
#include <map>
|
|
#include <iostream>
|
|
|
|
// ── SceneTrackerFunc ──────────────────────────────────────────────────────────
|
|
// KPN node: maintains an extinction-timer state machine per identified actor.
|
|
//
|
|
// On each MatchedSceneFrame:
|
|
// 1. Update last_seen for every matched known actor.
|
|
// 2. Expire actors whose last_seen is older than extinction_sec.
|
|
// 3. Emit SceneAnnotation with all currently active (non-expired) actors,
|
|
// including their most recently seen bbox and best similarity score.
|
|
//
|
|
// Unknown faces (actor_idx == -1) are passed through per-frame but are NOT
|
|
// tracked across frames — each frame reports its own unknowns independently.
|
|
|
|
struct SceneTrackerFunc {
|
|
static constexpr std::string_view label() { return "scene_tracker"; }
|
|
|
|
explicit SceneTrackerFunc(const Config& cfg)
|
|
: extinction_sec_(cfg.extinction_sec)
|
|
{
|
|
std::cerr << "[scene_tracker] extinction_sec=" << extinction_sec_ << "\n";
|
|
}
|
|
|
|
// Runtime setter for pipeline reuse across a sweep. Also clears the active-actor
|
|
// state so a re-run starts clean (no carry-over from the previous config's film).
|
|
void set_extinction_sec(double s) { extinction_sec_ = s; active_.clear(); }
|
|
|
|
SceneAnnotation operator()(MatchedSceneFrame mf) {
|
|
if (mf.source.eof) return {0.0, {}, /*eof=*/true};
|
|
|
|
double now = mf.source.timestamp_sec;
|
|
|
|
// Update known actors
|
|
for (const auto& ia : mf.actors) {
|
|
if (ia.actor_idx < 0) continue; // skip unknowns
|
|
|
|
auto& slot = active_[ia.actor_idx];
|
|
slot.last_seen = now;
|
|
slot.last_bbox = ia.bbox;
|
|
slot.last_crop = ia.crop;
|
|
slot.name = ia.name;
|
|
slot.imdb_id = ia.imdb_id;
|
|
slot.tmdb_id = ia.tmdb_id;
|
|
slot.jellyfin_id = ia.jellyfin_id;
|
|
// Keep the best (highest) similarity seen in this window
|
|
if (ia.similarity > slot.best_similarity)
|
|
slot.best_similarity = ia.similarity;
|
|
}
|
|
|
|
// Expire stale actors
|
|
for (auto it = active_.begin(); it != active_.end(); ) {
|
|
if ((now - it->second.last_seen) > extinction_sec_)
|
|
it = active_.erase(it);
|
|
else
|
|
++it;
|
|
}
|
|
|
|
// Build annotation: active known actors
|
|
std::vector<IdentifiedActor> visible;
|
|
visible.reserve(active_.size() + mf.actors.size());
|
|
|
|
for (const auto& [actor_idx, slot] : active_) {
|
|
IdentifiedActor ia;
|
|
ia.actor_idx = actor_idx;
|
|
ia.name = slot.name;
|
|
ia.imdb_id = slot.imdb_id;
|
|
ia.tmdb_id = slot.tmdb_id;
|
|
ia.jellyfin_id = slot.jellyfin_id;
|
|
ia.similarity = slot.best_similarity;
|
|
ia.bbox = slot.last_bbox;
|
|
ia.crop = slot.last_crop;
|
|
visible.push_back(ia);
|
|
}
|
|
|
|
// Append per-frame unknowns (actor_idx == -1) directly
|
|
for (const auto& ia : mf.actors) {
|
|
if (ia.actor_idx < 0) visible.push_back(ia);
|
|
}
|
|
|
|
return {now, std::move(visible)};
|
|
}
|
|
|
|
private:
|
|
struct Slot {
|
|
double last_seen{0.0};
|
|
float best_similarity{0.f};
|
|
cv::Rect2f last_bbox;
|
|
cv::Mat last_crop;
|
|
std::string name;
|
|
std::string imdb_id;
|
|
std::string tmdb_id;
|
|
std::string jellyfin_id;
|
|
};
|
|
|
|
double extinction_sec_;
|
|
std::map<int, Slot> active_; // actor_idx → state
|
|
};
|