Remove legacy face alarm fallback path
This commit is contained in:
parent
afd428f77c
commit
afa197fbd5
@ -30,8 +30,6 @@ namespace rk3588 {
|
||||
namespace {
|
||||
|
||||
struct FaceTrackAggregationConfig {
|
||||
bool enable = true;
|
||||
bool require_person_track = true;
|
||||
int known_min_hits = 3;
|
||||
int known_hit_window_ms = 3000;
|
||||
int unknown_min_track_age_ms = 2000;
|
||||
@ -68,8 +66,6 @@ FaceTrackAggregationConfig ParseFaceTrackAggregationConfig(const SimpleJson& con
|
||||
const SimpleJson* agg = config.Find("face_track_aggregation");
|
||||
if (!agg || !agg->IsObject()) return cfg;
|
||||
|
||||
cfg.enable = agg->ValueOr<bool>("enable", cfg.enable);
|
||||
cfg.require_person_track = agg->ValueOr<bool>("require_person_track", cfg.require_person_track);
|
||||
cfg.known_min_hits = std::max(1, agg->ValueOr<int>("known_min_hits", cfg.known_min_hits));
|
||||
cfg.known_hit_window_ms = std::max(0, agg->ValueOr<int>("known_hit_window_ms", cfg.known_hit_window_ms));
|
||||
cfg.unknown_min_track_age_ms = std::max(0, agg->ValueOr<int>("unknown_min_track_age_ms", cfg.unknown_min_track_age_ms));
|
||||
@ -515,7 +511,6 @@ public:
|
||||
track_agg_cfg_ = new_track_agg_cfg;
|
||||
face_last_trigger_.clear();
|
||||
face_person_last_trigger_.clear();
|
||||
face_vote_history_.clear();
|
||||
face_track_states_.clear();
|
||||
packet_buffer_ = std::move(new_packet_buffer);
|
||||
old_actions = std::move(actions_);
|
||||
@ -636,7 +631,6 @@ private:
|
||||
face_rules_ = ParseFaceRulesFromConfig(config);
|
||||
face_last_trigger_.clear();
|
||||
face_person_last_trigger_.clear();
|
||||
face_vote_history_.clear();
|
||||
face_track_states_.clear();
|
||||
}
|
||||
|
||||
@ -649,7 +643,7 @@ private:
|
||||
const int img_w = frame->face_recog->img_w > 0 ? frame->face_recog->img_w : frame->width;
|
||||
const int img_h = frame->face_recog->img_h > 0 ? frame->face_recog->img_h : frame->height;
|
||||
const double img_area = (img_w > 0 && img_h > 0) ? static_cast<double>(img_w) * static_cast<double>(img_h) : 0.0;
|
||||
if (track_agg_cfg_.enable && track_agg_cfg_.state_expire_ms > 0) {
|
||||
if (track_agg_cfg_.state_expire_ms > 0) {
|
||||
const uint64_t expire_ms = static_cast<uint64_t>(track_agg_cfg_.state_expire_ms);
|
||||
for (auto it = face_track_states_.begin(); it != face_track_states_.end();) {
|
||||
const auto& state = it->second;
|
||||
@ -717,15 +711,9 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
const bool can_use_track_aggregation =
|
||||
track_agg_cfg_.enable && it.person_track_id >= 0;
|
||||
if (track_agg_cfg_.enable && track_agg_cfg_.require_person_track && it.person_track_id < 0) {
|
||||
continue;
|
||||
}
|
||||
if (it.person_track_id < 0) continue;
|
||||
|
||||
const std::string key = can_use_track_aggregation
|
||||
? BuildTrackAwareFaceVoteKey(rule, it)
|
||||
: BuildFaceVoteKey(rule, it);
|
||||
const std::string key = BuildFaceTrackKey(rule, it.person_track_id);
|
||||
if (rule.per_person_cooldown_ms > 0) {
|
||||
auto it_last = face_person_last_trigger_.find(key);
|
||||
if (it_last != face_person_last_trigger_.end()) {
|
||||
@ -736,14 +724,10 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
if (can_use_track_aggregation) {
|
||||
auto& state = face_track_states_[it.person_track_id];
|
||||
const FaceTrackDecision decision = UpdateFaceTrackState(track_agg_cfg_, state, it, now_epoch_ms);
|
||||
if (rule.kind == FaceRule::Kind::Person && !decision.trigger_known) continue;
|
||||
if (rule.kind == FaceRule::Kind::Unknown && !decision.trigger_unknown) continue;
|
||||
} else {
|
||||
if (!CheckFaceVote(rule, key, now)) continue;
|
||||
}
|
||||
auto& state = face_track_states_[it.person_track_id];
|
||||
const FaceTrackDecision decision = UpdateFaceTrackState(track_agg_cfg_, state, it, now_epoch_ms);
|
||||
if (rule.kind == FaceRule::Kind::Person && !decision.trigger_known) continue;
|
||||
if (rule.kind == FaceRule::Kind::Unknown && !decision.trigger_unknown) continue;
|
||||
|
||||
matched = true;
|
||||
if (rule.kind == FaceRule::Kind::Person) matched_name = it.best_name;
|
||||
@ -793,40 +777,8 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
static std::string BuildTrackAwareFaceVoteKey(const FaceRule& rule, const FaceRecogItem& item) {
|
||||
if (item.person_track_id >= 0) {
|
||||
return rule.name + "#track:" + std::to_string(item.person_track_id);
|
||||
}
|
||||
return BuildFaceVoteKey(rule, item);
|
||||
}
|
||||
|
||||
static std::string BuildFaceVoteKey(const FaceRule& rule, const FaceRecogItem& item) {
|
||||
if (rule.kind == FaceRule::Kind::Person) {
|
||||
if (item.best_person_id >= 0) {
|
||||
return rule.name + "#" + std::to_string(item.best_person_id);
|
||||
}
|
||||
return rule.name + "#" + item.best_name;
|
||||
}
|
||||
return rule.name + "#unknown";
|
||||
}
|
||||
|
||||
static std::string BuildFaceVoteKey(const FaceRule& rule, int person_id, const std::string& name) {
|
||||
if (rule.kind == FaceRule::Kind::Person) {
|
||||
if (person_id >= 0) return rule.name + "#" + std::to_string(person_id);
|
||||
return rule.name + "#" + name;
|
||||
}
|
||||
return rule.name + "#unknown";
|
||||
}
|
||||
|
||||
bool CheckFaceVote(const FaceRule& rule, const std::string& key, const std::chrono::steady_clock::time_point& now) {
|
||||
if (rule.min_hits <= 1 || rule.hit_window_ms <= 0) return true;
|
||||
auto& dq = face_vote_history_[key];
|
||||
const auto window = std::chrono::milliseconds(rule.hit_window_ms);
|
||||
while (!dq.empty() && (now - dq.front()) > window) {
|
||||
dq.pop_front();
|
||||
}
|
||||
dq.push_back(now);
|
||||
return static_cast<int>(dq.size()) >= rule.min_hits;
|
||||
static std::string BuildFaceTrackKey(const FaceRule& rule, int track_id) {
|
||||
return rule.name + "#track:" + std::to_string(track_id);
|
||||
}
|
||||
void WorkerLoop() {
|
||||
while (worker_running_.load()) {
|
||||
@ -874,7 +826,6 @@ private:
|
||||
std::vector<FaceRule> face_rules_;
|
||||
std::map<std::string, std::chrono::steady_clock::time_point> face_last_trigger_;
|
||||
std::map<std::string, std::chrono::steady_clock::time_point> face_person_last_trigger_;
|
||||
std::map<std::string, std::deque<std::chrono::steady_clock::time_point>> face_vote_history_;
|
||||
FaceTrackAggregationConfig track_agg_cfg_;
|
||||
std::map<int, FaceTrackState> face_track_states_;
|
||||
std::shared_ptr<PacketRingBuffer> packet_buffer_;
|
||||
|
||||
@ -52,6 +52,14 @@ FramePtr MakeFaceFrame(uint64_t frame_id, const FaceRecogItem& item, int img_w =
|
||||
return frame;
|
||||
}
|
||||
|
||||
SimpleJson ParseConfig(const std::string& text) {
|
||||
SimpleJson config;
|
||||
std::string err;
|
||||
const bool ok = ParseSimpleJson(text, config, err);
|
||||
EXPECT_TRUE(ok) << err;
|
||||
return config;
|
||||
}
|
||||
|
||||
AlarmNode::FaceRule MakeKnownRule() {
|
||||
AlarmNode::FaceRule rule;
|
||||
rule.name = "known_person";
|
||||
@ -61,16 +69,6 @@ AlarmNode::FaceRule MakeKnownRule() {
|
||||
return rule;
|
||||
}
|
||||
|
||||
AlarmNode::FaceRule MakeLegacyKnownRule() {
|
||||
AlarmNode::FaceRule rule;
|
||||
rule.name = "known_person";
|
||||
rule.kind = AlarmNode::FaceRule::Kind::Person;
|
||||
rule.cooldown_ms = 0;
|
||||
rule.min_hits = 2;
|
||||
rule.hit_window_ms = 5000;
|
||||
return rule;
|
||||
}
|
||||
|
||||
TEST(FaceTrackAlarmTest, IgnoresLowQualityUntrackedFace) {
|
||||
FaceTrackAggregationConfig cfg;
|
||||
FaceTrackState state;
|
||||
@ -152,7 +150,6 @@ TEST(FaceTrackAlarmTest, ExpiresStateAfterTrackInactivity) {
|
||||
|
||||
TEST(FaceTrackAlarmTest, DisqualifiedFramesDoNotAdvanceTrackAggregation) {
|
||||
AlarmNode node;
|
||||
node.track_agg_cfg_.enable = true;
|
||||
node.track_agg_cfg_.known_min_hits = 2;
|
||||
node.track_agg_cfg_.known_hit_window_ms = 5000;
|
||||
auto rule = MakeKnownRule();
|
||||
@ -174,20 +171,58 @@ TEST(FaceTrackAlarmTest, DisqualifiedFramesDoNotAdvanceTrackAggregation) {
|
||||
EXPECT_EQ(node.alarm_count_, 1u);
|
||||
}
|
||||
|
||||
TEST(FaceTrackAlarmTest, LegacyFallbackKeepsPersonVoteAcrossTrackChanges) {
|
||||
TEST(FaceTrackAlarmTest, UntrackedQualifiedFaceDoesNotTriggerAlarm) {
|
||||
AlarmNode node;
|
||||
node.track_agg_cfg_.enable = false;
|
||||
node.face_rules_.push_back(MakeLegacyKnownRule());
|
||||
node.track_agg_cfg_.known_min_hits = 2;
|
||||
node.track_agg_cfg_.known_hit_window_ms = 5000;
|
||||
node.face_rules_.push_back(MakeKnownRule());
|
||||
|
||||
FaceRecogItem first = MakeKnownFace(21, 5, "alice", 0.88f);
|
||||
FaceRecogItem first = MakeKnownFace(-1, 5, "alice", 0.88f);
|
||||
first.bbox = Rect{0.0f, 0.0f, 20.0f, 20.0f};
|
||||
FaceRecogItem second = first;
|
||||
second.person_track_id = 22;
|
||||
|
||||
EXPECT_EQ(node.Process(MakeFaceFrame(1, first)), NodeStatus::OK);
|
||||
EXPECT_EQ(node.alarm_count_, 0u);
|
||||
|
||||
EXPECT_EQ(node.Process(MakeFaceFrame(2, second)), NodeStatus::OK);
|
||||
EXPECT_EQ(node.alarm_count_, 0u);
|
||||
}
|
||||
|
||||
TEST(FaceTrackAlarmTest, IgnoresLegacyDisableFlagAndStillUsesTrackAggregation) {
|
||||
AlarmNode node;
|
||||
NodeContext ctx;
|
||||
ctx.input_queue = std::make_shared<SpscQueue<FramePtr>>(4, QueueDropStrategy::DropOldest);
|
||||
|
||||
const SimpleJson config = ParseConfig(R"({
|
||||
"id": "alarm",
|
||||
"face_rules": [
|
||||
{
|
||||
"name": "known_person",
|
||||
"type": "person",
|
||||
"persons": ["alice"],
|
||||
"cooldown_ms": 0
|
||||
}
|
||||
],
|
||||
"face_track_aggregation": {
|
||||
"enable": false,
|
||||
"known": {
|
||||
"min_hits": 2,
|
||||
"hit_window_ms": 5000
|
||||
}
|
||||
}
|
||||
})");
|
||||
|
||||
ASSERT_TRUE(node.Init(config, ctx));
|
||||
EXPECT_EQ(node.track_agg_cfg_.known_min_hits, 2);
|
||||
EXPECT_EQ(node.track_agg_cfg_.known_hit_window_ms, 5000);
|
||||
|
||||
FaceRecogItem item = MakeKnownFace(31, 5, "alice", 0.88f);
|
||||
item.bbox = Rect{0.0f, 0.0f, 20.0f, 20.0f};
|
||||
|
||||
EXPECT_EQ(node.Process(MakeFaceFrame(1, item)), NodeStatus::OK);
|
||||
EXPECT_EQ(node.alarm_count_, 0u);
|
||||
|
||||
EXPECT_EQ(node.Process(MakeFaceFrame(2, item)), NodeStatus::OK);
|
||||
EXPECT_EQ(node.alarm_count_, 1u);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user