Keep suppressed face reentry from aging unknown

This commit is contained in:
tian 2026-04-15 16:59:41 +08:00
parent 2df11fa072
commit a173ea46f9
3 changed files with 68 additions and 5 deletions

View File

@ -366,8 +366,7 @@
},
"unknown": {
"min_track_age_ms": 2000,
"min_quality_hits": 4,
"reentry_cooldown_ms": 300000
"min_quality_hits": 4
}
},
"face_rules": [

View File

@ -36,7 +36,6 @@ struct FaceTrackAggregationConfig {
int known_reentry_cooldown_ms = 0;
int unknown_min_track_age_ms = 2000;
int unknown_min_quality_hits = 4;
int unknown_reentry_cooldown_ms = 0;
int state_expire_ms = 5000;
};
@ -97,7 +96,6 @@ FaceTrackAggregationConfig ParseFaceTrackAggregationConfig(const SimpleJson& con
cfg.known_reentry_cooldown_ms = std::max(0, agg->ValueOr<int>("known_reentry_cooldown_ms", cfg.known_reentry_cooldown_ms));
cfg.unknown_min_track_age_ms = std::max(0, agg->ValueOr<int>("unknown_min_track_age_ms", cfg.unknown_min_track_age_ms));
cfg.unknown_min_quality_hits = std::max(1, agg->ValueOr<int>("unknown_min_quality_hits", cfg.unknown_min_quality_hits));
cfg.unknown_reentry_cooldown_ms = std::max(0, agg->ValueOr<int>("unknown_reentry_cooldown_ms", cfg.unknown_reentry_cooldown_ms));
cfg.state_expire_ms = std::max(0, agg->ValueOr<int>("state_expire_ms", cfg.state_expire_ms));
if (const SimpleJson* known = agg->Find("known"); known && known->IsObject()) {
@ -108,7 +106,6 @@ FaceTrackAggregationConfig ParseFaceTrackAggregationConfig(const SimpleJson& con
if (const SimpleJson* unknown = agg->Find("unknown"); unknown && unknown->IsObject()) {
cfg.unknown_min_track_age_ms = std::max(0, unknown->ValueOr<int>("min_track_age_ms", cfg.unknown_min_track_age_ms));
cfg.unknown_min_quality_hits = std::max(1, unknown->ValueOr<int>("min_quality_hits", cfg.unknown_min_quality_hits));
cfg.unknown_reentry_cooldown_ms = std::max(0, unknown->ValueOr<int>("reentry_cooldown_ms", cfg.unknown_reentry_cooldown_ms));
}
return cfg;
@ -176,6 +173,11 @@ FaceTrackDecision UpdateFaceTrackState(
}
if (state.reported_known) return decision;
if (!state.reported_known &&
state.best_known_person_id >= 0 &&
state.known_reentry_suppressed_until_ms > 0) {
return decision;
}
if (state.known_reentry_suppressed_until_ms > now_ms) return decision;
if (IsKnownLeaningTrack(state, cfg)) return decision;

View File

@ -405,6 +405,35 @@ TEST(FaceTrackAlarmTest, KnownPersonReEntryTrackCanAlarmAfterCooldownExpires) {
EXPECT_TRUE(node.face_track_states_.at(82).reported_known);
}
TEST(FaceTrackAlarmTest, SuppressedKnownReentryTrackDoesNotAgeIntoUnknownAfterSuppressionWindowWobble) {
FaceTrackAggregationConfig cfg;
cfg.known_min_hits = 2;
cfg.known_hit_window_ms = 5000;
cfg.known_reentry_cooldown_ms = 5000;
cfg.unknown_min_track_age_ms = 1000;
cfg.unknown_min_quality_hits = 1;
std::unordered_map<int, uint64_t> known_identity_last_alarm_ms;
const FaceRecogItem initial_track = MakeKnownFace(91, 5, "alice", 0.88f);
FaceTrackState first_track_state;
EXPECT_FALSE(UpdateFaceTrackState(cfg, first_track_state, known_identity_last_alarm_ms, initial_track, 1000).trigger_known);
EXPECT_TRUE(UpdateFaceTrackState(cfg, first_track_state, known_identity_last_alarm_ms, initial_track, 1500).trigger_known);
FaceTrackState reentry_state;
FaceRecogItem reentry_track = initial_track;
reentry_track.person_track_id = 92;
EXPECT_FALSE(UpdateFaceTrackState(cfg, reentry_state, known_identity_last_alarm_ms, reentry_track, 4000).trigger_known);
EXPECT_FALSE(UpdateFaceTrackState(cfg, reentry_state, known_identity_last_alarm_ms, reentry_track, 4500).trigger_known);
FaceRecogItem wobble = MakeUnknownFace(92, 5, "alice", 0.42f);
const FaceTrackDecision wobble_decision = UpdateFaceTrackState(
cfg, reentry_state, known_identity_last_alarm_ms, wobble, 7000);
EXPECT_FALSE(wobble_decision.trigger_unknown);
EXPECT_FALSE(reentry_state.reported_unknown);
}
TEST(FaceTrackAlarmTest, IgnoresLegacyDisableFlagAndStillUsesTrackAggregation) {
AlarmNode node;
NodeContext ctx;
@ -445,5 +474,38 @@ TEST(FaceTrackAlarmTest, IgnoresLegacyDisableFlagAndStillUsesTrackAggregation) {
EXPECT_EQ(node.alarm_count_, 1u);
}
TEST(FaceTrackAlarmTest, ParsesTrackAggregationWithoutUnknownReentryCooldownContract) {
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": "unknown_face",
"type": "unknown",
"cooldown_ms": 0
}
],
"face_track_aggregation": {
"known": {
"min_hits": 2,
"hit_window_ms": 5000,
"reentry_cooldown_ms": 60000
},
"unknown": {
"min_track_age_ms": 1200,
"min_quality_hits": 2
}
}
})");
ASSERT_TRUE(node.Init(config, ctx));
EXPECT_EQ(node.track_agg_cfg_.known_reentry_cooldown_ms, 60000);
EXPECT_EQ(node.track_agg_cfg_.unknown_min_track_age_ms, 1200);
EXPECT_EQ(node.track_agg_cfg_.unknown_min_quality_hits, 2);
}
} // namespace
} // namespace rk3588