From 62868411179d3d0dbf3f24646058d72c0cddea2d Mon Sep 17 00:00:00 2001 From: Barzan Hayati Date: Fri, 26 Sep 2025 16:06:51 +0000 Subject: [PATCH] Fix face candidate trace --- .devcontainer/devcontainer.json | 3 +- .vscode/settings.json | 4 +- CMakeLists.txt | 3 +- src/face_candid_trace.cpp | 230 +++++++++++++++++++-------- src/face_candid_trace.hpp | 103 +++++++----- src/face_nv_infer_server_manager.cpp | 1 + src/nv_tracker_manager.cpp | 43 +++-- src/nv_tracker_manager.hpp | 2 +- 8 files changed, 257 insertions(+), 132 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 51c3288..f3b0d46 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -46,7 +46,8 @@ }, "extensions": [ "ms-vscode.cpptools", - "ms-vscode.cmake-tools" + "ms-vscode.cmake-tools", + "mhutchie.git-graph" ] } }, diff --git a/.vscode/settings.json b/.vscode/settings.json index cb8a66c..126e882 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -78,6 +78,8 @@ "variant": "cpp", "shared_mutex": "cpp", "cfenv": "cpp", - "stream_ref": "cpp" + "stream_ref": "cpp", + "ranges": "cpp", + "__nullptr": "cpp" } } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 465a6ba..329b407 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,7 +104,8 @@ set(SOURCES src/main.cpp src/camera_manager.cpp src/pipeline_manager.cpp src/st src/rtsp_streaming_manager.cpp # src/metrics_manager.cpp src/config_manager.cpp - src/nv_infer_server_manager.cpp src/nv_tracker_manager.cpp src/face_candid_trace.cpp + src/nv_infer_server_manager.cpp src/nv_tracker_manager.cpp + src/face_candid_trace.cpp src/face_nv_infer_server_manager.cpp src/face_nv_infer_server_manager.cpp src/nv_message_converter.cpp src/nv_message_broker.cpp src/tee_manager.cpp) diff --git a/src/face_candid_trace.cpp b/src/face_candid_trace.cpp index 61af6c8..23184f4 100644 --- a/src/face_candid_trace.cpp +++ b/src/face_candid_trace.cpp @@ -1,87 +1,177 @@ #include "face_candid_trace.hpp" -FaceCandidTrace::FaceCandidTrace() { - maxlen = 150; - // interval_frame_log=20; - face_detection_threshold = 0.5; - face_surface_threshold = 100; - termostat_threshold = 0.00001; +// ================= QueueDict ================= +QueueDict::QueueDict(size_t maxlen) : maxlen(maxlen) {} + +void QueueDict::add(int key, double value) { + auto it = map.find(key); + if (it != map.end()) { + items.erase(it->second); + map.erase(it); + } + items.emplace_back(key, value); + + map[key] = std::prev(items.end()); + + if (items.size() > maxlen) { + auto oldest = items.begin(); + map.erase(oldest->first); + items.pop_front(); + } } -bool FaceCandidTrace::filter(FaceCandidate* face_candidate) { - float w = face_candidate->w; - float h = face_candidate->h; - float face_surface = w * h; - float score_face = face_candidate->face_score; // result["temp_face_score"] - // int frame = face_candidate->frame_number; //result["frame_count"] +double QueueDict::get(int key, double default_val) const { + auto it = map.find(key); + if (it != map.end()) return it->second->second; + return default_val; +} - if (score_face < face_detection_threshold || - face_surface < face_surface_threshold) { - // if self.logger and self._should_log(frame): - // self.logger.info(f"Ignore instance — surface={face_surface}, - // score={score:.2f}, track_id={result['track_id']} @ {frame}", - // extra={"stream_id": stream_id}) - // elif self._should_log(frame): - // print(f"Ignore instance — surface={face_surface}, - // score={score:.2f}, track_id={result['track_id']} @ {frame}") +bool QueueDict::contains(int key) const { return map.find(key) != map.end(); } + +size_t QueueDict::size() const { return items.size(); } + +std::string QueueDict::repr() const { + std::ostringstream oss; + oss << "QueueDict(["; + bool first = true; + for (const auto& kv : items) { + if (!first) oss << ", "; + oss << "(" << kv.first << ", " << kv.second << ")"; + first = false; + } + oss << "])"; + return oss.str(); +} + +// ================= FaceCandidTrace ================= +FaceCandidTrace::FaceCandidTrace(int maxlen, int interval_frame_log, + double face_detection_th, int face_surface_th) + : queue(maxlen), + last_log_frame(-interval_frame_log), + interval_frame_log(interval_frame_log), + fr_face_detection_th(face_detection_th), + fr_face_surface_th(face_surface_th), + th_thermostat(0.00001) {} + +bool FaceCandidTrace::should_log(int current_frame) { + if ((current_frame - last_log_frame) >= interval_frame_log) { + last_log_frame = current_frame; + return true; + } + return false; +} + +bool FaceCandidTrace::filter( + const std::unordered_map& result, + const std::string& stream_id) { + (void)stream_id; + double x1 = result.at("x1"); + double y1 = result.at("y1"); + double x2 = result.at("x2"); + double y2 = result.at("y2"); + double face_surface = (y2 - y1) * (x2 - x1); + double score = result.at("temp_face_score"); + int frame = (int)result.at("frame_count"); + + if (score < fr_face_detection_th || face_surface < fr_face_surface_th) { + if (should_log(frame)) { + // std::cout << "Ignore instance — surface=" << face_surface + // << ", score=" << score + // << ", track_id=" << result.at("track_id") + // << " @ " << frame + // << " [stream=" << stream_id << "]\n"; + } return false; } return true; } -float FaceCandidTrace::metric(FaceCandidate* face_candidate) { - // x1, y1, x2, y2 = result["face_bbox"] - // face_surface = (y2 - y1) * (x2 - x1) - float w = face_candidate->w; - float h = face_candidate->h; - float face_surface = w * h; - face_surface = std::max(face_surface, 30000); - face_surface = face_surface / 30000; - float out = 0.3 * face_candidate->face_score + 0.7 * face_surface; - // # self.termostat_threshold = 0.02 * out - return out; +double FaceCandidTrace::metric( + const std::unordered_map& result) { + double x1 = result.at("x1"); + double y1 = result.at("y1"); + double x2 = result.at("x2"); + double y2 = result.at("y2"); + double face_surface = (y2 - y1) * (x2 - x1); + face_surface = std::max(face_surface, 30000.0); + face_surface /= 30000.0; + return 0.3 * result.at("temp_face_score") + 0.7 * face_surface; } -float FaceCandidTrace::check_existence(int object_id, int source_id) { - for (std::vector::iterator iter = queue.begin(); - iter != queue.end(); iter++) { - if (((*iter).object_id == object_id) && - ((*iter).source_id == source_id)) { - return (*iter).face_score; - } - } - return 0; -} - -bool FaceCandidTrace::add(FaceCandidate* face_candidate) { - if (filter(face_candidate)) { - float current_metric = metric(face_candidate); - float prev = check_existence(face_candidate->object_id, - face_candidate->source_id); - // prev = self.queue.get(track_id, 0) - if ((current_metric - termostat_threshold) > prev) { - queue.emplace_back( - FaceBody{face_candidate->object_id, face_candidate->source_id, - face_candidate->frame_number, current_metric}); - std::cout << "FaceCandidTrace source_id = " - << face_candidate->source_id - << " frame_num = " << face_candidate->frame_number - << " object_id = " << face_candidate->object_id - << " size queue = " << queue.size() << std::endl; - // self.queue.add(track_id, current_metric); +bool FaceCandidTrace::add(int track_id, + const std::unordered_map& result, + const std::string& stream_id) { + if (filter(result, stream_id)) { + double current_metric = metric(result); + double prev = queue.get(track_id, 0.0); + if ((current_metric - th_thermostat) > prev) { + queue.add(track_id, current_metric); return true; } - // int frame_count = face_candidate->frame_number; - // //result["frame_count"] if self.ogger and - // self._should_log(frame_count): - // self.logger.info(f"Ignore (better seen before): - // now={current_metric - self.termostat_threshold:.2f}, - // history={prev:.2f}, track_id={result['track_id']} @ - // {frame_count}", extra={"stream_id": stream_id}) - // elif self._should_log(frame_count): - // print(f"Ignore (better seen before): now={current_metric - - // self.termostat_threshold:.2f}, history={prev:.2f}, - // track_id={result['track_id']} @ {frame_count}") + int frame_count = (int)result.at("frame_count"); + if (should_log(frame_count)) { + // std::cout << "Ignore (better seen before): now=" + // << (current_metric - th_thermostat) + // << ", history=" << prev + // << ", track_id=" << result.at("track_id") + // << " @ " << frame_count + // << " [stream=" << stream_id << "]\n"; + } } return false; +} + +double FaceCandidTrace::get(int track_id, double default_val) const { + return queue.get(track_id, default_val); +} + +bool FaceCandidTrace::contains(int track_id) const { + return queue.contains(track_id); +} + +size_t FaceCandidTrace::size() const { return queue.size(); } + +std::string FaceCandidTrace::str() const { + std::ostringstream oss; + oss << ""; + return oss.str(); +} + +// In FaceCandidTrace.cpp +std::string FaceCandidTrace::dump() const { + return queue.repr(); // QueueDict already has repr() +} + +// ================= FaceCandidTraceManager ================= +bool FaceCandidTraceManager::add( + const std::string& stream_id, int track_id, + const std::unordered_map& result) { + return traces[stream_id].add(track_id, result, stream_id); +} + +double FaceCandidTraceManager::get(const std::string& stream_id, int track_id, + double default_val) { + return traces[stream_id].get(track_id, default_val); +} + +bool FaceCandidTraceManager::contains(const std::string& stream_id, + int track_id) { + return traces[stream_id].contains(track_id); +} + +size_t FaceCandidTraceManager::size() const { + size_t total = 0; + for (const auto& kv : traces) { + total += kv.second.size(); + } + return total; +} + +std::string FaceCandidTraceManager::str() const { + std::ostringstream oss; + for (const auto& kv : traces) { + oss << kv.first << " → " << kv.second.str() << "\n"; + oss << " " << kv.second.dump() << "\n"; // show all track_id values + } + return oss.str(); } \ No newline at end of file diff --git a/src/face_candid_trace.hpp b/src/face_candid_trace.hpp index 9795d3c..0bcc1b0 100644 --- a/src/face_candid_trace.hpp +++ b/src/face_candid_trace.hpp @@ -1,39 +1,70 @@ -#include // Required for std::max -#include +// #pragma once + +#include #include +#include +#include +#include +#include -#include "gstnvdsmeta.h" -#include "nvdsmeta.h" -#include "nvdsmeta_schema.h" - -class FaceCandidTrace { - private: - int maxlen; - // int interval_frame_log; - float face_detection_threshold; - int face_surface_threshold; - float termostat_threshold; - struct FaceBody { - int object_id = 0; - int source_id = 0; - int num_frames = 0; - float face_score = -1; - }; - std::vector queue; - +// ================= QueueDict ================= +class QueueDict { public: - struct FaceCandidate { - float w = 0; - float h = 0; - float face_score; - gint frame_number; - int object_id; - int source_id; - }; - FaceCandidTrace(); - ~FaceCandidTrace(); - bool filter(FaceCandidate *); - float metric(FaceCandidate *face_candidate); - bool add(FaceCandidate *); - float check_existence(int, int); -}; \ No newline at end of file + explicit QueueDict(size_t maxlen); + + void add(int key, double value); + double get(int key, double default_val = 0.0) const; + bool contains(int key) const; + size_t size() const; + std::string repr() const; + + private: + size_t maxlen; + std::list> items; + std::unordered_map>::iterator> map; +}; + +// ================= FaceCandidTrace ================= +class FaceCandidTrace { + public: + explicit FaceCandidTrace(int maxlen = 150, int interval_frame_log = 20, + double face_detection_th = 0.5, + int face_surface_th = 100); + + bool add(int track_id, + const std::unordered_map& result, + const std::string& stream_id); + double get(int track_id, double default_val = 0.0) const; + bool contains(int track_id) const; + size_t size() const; + std::string str() const; + std::string dump() const; + + private: + QueueDict queue; + int last_log_frame; + int interval_frame_log; + double fr_face_detection_th; + int fr_face_surface_th; + double th_thermostat; + + bool should_log(int current_frame); + bool filter(const std::unordered_map& result, + const std::string& stream_id); + double metric(const std::unordered_map& result); +}; + +// ================= FaceCandidTraceManager ================= +class FaceCandidTraceManager { + public: + bool add(const std::string& stream_id, int track_id, + const std::unordered_map& result); + double get(const std::string& stream_id, int track_id, + double default_val = 0.0); + bool contains(const std::string& stream_id, int track_id); + size_t size() const; + std::string str() const; + + private: + std::unordered_map traces; +}; diff --git a/src/face_nv_infer_server_manager.cpp b/src/face_nv_infer_server_manager.cpp index 3bc7c31..323e8b3 100644 --- a/src/face_nv_infer_server_manager.cpp +++ b/src/face_nv_infer_server_manager.cpp @@ -10,6 +10,7 @@ #define MAX_DISPLAY_LEN 64 #define PGIE_CLASS_ID_PERSON 0 +#define FACE_CLASS_ID 1 #define PGIE_DETECTED_CLASS_NUM 1 #define SGIE_DETECTED_CLASS_NUM 1 #define BODY_COMPONENT_ID 1 diff --git a/src/nv_tracker_manager.cpp b/src/nv_tracker_manager.cpp index 5393d89..acda8ca 100644 --- a/src/nv_tracker_manager.cpp +++ b/src/nv_tracker_manager.cpp @@ -8,6 +8,7 @@ #define MAX_DISPLAY_LEN 64 #define PGIE_CLASS_ID_PERSON 0 #define FACE_CLASS_ID 1 +#define IGNORE_CLASS_ID 41 #define THRESHOLD_LANDMARKS 0.1 #define FACE_DETECTED_CLASS_NUM 1 #define BODY_COMPONENT_ID 1 @@ -18,8 +19,8 @@ unsigned int NvTrackerManager::PGIE_NET_HEIGHT = 1; unsigned int NvTrackerManager::MUXER_OUTPUT_WIDTH = 1; unsigned int NvTrackerManager::MUXER_OUTPUT_HEIGHT = 1; std::vector NvTrackerManager::body_face_list; -FaceCandidTrace *NvTrackerManager::face_candidate_trace = - new FaceCandidTrace(); // nullptr; // Definition +FaceCandidTraceManager *NvTrackerManager::face_candidate_trace_manager = + new FaceCandidTraceManager(); gint NvTrackerManager::frame_number = 0; const gchar face_class_str[FACE_DETECTED_CLASS_NUM][32] = { @@ -332,33 +333,31 @@ GstPadProbeReturn NvTrackerManager::tracker_src_pad_buffer_probe( face_obj->rect_params.border_color = NvOSD_ColorParams{0.0, 0.0, 1.0, 1.0}; // Blue box - // FaceCandidate *face_candidate = new FaceCandidate(); - FaceCandidTrace::FaceCandidate *face_candidate = - new FaceCandidTrace::FaceCandidate(); - // NvTrackerManager::FaceCandidate* face_candidate = new - // NvTrackerManager::FaceCandidate(); - - // manager->face_candidate - face_candidate->frame_number = frame_meta->frame_num; - face_candidate->h = face_rect_params->height; - face_candidate->w = face_rect_params->width; - - face_candidate->face_score = - confidence; // manager->get_face_score(user_meta_data); - // // manager->face_score; face_obj->confidence = - face_candidate->face_score; // 1.0; - face_candidate->object_id = obj_meta->object_id; + confidence; // face_candidate->face_score; // 1.0; face_obj->object_id = obj_meta->object_id; - face_candidate->source_id = frame_meta->source_id; - bool add_status = - face_candidate_trace->add(face_candidate); + // Example "result" dictionary (similar to Python dict) + std::unordered_map result = { + {"x1", face_rect_params->left}, + {"y1", face_rect_params->top}, + {"x2", + face_rect_params->left + face_rect_params->width}, + {"y2", + face_rect_params->top + face_rect_params->height}, + {"temp_face_score", confidence}, + {"frame_count", frame_meta->frame_num}, + {"track_id", obj_meta->object_id}}; + std::string stream_id = + "stream_" + std::to_string(frame_meta->source_id); + + bool add_status = face_candidate_trace_manager->add( + stream_id, obj_meta->object_id, result); if (add_status) { face_obj->class_id = FACE_CLASS_ID; } else { - face_obj->class_id = 41; + face_obj->class_id = IGNORE_CLASS_ID; } NvOSD_TextParams &text_params = face_obj->text_params; diff --git a/src/nv_tracker_manager.hpp b/src/nv_tracker_manager.hpp index 9dd7a16..f99cd82 100644 --- a/src/nv_tracker_manager.hpp +++ b/src/nv_tracker_manager.hpp @@ -32,8 +32,8 @@ class NvTrackerManager { }; static std::vector body_face_list; - static FaceCandidTrace *face_candidate_trace; float face_score; + static FaceCandidTraceManager *face_candidate_trace_manager; public: static unsigned int PGIE_NET_WIDTH;