Fix face alarm reentry track latch

This commit is contained in:
tian 2026-04-15 16:44:00 +08:00
parent 68d7c9edcf
commit 2df11fa072
2 changed files with 43 additions and 3 deletions

View File

@ -49,6 +49,7 @@ struct FaceTrackState {
int quality_hits = 0; int quality_hits = 0;
bool reported_known = false; bool reported_known = false;
bool reported_unknown = false; bool reported_unknown = false;
uint64_t known_reentry_suppressed_until_ms = 0;
std::deque<uint64_t> known_hit_times; std::deque<uint64_t> known_hit_times;
}; };
@ -158,8 +159,9 @@ FaceTrackDecision UpdateFaceTrackState(
if (it_last != known_identity_last_alarm_ms.end() && if (it_last != known_identity_last_alarm_ms.end() &&
now_ms >= it_last->second && now_ms >= it_last->second &&
(now_ms - it_last->second) < static_cast<uint64_t>(cfg.known_reentry_cooldown_ms)) { (now_ms - it_last->second) < static_cast<uint64_t>(cfg.known_reentry_cooldown_ms)) {
state.reported_known = true; state.known_reentry_suppressed_until_ms =
state.reported_unknown = false; std::max(state.known_reentry_suppressed_until_ms,
it_last->second + static_cast<uint64_t>(cfg.known_reentry_cooldown_ms));
return decision; return decision;
} }
} }
@ -174,6 +176,7 @@ FaceTrackDecision UpdateFaceTrackState(
} }
if (state.reported_known) return decision; if (state.reported_known) return decision;
if (state.known_reentry_suppressed_until_ms > now_ms) return decision;
if (IsKnownLeaningTrack(state, cfg)) return decision; if (IsKnownLeaningTrack(state, cfg)) return decision;
++state.quality_hits; ++state.quality_hits;

View File

@ -120,8 +120,14 @@ TEST(FaceTrackAlarmTest, SuppressesKnownReentryInsideConfiguredCooldown) {
const FaceTrackDecision suppressed = UpdateFaceTrackState( const FaceTrackDecision suppressed = UpdateFaceTrackState(
cfg, reentry_state, known_identity_last_alarm_ms, reentry_track, 4500); cfg, reentry_state, known_identity_last_alarm_ms, reentry_track, 4500);
EXPECT_FALSE(suppressed.trigger_known); EXPECT_FALSE(suppressed.trigger_known);
EXPECT_TRUE(reentry_state.reported_known); EXPECT_FALSE(reentry_state.reported_known);
EXPECT_EQ(known_identity_last_alarm_ms.at(1), 1500u); EXPECT_EQ(known_identity_last_alarm_ms.at(1), 1500u);
const FaceTrackDecision after_cooldown = UpdateFaceTrackState(
cfg, reentry_state, known_identity_last_alarm_ms, reentry_track, 7000);
EXPECT_TRUE(after_cooldown.trigger_known);
EXPECT_TRUE(reentry_state.reported_known);
EXPECT_EQ(known_identity_last_alarm_ms.at(1), 7000u);
} }
TEST(FaceTrackAlarmTest, DoesNotEmitUnknownForKnownPersonScoreWobble) { TEST(FaceTrackAlarmTest, DoesNotEmitUnknownForKnownPersonScoreWobble) {
@ -368,6 +374,37 @@ TEST(FaceTrackAlarmTest, KnownPersonReEntryInsideCooldownOnNewTrackDoesNotReAlar
EXPECT_EQ(node.known_identity_last_alarm_ms_.at(5), first_alarm_it->second); EXPECT_EQ(node.known_identity_last_alarm_ms_.at(5), first_alarm_it->second);
} }
TEST(FaceTrackAlarmTest, KnownPersonReEntryTrackCanAlarmAfterCooldownExpires) {
AlarmNode node;
node.track_agg_cfg_.known_min_hits = 2;
node.track_agg_cfg_.known_hit_window_ms = 5000;
node.track_agg_cfg_.known_reentry_cooldown_ms = 1000;
auto rule = MakeKnownRule();
rule.cooldown_ms = 0;
node.face_rules_.push_back(rule);
FaceRecogItem first_track = MakeKnownFace(81, 5, "alice", 0.88f);
first_track.bbox = Rect{0.0f, 0.0f, 20.0f, 20.0f};
FaceRecogItem second_track = MakeKnownFace(82, 5, "alice", 0.88f);
second_track.bbox = first_track.bbox;
EXPECT_EQ(node.Process(MakeFaceFrame(1, first_track)), NodeStatus::OK);
EXPECT_EQ(node.Process(MakeFaceFrame(2, first_track)), NodeStatus::OK);
EXPECT_EQ(node.alarm_count_, 1u);
EXPECT_EQ(node.Process(MakeFaceFrame(3, second_track)), NodeStatus::OK);
EXPECT_EQ(node.Process(MakeFaceFrame(4, second_track)), NodeStatus::OK);
EXPECT_EQ(node.alarm_count_, 1u);
EXPECT_FALSE(node.face_track_states_.at(82).reported_known);
node.known_identity_last_alarm_ms_[5] = 0;
EXPECT_EQ(node.Process(MakeFaceFrame(5, second_track)), NodeStatus::OK);
EXPECT_EQ(node.alarm_count_, 2u);
EXPECT_TRUE(node.face_track_states_.at(82).reported_known);
}
TEST(FaceTrackAlarmTest, IgnoresLegacyDisableFlagAndStillUsesTrackAggregation) { TEST(FaceTrackAlarmTest, IgnoresLegacyDisableFlagAndStillUsesTrackAggregation) {
AlarmNode node; AlarmNode node;
NodeContext ctx; NodeContext ctx;