diff --git a/configs/full_pipeline_1080p.json b/configs/full_pipeline_1080p.json index 4acd662..4ad1657 100644 --- a/configs/full_pipeline_1080p.json +++ b/configs/full_pipeline_1080p.json @@ -85,7 +85,6 @@ "backend": "sqlite", "path": "./models/face_gallery.db", "load_on_start": true, - "expected_dim": 128, "dtype": "auto" } }, @@ -132,7 +131,6 @@ "cpu_affinity": [5], "mode": "bytetrack_lite", "per_class": true, - "state_key": "full_pipeline_1080p_workshoe", "track_classes": [0], "ignore_classes": [], "high_th": 0.55, diff --git a/configs/full_pipeline_1080p_test_alarm.json b/configs/full_pipeline_1080p_test_alarm.json index 2e71270..fe9dd03 100644 --- a/configs/full_pipeline_1080p_test_alarm.json +++ b/configs/full_pipeline_1080p_test_alarm.json @@ -92,7 +92,6 @@ "emit_embedding": false, "max_faces": 50, "person_class_id": 0, - "track_state_key": "full_pipeline_1080p_workshoe", "track_state_max_age_ms": 1000, "input_format": "rgb", "input_dtype": "uint8", @@ -104,7 +103,6 @@ "backend": "sqlite", "path": "./models/face_gallery.db", "load_on_start": true, - "expected_dim": 512, "dtype": "auto" }, "debug": { @@ -162,7 +160,6 @@ ], "mode": "bytetrack_lite", "per_class": true, - "state_key": "full_pipeline_1080p_workshoe", "track_classes": [ 0 ], diff --git a/configs/full_pipeline_1080p_test_alarm_shoe_debug.json b/configs/full_pipeline_1080p_test_alarm_shoe_debug.json index db09c28..1254a61 100644 --- a/configs/full_pipeline_1080p_test_alarm_shoe_debug.json +++ b/configs/full_pipeline_1080p_test_alarm_shoe_debug.json @@ -101,7 +101,6 @@ "backend": "sqlite", "path": "./models/face_gallery.db", "load_on_start": true, - "expected_dim": 512, "dtype": "auto" }, "debug": { @@ -159,7 +158,6 @@ ], "mode": "bytetrack_lite", "per_class": true, - "state_key": "full_pipeline_1080p_workshoe", "track_classes": [ 0 ], diff --git a/configs/production_4ch.json b/configs/production_4ch.json index f00f666..8932a7f 100644 --- a/configs/production_4ch.json +++ b/configs/production_4ch.json @@ -63,7 +63,6 @@ "enable": true, "mode": "bytetrack_lite", "per_class": true, - "state_key": "${name}", "track_classes": [3, 6, 10], "ignore_classes": [], "allowed_models": ["yolov8"], @@ -121,7 +120,6 @@ "backend": "sqlite", "path": "${face_gallery_path}", "load_on_start": true, - "expected_dim": 512, "dtype": "auto" } }, diff --git a/configs/sample_cam1.json b/configs/sample_cam1.json index 80cfb4f..b81d3a6 100644 --- a/configs/sample_cam1.json +++ b/configs/sample_cam1.json @@ -73,7 +73,6 @@ "backend": "sqlite", "path": "./models/face_gallery.db", "load_on_start": true, - "expected_dim": 512, "dtype": "auto" } }, @@ -84,7 +83,6 @@ "enable": true, "mode": "bytetrack_lite", "per_class": true, - "state_key": "cam1_sample_full_pipeline", "track_classes": [0], "ignore_classes": [], "allowed_models": ["yolov5", "yolov8"], @@ -101,7 +99,6 @@ "type": "gate", "role": "filter", "enable": true, - "state_key": "cam1_sample_full_pipeline", "class_ids": [0], "require_confirmed": true, "min_count": 2, diff --git a/configs/sample_cam1_face_zoned.json b/configs/sample_cam1_face_zoned.json index a5482d5..142112e 100644 --- a/configs/sample_cam1_face_zoned.json +++ b/configs/sample_cam1_face_zoned.json @@ -103,7 +103,6 @@ "backend": "sqlite", "path": "./models/face_gallery.db", "load_on_start": true, - "expected_dim": 512, "dtype": "auto" } }, diff --git a/configs/sample_cam1_native_rtsp_face.json b/configs/sample_cam1_native_rtsp_face.json index bc05b0d..7ccbb9e 100644 --- a/configs/sample_cam1_native_rtsp_face.json +++ b/configs/sample_cam1_native_rtsp_face.json @@ -53,7 +53,6 @@ "enable": true, "mode": "bytetrack_lite", "per_class": true, - "state_key": "cam1_native_main", "track_classes": [0], "ignore_classes": [], "allowed_models": ["yolov5", "yolov8"], @@ -231,7 +230,6 @@ "backend": "sqlite", "path": "./models/face_gallery.db", "load_on_start": true, - "expected_dim": 512, "dtype": "auto" } }, diff --git a/configs/sample_cam1_ppe12.json b/configs/sample_cam1_ppe12.json index 07d349c..fa26e1c 100644 --- a/configs/sample_cam1_ppe12.json +++ b/configs/sample_cam1_ppe12.json @@ -63,7 +63,6 @@ "enable": true, "mode": "bytetrack_lite", "per_class": true, - "state_key": "cam_ppe11_detection", "track_classes": [3, 6, 10], "ignore_classes": [], "allowed_models": ["yolov8"], @@ -121,7 +120,6 @@ "backend": "sqlite", "path": "./models/face_gallery.db", "load_on_start": true, - "expected_dim": 512, "dtype": "auto" } }, diff --git a/configs/sample_cam1_v5.json b/configs/sample_cam1_v5.json index 6c14ffc..330223c 100644 --- a/configs/sample_cam1_v5.json +++ b/configs/sample_cam1_v5.json @@ -73,7 +73,6 @@ "backend": "sqlite", "path": "./models/face_gallery.db", "load_on_start": true, - "expected_dim": 512, "dtype": "auto" } }, @@ -84,7 +83,6 @@ "enable": true, "mode": "bytetrack_lite", "per_class": true, - "state_key": "cam1_sample_full_pipeline", "track_classes": [0], "ignore_classes": [], "allowed_models": ["yolov5", "yolov8"], diff --git a/configs/stress_5ch_letterbox.json b/configs/stress_5ch_letterbox.json index 6bbc23d..65b6cef 100644 --- a/configs/stress_5ch_letterbox.json +++ b/configs/stress_5ch_letterbox.json @@ -84,7 +84,6 @@ "backend": "sqlite", "path": "${face_gallery_path}", "load_on_start": true, - "expected_dim": 512, "dtype": "auto" } }, @@ -95,7 +94,6 @@ "enable": true, "mode": "bytetrack_lite", "per_class": true, - "state_key": "${name}", "track_classes": [3, 6], "ignore_classes": [], "allowed_models": ["yolov5", "yolov8"], diff --git a/configs/stress_5ch_stretch.json b/configs/stress_5ch_stretch.json index 58a63dd..d41a182 100644 --- a/configs/stress_5ch_stretch.json +++ b/configs/stress_5ch_stretch.json @@ -84,7 +84,6 @@ "backend": "sqlite", "path": "${face_gallery_path}", "load_on_start": true, - "expected_dim": 512, "dtype": "auto" } }, @@ -95,7 +94,6 @@ "enable": true, "mode": "bytetrack_lite", "per_class": true, - "state_key": "${name}", "track_classes": [3, 6], "ignore_classes": [], "allowed_models": ["yolov5", "yolov8"], diff --git a/configs/test_cam1_face_det_recog_rtsp_server.json b/configs/test_cam1_face_det_recog_rtsp_server.json index c465c1d..98559e2 100644 --- a/configs/test_cam1_face_det_recog_rtsp_server.json +++ b/configs/test_cam1_face_det_recog_rtsp_server.json @@ -60,7 +60,6 @@ "backend": "sqlite", "path": "./models/face_gallery.db", "load_on_start": true, - "expected_dim": 512, "dtype": "auto" } }, diff --git a/configs/test_scrfd_640_recog.json b/configs/test_scrfd_640_recog.json index 6a6ab22..e0688a6 100644 --- a/configs/test_scrfd_640_recog.json +++ b/configs/test_scrfd_640_recog.json @@ -67,7 +67,6 @@ "backend": "sqlite", "path": "./models/face_gallery.db", "load_on_start": true, - "expected_dim": 512, "dtype": "auto" } }, diff --git a/configs/test_scrfd_sliding_1080p_recog.json b/configs/test_scrfd_sliding_1080p_recog.json index f1f6cc6..53d3816 100644 --- a/configs/test_scrfd_sliding_1080p_recog.json +++ b/configs/test_scrfd_sliding_1080p_recog.json @@ -70,7 +70,6 @@ "backend": "sqlite", "path": "./models/face_gallery.db", "load_on_start": true, - "expected_dim": 512, "dtype": "auto" } }, diff --git a/docs/config_guide.md b/docs/config_guide.md index 9b83632..cfde8c6 100644 --- a/docs/config_guide.md +++ b/docs/config_guide.md @@ -256,7 +256,6 @@ pre_rgb -> face_det -> person_det -> person_trk -> face_recog -> ... "emit_embedding": false, "max_faces": 50, "person_class_id": 0, - "track_state_key": "full_pipeline_1080p_workshoe", "track_state_max_age_ms": 1000, "input_format": "rgb", "input_dtype": "uint8", @@ -268,7 +267,6 @@ pre_rgb -> face_det -> person_det -> person_trk -> face_recog -> ... "backend": "sqlite", "path": "./models/face_gallery.db", "load_on_start": true, - "expected_dim": 512, "dtype": "auto" }, "debug": { @@ -290,11 +288,14 @@ pre_rgb -> face_det -> person_det -> person_trk -> face_recog -> ... | `threshold.accept` | 识别为已知人的最低相似度 | 当前测试用 `0.45` | | `threshold.margin` | top1 与 top2 的最小差值 | 当前测试用 `0.05`,用于降低相似人员误认 | | `gallery.path` | SQLite 人脸库路径 | `./models/face_gallery.db` | -| `gallery.expected_dim` | embedding 维度 | `512`,需与识别模型一致 | -| `track_state_key` | 读取人体跟踪状态的 key | 必须与 `tracker.state_key` 一致 | | `track_state_max_age_ms` | 可接受的跟踪状态最大年龄 | `1000` 左右 | | `debug.log_matches` | 打印每次人脸匹配结果 | 测试阶段开启,正式运行可关闭 | +说明: + +- 人脸识别会自动读取同一 graph 内 tracker 发布的人体跟踪状态,不需要配置 shared-state key。 +- 人脸库 embedding 维度会从图库数据自动推断,不需要在配置文件中填写。 + 识别状态含义: - `known`:满足 `threshold.accept` 和 `threshold.margin`,可以作为“已知人”证据。 diff --git a/include/node.h b/include/node.h index 4766d82..a2b2361 100644 --- a/include/node.h +++ b/include/node.h @@ -22,6 +22,7 @@ enum class NodeStatus { }; struct NodeContext { + std::string graph_name; // For nodes with upstream input. std::shared_ptr> input_queue; // For nodes that produce downstream outputs (one queue per outgoing edge). diff --git a/include/utils/shared_state.h b/include/utils/shared_state.h index 970bbb1..fdb993c 100644 --- a/include/utils/shared_state.h +++ b/include/utils/shared_state.h @@ -42,6 +42,7 @@ struct TargetsSnapshot { }; RK3588_SHARED_STATE_API uint64_t NowSteadyUs(); +RK3588_SHARED_STATE_API std::string DefaultTrackedTargetsKey(const std::string& graph_name); class RK3588_SHARED_STATE_API SharedState { public: diff --git a/plugins/ai_face_recog/ai_face_recog_node.cpp b/plugins/ai_face_recog/ai_face_recog_node.cpp index 2e99fb8..af9bfe2 100644 --- a/plugins/ai_face_recog/ai_face_recog_node.cpp +++ b/plugins/ai_face_recog/ai_face_recog_node.cpp @@ -677,7 +677,7 @@ struct FaceRecogConfigSnapshot { std::string gallery_backend = "sqlite"; std::string gallery_path = "./models/face_gallery.db"; bool gallery_load_on_start = true; - int gallery_expected_dim = 512; + int gallery_expected_dim = 0; std::string gallery_dtype = "auto"; int gallery_reload_seq = 0; @@ -694,7 +694,6 @@ static bool BuildFaceRecogConfigSnapshot(const SimpleJson& config, snap->emit_embedding = config.ValueOr("emit_embedding", snap->emit_embedding); snap->max_faces = std::max(1, config.ValueOr("max_faces", snap->max_faces)); snap->person_class_id = config.ValueOr("person_class_id", snap->person_class_id); - snap->track_state_key = config.ValueOr("track_state_key", snap->track_state_key); snap->track_state_max_age_ms = std::max(0, static_cast(config.ValueOr("track_state_max_age_ms", static_cast(snap->track_state_max_age_ms)))); @@ -740,7 +739,6 @@ static bool BuildFaceRecogConfigSnapshot(const SimpleJson& config, snap->gallery_backend = g->ValueOr("backend", snap->gallery_backend); snap->gallery_path = g->ValueOr("path", snap->gallery_path); snap->gallery_load_on_start = g->ValueOr("load_on_start", snap->gallery_load_on_start); - snap->gallery_expected_dim = std::max(0, g->ValueOr("expected_dim", snap->gallery_expected_dim)); snap->gallery_dtype = g->ValueOr("dtype", snap->gallery_dtype); snap->gallery_reload_seq = g->ValueOr("reload_seq", snap->gallery_reload_seq); } @@ -778,6 +776,8 @@ public: } std::shared_ptr snap; BuildFaceRecogConfigSnapshot(config, nullptr, snap); + std::const_pointer_cast(snap)->track_state_key = + DefaultTrackedTargetsKey(ctx.graph_name); { std::lock_guard lock(mu_); cfg_ = std::move(snap); @@ -844,6 +844,7 @@ public: " thr_accept=" + std::to_string(thr_accept) + " thr_margin=" + std::to_string(thr_margin) + " infer_interval_ms=" + std::to_string(infer_interval_ms_) + + " shared_target_key=" + (cfg ? cfg->track_state_key : std::string{}) + " debug=" + std::string(debug_enabled ? "true" : "false") + " debug_log_matches=" + std::string(debug_log_matches ? "true" : "false") + " debug_min_log_interval_ms=" + std::to_string(debug_interval_ms)); @@ -871,9 +872,9 @@ public: bool reload = false; if (base && snap) { + std::const_pointer_cast(snap)->track_state_key = base->track_state_key; reload = (snap->gallery_backend != base->gallery_backend || snap->gallery_path != base->gallery_path || - snap->gallery_expected_dim != base->gallery_expected_dim || snap->gallery_dtype != base->gallery_dtype || snap->gallery_reload_seq != base->gallery_reload_seq); } diff --git a/plugins/gate/gate_node.cpp b/plugins/gate/gate_node.cpp index 611aef0..75f23d0 100644 --- a/plugins/gate/gate_node.cpp +++ b/plugins/gate/gate_node.cpp @@ -48,7 +48,6 @@ static bool BuildConfigSnapshot(const SimpleJson& config, std::shared_ptr(); snap->id = config.ValueOr("id", "gate"); - snap->state_key = config.ValueOr("state_key", ""); snap->require_confirmed = config.ValueOr("require_confirmed", true); snap->min_count = config.ValueOr("min_count", 1); snap->max_age_ms = static_cast(config.ValueOr("max_age_ms", 800)); @@ -89,6 +88,7 @@ public: } id_ = snap->id; ctx_ = ctx; + std::const_pointer_cast(snap)->state_key = DefaultTrackedTargetsKey(ctx.graph_name); { std::lock_guard lk(mu_); cfg_ = std::move(snap); @@ -111,6 +111,7 @@ public: return false; } std::lock_guard lk(mu_); + if (cfg_) std::const_pointer_cast(snap)->state_key = cfg_->state_key; cfg_ = std::move(snap); return true; } diff --git a/plugins/tracker/tracker_node.cpp b/plugins/tracker/tracker_node.cpp index 0b0b0dc..1abcb19 100644 --- a/plugins/tracker/tracker_node.cpp +++ b/plugins/tracker/tracker_node.cpp @@ -63,7 +63,7 @@ struct ConfigSnapshot { std::string mode; // off | bytetrack_lite bool per_class = true; - // If set, write current tracked targets into SharedState under this key. + // Internal graph-scoped key used to publish current tracked targets. std::string state_key; std::set track_classes; // whitelist @@ -115,7 +115,6 @@ static bool BuildConfigSnapshot(const SimpleJson& config, std::shared_ptrid = config.ValueOr("id", "tracker"); snap->mode = config.ValueOr("mode", "bytetrack_lite"); snap->per_class = config.ValueOr("per_class", true); - snap->state_key = config.ValueOr("state_key", ""); if (const SimpleJson* tc = config.Find("track_classes")) { if (!ParseIntSet(*tc, snap->track_classes, err)) { @@ -269,6 +268,7 @@ public: return false; } id_ = snap->id; + std::const_pointer_cast(snap)->state_key = DefaultTrackedTargetsKey(ctx.graph_name); input_queue_ = ctx.input_queue; if (!input_queue_) { @@ -292,7 +292,12 @@ public: } bool Start() override { - LogInfo("[tracker] started id=" + id_); + std::string state_key; + { + std::lock_guard lk(mu_); + state_key = cfg_ ? cfg_->state_key : std::string{}; + } + LogInfo("[tracker] started id=" + id_ + " shared_target_key=" + state_key); return true; } @@ -315,6 +320,7 @@ public: { std::lock_guard lk(mu_); if (cfg_) { + std::const_pointer_cast(snap)->state_key = cfg_->state_key; should_reset = (cfg_->mode != snap->mode) || (cfg_->per_class != snap->per_class) || (cfg_->track_classes != snap->track_classes) || (cfg_->ignore_classes != snap->ignore_classes) || diff --git a/src/graph_manager.cpp b/src/graph_manager.cpp index c309a28..bf944ff 100644 --- a/src/graph_manager.cpp +++ b/src/graph_manager.cpp @@ -501,6 +501,7 @@ bool Graph::Build(const SimpleJson& graph_cfg, PluginLoader& loader, size_t defa entry.role = node_val.ValueOr("role", ""); entry.enabled = node_val.ValueOr("enable", true); entry.metrics = std::make_shared(); + entry.context.graph_name = name_; entry.context.infer_backend = infer_backend_; if (entry.type == "preprocess" || entry.type == "ai_shoe_det" || entry.type == "ai_yolo") { entry.context.image_processor = HwFactory::CreateImageProcessor(entry.config); diff --git a/src/utils/shared_state.cpp b/src/utils/shared_state.cpp index 889845d..bb3d58a 100644 --- a/src/utils/shared_state.cpp +++ b/src/utils/shared_state.cpp @@ -11,6 +11,10 @@ uint64_t NowSteadyUs() { .count()); } +std::string DefaultTrackedTargetsKey(const std::string& graph_name) { + return "graph:" + (graph_name.empty() ? std::string("default") : graph_name) + ":tracked_targets"; +} + SharedState& SharedState::Instance() { static SharedState inst; return inst; diff --git a/tests/test_face_track_association.cpp b/tests/test_face_track_association.cpp index 46a5197..846597d 100644 --- a/tests/test_face_track_association.cpp +++ b/tests/test_face_track_association.cpp @@ -95,6 +95,33 @@ TEST(FaceTrackAssociationTest, FallsBackToSharedTrackedPersonsWhenFrameDetection SharedState::Instance().ClearTargets(state_key); } +TEST(FaceTrackAssociationTest, UsesGraphDefaultSharedTargetKey) { + EXPECT_EQ(DefaultTrackedTargetsKey("cam1_full_pipeline"), + "graph:cam1_full_pipeline:tracked_targets"); + EXPECT_EQ(DefaultTrackedTargetsKey(""), "graph:default:tracked_targets"); +} + +TEST(FaceTrackAssociationTest, FaceRecogConfigUsesInternalDefaultsForTrackStateAndGalleryDim) { + const std::string cfg_text = R"({ + "id": "face_recog", + "track_state_key": "user_should_not_control_this", + "gallery": { + "backend": "sqlite", + "path": "./models/face_gallery.db", + "expected_dim": 999 + } + })"; + SimpleJson cfg; + std::string err; + ASSERT_TRUE(ParseSimpleJson(cfg_text, cfg, err)) << err; + + std::shared_ptr snap; + ASSERT_TRUE(BuildFaceRecogConfigSnapshot(cfg, nullptr, snap)); + + EXPECT_TRUE(snap->track_state_key.empty()); + EXPECT_EQ(snap->gallery_expected_dim, 0); +} + TEST(FaceTrackAssociationTest, DebugLineIncludesPersonTrackId) { FaceRecogItem item; item.person_track_id = 88;