修复人脸画框3
Some checks are pending
CI / host-build (push) Waiting to run
CI / rk3588-cross-build (push) Waiting to run

This commit is contained in:
sladro 2026-01-07 17:51:42 +08:00
parent dd1f419406
commit 63f448c108
2 changed files with 52 additions and 6 deletions

View File

@ -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",

View File

@ -382,6 +382,10 @@ public:
nms_thresh_ = config.ValueOr<float>("nms", 0.4f);
max_faces_ = std::max(1, config.ValueOr<int>("max_faces", 10));
output_landmarks_ = config.ValueOr<bool>("output_landmarks", true);
face_class_index_ = config.ValueOr<int>("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<std::string>("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<size_t>(i) * 2 + 0];
const float s1 = conf.data[static_cast<size_t>(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<Prior> priors = GenerateRetinaFacePriors(in_w, in_h, steps_, min_sizes_);
if (!priors.empty() && static_cast<int>(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<size_t>(i) * 2 + 0];
const float s1 = conf.data[static_cast<size_t>(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<size_t>(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<int> 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<bool> logged_io_{false};
std::atomic<bool> logged_decode_{false};
std::atomic<bool> logged_decode_detail_{false};
std::atomic<bool> logged_conf_probe_{false};
std::atomic<bool> logged_no_face_detail_{false};
};
REGISTER_NODE(AiFaceDetNode, "ai_face_det");