Source (KPN++ pipeline nodes, ArcFace embedders, SCRFD/YuNet detectors, gallery builder), build scripts, and eval artifacts. - external/KPN as a git submodule (gitea.tourolle.paris/dtourolle/KPN) - ONNX models tracked via Git LFS (models/*.onnx) - generated outputs, TensorRT engines, reference repos, and media ignored
93 lines
3.2 KiB
C++
93 lines
3.2 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";
|
|
}
|
|
|
|
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;
|
|
// 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.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;
|
|
};
|
|
|
|
double extinction_sec_;
|
|
std::map<int, Slot> active_; // actor_idx → state
|
|
};
|