Add face recognition debug switch
This commit is contained in:
parent
7e8a4c870e
commit
ba4bf5339d
@ -103,6 +103,11 @@
|
||||
"load_on_start": true,
|
||||
"expected_dim": 512,
|
||||
"dtype": "auto"
|
||||
},
|
||||
"debug": {
|
||||
"enabled": false,
|
||||
"log_matches": false,
|
||||
"min_log_interval_ms": 1000
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
57
include/face/face_recog_debug.h
Normal file
57
include/face/face_recog_debug.h
Normal file
@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "face/face_result.h"
|
||||
#include "utils/simple_json.h"
|
||||
|
||||
namespace rk3588 {
|
||||
|
||||
struct FaceRecogDebugConfig {
|
||||
bool enabled = false;
|
||||
bool log_matches = false;
|
||||
int min_log_interval_ms = 2000;
|
||||
};
|
||||
|
||||
inline FaceRecogDebugConfig ParseFaceRecogDebugConfig(
|
||||
const SimpleJson& cfg, const FaceRecogDebugConfig& base = {}) {
|
||||
FaceRecogDebugConfig out = base;
|
||||
const SimpleJson* debug = cfg.Find("debug");
|
||||
if (!debug || !debug->IsObject()) return out;
|
||||
|
||||
out.enabled = debug->ValueOr<bool>("enabled", out.enabled);
|
||||
out.log_matches = debug->ValueOr<bool>("log_matches", out.log_matches);
|
||||
out.min_log_interval_ms = std::max(0, debug->ValueOr<int>("min_log_interval_ms", out.min_log_interval_ms));
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::string BuildFaceRecogDebugSummaryLine(
|
||||
const std::string& node_id, uint64_t frame_id, const FaceRecogItem& item) {
|
||||
const float sim_margin = item.best_sim - item.second_sim;
|
||||
const std::string candidate = item.candidate_name.empty() ? "n/a" : item.candidate_name;
|
||||
const std::string status = item.unknown ? "unknown" : "known";
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "[ai_face_recog] match"
|
||||
<< " id=" << node_id
|
||||
<< " frame=" << frame_id
|
||||
<< " status=" << status
|
||||
<< " candidate=" << candidate
|
||||
<< " candidate_id=" << item.candidate_person_id
|
||||
<< " best_sim=" << std::fixed << std::setprecision(2) << item.best_sim
|
||||
<< " second_sim=" << std::fixed << std::setprecision(2) << item.second_sim
|
||||
<< " sim_margin=" << std::fixed << std::setprecision(2) << sim_margin
|
||||
<< " bbox=(" << static_cast<int>(std::lround(item.bbox.x))
|
||||
<< "," << static_cast<int>(std::lround(item.bbox.y))
|
||||
<< "," << static_cast<int>(std::lround(item.bbox.w))
|
||||
<< "," << static_cast<int>(std::lround(item.bbox.h))
|
||||
<< ")";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
} // namespace rk3588
|
||||
@ -13,6 +13,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "hw/i_infer_backend.h"
|
||||
#include "face/face_recog_debug.h"
|
||||
#include "face/face_result.h"
|
||||
#include "node.h"
|
||||
#include "utils/dma_alloc.h"
|
||||
@ -570,6 +571,8 @@ struct FaceRecogConfigSnapshot {
|
||||
int gallery_expected_dim = 512;
|
||||
std::string gallery_dtype = "auto";
|
||||
int gallery_reload_seq = 0;
|
||||
|
||||
FaceRecogDebugConfig debug;
|
||||
};
|
||||
|
||||
static bool BuildFaceRecogConfigSnapshot(const SimpleJson& config,
|
||||
@ -627,6 +630,7 @@ static bool BuildFaceRecogConfigSnapshot(const SimpleJson& config,
|
||||
snap->gallery_dtype = g->ValueOr<std::string>("dtype", snap->gallery_dtype);
|
||||
snap->gallery_reload_seq = g->ValueOr<int>("reload_seq", snap->gallery_reload_seq);
|
||||
}
|
||||
snap->debug = ParseFaceRecogDebugConfig(config, snap->debug);
|
||||
for (auto& c : snap->gallery_backend) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
for (auto& c : snap->gallery_dtype) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
|
||||
@ -719,10 +723,16 @@ public:
|
||||
const bool align = cfg ? cfg->align : false;
|
||||
const float thr_accept = cfg ? cfg->thr_accept : 0.0f;
|
||||
const float thr_margin = cfg ? cfg->thr_margin : 0.0f;
|
||||
const bool debug_enabled = cfg ? cfg->debug.enabled : false;
|
||||
const bool debug_log_matches = cfg ? cfg->debug.log_matches : false;
|
||||
const int debug_interval_ms = cfg ? cfg->debug.min_log_interval_ms : 0;
|
||||
LogInfo("[ai_face_recog] start id=" + id_ + " align=" + std::string(align ? "true" : "false") +
|
||||
" thr_accept=" + std::to_string(thr_accept) +
|
||||
" thr_margin=" + std::to_string(thr_margin) +
|
||||
" infer_interval_ms=" + std::to_string(infer_interval_ms_));
|
||||
" infer_interval_ms=" + std::to_string(infer_interval_ms_) +
|
||||
" 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));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -960,6 +970,7 @@ private:
|
||||
item.unknown = !accept;
|
||||
|
||||
if (cfg->emit_embedding) item.embedding = emb;
|
||||
MaybeLogDebugMatch(*cfg, frame->frame_id, frame->pts, item);
|
||||
rr.items.push_back(std::move(item));
|
||||
}
|
||||
|
||||
@ -967,6 +978,24 @@ private:
|
||||
|
||||
frame->face_recog = std::make_shared<FaceRecogResult>(std::move(rr));
|
||||
}
|
||||
|
||||
void MaybeLogDebugMatch(const FaceRecogConfigSnapshot& cfg, uint64_t frame_id, uint64_t pts_us,
|
||||
const FaceRecogItem& item) {
|
||||
if (!cfg.debug.enabled || !cfg.debug.log_matches) return;
|
||||
|
||||
if (cfg.debug.min_log_interval_ms > 0) {
|
||||
const int64_t now_key_ms = pts_us > 0
|
||||
? static_cast<int64_t>(pts_us / 1000ULL)
|
||||
: static_cast<int64_t>(frame_id);
|
||||
if (now_key_ms > 0 &&
|
||||
(now_key_ms - last_debug_log_pts_ms_) < cfg.debug.min_log_interval_ms) {
|
||||
return;
|
||||
}
|
||||
last_debug_log_pts_ms_ = now_key_ms;
|
||||
}
|
||||
|
||||
LogInfo(BuildFaceRecogDebugSummaryLine(id_, frame_id, item));
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string id_;
|
||||
@ -989,6 +1018,7 @@ private:
|
||||
int64_t infer_interval_ms_ = 0;
|
||||
int64_t infer_phase_ms_ = 0;
|
||||
int64_t last_infer_pts_ms_ = 0;
|
||||
int64_t last_debug_log_pts_ms_ = std::numeric_limits<int64_t>::min();
|
||||
};
|
||||
|
||||
REGISTER_NODE(AiFaceRecogNode, "ai_face_recog");
|
||||
|
||||
@ -47,6 +47,7 @@ add_executable(rk3588_gtests
|
||||
test_event_fusion.cpp
|
||||
test_alarm_behavior_events.cpp
|
||||
test_log_action.cpp
|
||||
test_face_recog_debug.cpp
|
||||
test_infer_backend.cpp
|
||||
test_image_processor.cpp
|
||||
test_codec_backend.cpp
|
||||
|
||||
57
tests/test_face_recog_debug.cpp
Normal file
57
tests/test_face_recog_debug.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "face/face_recog_debug.h"
|
||||
#include "utils/simple_json.h"
|
||||
|
||||
namespace rk3588 {
|
||||
namespace {
|
||||
|
||||
TEST(FaceRecogDebugTest, ParsesDebugConfigWithDefaultsAndOverrides) {
|
||||
FaceRecogDebugConfig defaults;
|
||||
EXPECT_FALSE(defaults.enabled);
|
||||
EXPECT_FALSE(defaults.log_matches);
|
||||
EXPECT_EQ(defaults.min_log_interval_ms, 2000);
|
||||
|
||||
SimpleJson::Object debug_obj;
|
||||
debug_obj.emplace("enabled", SimpleJson(true));
|
||||
debug_obj.emplace("log_matches", SimpleJson(true));
|
||||
debug_obj.emplace("min_log_interval_ms", SimpleJson(350.0));
|
||||
|
||||
SimpleJson::Object root_obj;
|
||||
root_obj.emplace("debug", SimpleJson(std::move(debug_obj)));
|
||||
SimpleJson cfg(std::move(root_obj));
|
||||
|
||||
FaceRecogDebugConfig parsed = ParseFaceRecogDebugConfig(cfg, defaults);
|
||||
EXPECT_TRUE(parsed.enabled);
|
||||
EXPECT_TRUE(parsed.log_matches);
|
||||
EXPECT_EQ(parsed.min_log_interval_ms, 350);
|
||||
}
|
||||
|
||||
TEST(FaceRecogDebugTest, BuildsSummaryLineForUnknownCandidate) {
|
||||
FaceRecogItem item;
|
||||
item.bbox = Rect{10.0f, 20.0f, 30.0f, 40.0f};
|
||||
item.candidate_person_id = 7;
|
||||
item.candidate_name = "alice";
|
||||
item.best_name = "unknown";
|
||||
item.best_sim = 0.44f;
|
||||
item.second_sim = 0.41f;
|
||||
item.unknown = true;
|
||||
|
||||
const std::string line = BuildFaceRecogDebugSummaryLine("face_recog", 42, item);
|
||||
|
||||
EXPECT_NE(line.find("[ai_face_recog] match"), std::string::npos);
|
||||
EXPECT_NE(line.find("id=face_recog"), std::string::npos);
|
||||
EXPECT_NE(line.find("frame=42"), std::string::npos);
|
||||
EXPECT_NE(line.find("status=unknown"), std::string::npos);
|
||||
EXPECT_NE(line.find("candidate=alice"), std::string::npos);
|
||||
EXPECT_NE(line.find("candidate_id=7"), std::string::npos);
|
||||
EXPECT_NE(line.find("best_sim=0.44"), std::string::npos);
|
||||
EXPECT_NE(line.find("second_sim=0.41"), std::string::npos);
|
||||
EXPECT_NE(line.find("sim_margin=0.03"), std::string::npos);
|
||||
EXPECT_NE(line.find("bbox=(10,20,30,40)"), std::string::npos);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace rk3588
|
||||
Loading…
Reference in New Issue
Block a user