From 63f448c10867cc5c2a20e8c9bb79ecd97973dd8a Mon Sep 17 00:00:00 2001 From: sladro Date: Wed, 7 Jan 2026 17:51:42 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=BA=E8=84=B8=E7=94=BB?= =?UTF-8?q?=E6=A1=863?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- configs/test_cam1_face_det_rtsp_server.json | 5 +- plugins/ai_face_det/ai_face_det_node.cpp | 53 +++++++++++++++++++-- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/configs/test_cam1_face_det_rtsp_server.json b/configs/test_cam1_face_det_rtsp_server.json index 0f3c23b..c425c00 100644 --- a/configs/test_cam1_face_det_rtsp_server.json +++ b/configs/test_cam1_face_det_rtsp_server.json @@ -36,11 +36,12 @@ "role": "filter", "enable": true, "model_path": "./models/RetinaFace_mobile320.rknn", - "conf": 0.6, + "conf": 0.2, "nms": 0.4, "max_faces": 10, "output_landmarks": true, - "input_format": "rgb" + "input_format": "bgr", + "face_class_index": -1 }, { "id": "osd_cam1", diff --git a/plugins/ai_face_det/ai_face_det_node.cpp b/plugins/ai_face_det/ai_face_det_node.cpp index 1127e76..9d6b73b 100644 --- a/plugins/ai_face_det/ai_face_det_node.cpp +++ b/plugins/ai_face_det/ai_face_det_node.cpp @@ -382,6 +382,10 @@ public: nms_thresh_ = config.ValueOr("nms", 0.4f); max_faces_ = std::max(1, config.ValueOr("max_faces", 10)); output_landmarks_ = config.ValueOr("output_landmarks", true); + face_class_index_ = config.ValueOr("face_class_index", face_class_index_); + if (face_class_index_ != 0 && face_class_index_ != 1) { + face_class_index_ = -1; // auto + } const std::string fmt = config.ValueOr("input_format", "rgb"); input_format_ = fmt; @@ -672,6 +676,35 @@ private: if (loc.n <= 0 || conf.n != loc.n) return; const int n = loc.n; + // Determine which class index represents "face". + // Most RetinaFace uses [bg, face], i.e., face_idx=1, but some exports swap it. + int face_idx = face_class_index_; + float max_p0 = 0.0f; + float max_p1 = 0.0f; + if (face_idx < 0) { + for (int i = 0; i < n; ++i) { + const float s0 = conf.data[static_cast(i) * 2 + 0]; + const float s1 = conf.data[static_cast(i) * 2 + 1]; + float p1; + if (s0 >= 0.0f && s0 <= 1.0f && s1 >= 0.0f && s1 <= 1.0f && std::fabs((s0 + s1) - 1.0f) < 0.1f) { + p1 = s1; + } else { + p1 = Softmax2(s0, s1); + } + const float p0 = 1.0f - p1; + if (p0 > max_p0) max_p0 = p0; + if (p1 > max_p1) max_p1 = p1; + } + face_idx = (max_p1 >= max_p0) ? 1 : 0; + } + + if (!logged_conf_probe_.exchange(true)) { + LogInfo("[ai_face_det] conf probe: max_p0=" + std::to_string(max_p0) + + " max_p1=" + std::to_string(max_p1) + + " face_idx=" + std::to_string(face_idx) + + (face_class_index_ < 0 ? " (auto)" : " (cfg)")); + } + const std::vector priors = GenerateRetinaFacePriors(in_w, in_h, steps_, min_sizes_); if (!priors.empty() && static_cast(priors.size()) != n) { // Mismatch: can't reliably decode. @@ -692,15 +725,18 @@ private: constexpr float var0 = 0.1f; constexpr float var1 = 0.2f; + float max_face_prob = 0.0f; for (int i = 0; i < n; ++i) { const float s0 = conf.data[static_cast(i) * 2 + 0]; const float s1 = conf.data[static_cast(i) * 2 + 1]; - float score; + float p1; if (s0 >= 0.0f && s0 <= 1.0f && s1 >= 0.0f && s1 <= 1.0f && std::fabs((s0 + s1) - 1.0f) < 0.1f) { - score = s1; + p1 = s1; } else { - score = Softmax2(s0, s1); + p1 = Softmax2(s0, s1); } + const float score = (face_idx == 1) ? p1 : (1.0f - p1); + if (score > max_face_prob) max_face_prob = score; if (score < conf_thresh_) continue; const Prior p = priors.empty() ? Prior{0, 0, 0, 0} : priors[static_cast(i)]; @@ -751,7 +787,13 @@ private: } } - if (boxes.empty()) return; + if (boxes.empty()) { + if (!logged_no_face_detail_.exchange(true)) { + LogInfo("[ai_face_det] no face passed conf=" + std::to_string(conf_thresh_) + + ", max_face_prob=" + std::to_string(max_face_prob)); + } + return; + } std::vector keep; NmsSorted(boxes, scores, nms_thresh_, keep); @@ -782,6 +824,7 @@ private: float nms_thresh_ = 0.4f; int max_faces_ = 10; bool output_landmarks_ = true; + int face_class_index_ = -1; // -1=auto, 0/1=explicit std::string input_format_ = "rgb"; @@ -801,6 +844,8 @@ private: std::atomic logged_io_{false}; std::atomic logged_decode_{false}; std::atomic logged_decode_detail_{false}; + std::atomic logged_conf_probe_{false}; + std::atomic logged_no_face_detail_{false}; }; REGISTER_NODE(AiFaceDetNode, "ai_face_det");