Remove legacy face alarm fallback path

This commit is contained in:
tian 2026-04-15 15:23:52 +08:00
parent afd428f77c
commit afa197fbd5
2 changed files with 60 additions and 74 deletions

View File

@ -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_;

View File

@ -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);
}