修复人脸画框,xin1
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 18:46:53 +08:00
parent 7f30d70d5a
commit 20f9a4ff2c
6 changed files with 174 additions and 6 deletions

View File

@ -33,6 +33,11 @@ struct InferInput {
int width = 0;
int height = 0;
bool is_nhwc = true; // true: NHWC, false: NCHW
#if defined(RK3588_ENABLE_RKNN)
// The actual data type of `data` passed to RKNN. Default preserves existing behavior.
rknn_tensor_type type = RKNN_TENSOR_UINT8;
#endif
};
struct InferOutput {

View File

@ -4,12 +4,14 @@
#pragma once
#include <cerrno>
#include <cctype>
#include <map>
#include <optional>
#include <cstdlib>
#include <string>
#include <string_view>
#include <type_traits>
#include <variant>
#include <vector>
@ -119,6 +121,8 @@ public:
return child->AsString(def);
} else if constexpr (std::is_same_v<T, double>) {
return child->AsNumber(def);
} else if constexpr (std::is_same_v<T, float>) {
return static_cast<float>(child->AsNumber(static_cast<double>(def)));
} else if constexpr (std::is_same_v<T, int>) {
return child->AsInt(def);
} else if constexpr (std::is_same_v<T, bool>) {

View File

@ -327,6 +327,29 @@ public:
input_format_ = fmt;
for (auto& c : input_format_) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
input_dtype_ = config.ValueOr<std::string>("input_dtype", input_dtype_);
for (auto& c : input_dtype_) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
// Optional normalization when input_dtype is float.
// - scale/bias: x = x*scale + bias
// - mean/std: x = (x - mean[c]) / std[c]
if (const SimpleJson* norm = config.Find("normalize"); norm && norm->IsObject()) {
if (const SimpleJson* mean = norm->Find("mean"); mean && mean->IsArray() && mean->AsArray().size() >= 3) {
for (int i = 0; i < 3; ++i) {
norm_mean_[static_cast<size_t>(i)] = static_cast<float>(mean->AsArray()[static_cast<size_t>(i)].AsNumber(norm_mean_[static_cast<size_t>(i)]));
}
norm_use_mean_std_ = true;
}
if (const SimpleJson* st = norm->Find("std"); st && st->IsArray() && st->AsArray().size() >= 3) {
for (int i = 0; i < 3; ++i) {
norm_std_[static_cast<size_t>(i)] = static_cast<float>(st->AsArray()[static_cast<size_t>(i)].AsNumber(norm_std_[static_cast<size_t>(i)]));
}
norm_use_mean_std_ = true;
}
norm_scale_ = norm->ValueOr<float>("scale", norm_scale_);
norm_bias_ = norm->ValueOr<float>("bias", norm_bias_);
}
// RetinaFace priors defaults for 320 input (MobileNet0.25).
steps_ = {8, 16, 32};
min_sizes_ = {{16, 32}, {64, 128}, {256, 512}};
@ -407,6 +430,29 @@ public:
max_faces_ = std::max(1, new_config.ValueOr<int>("max_faces", max_faces_));
output_landmarks_ = new_config.ValueOr<bool>("output_landmarks", output_landmarks_);
std::string dtype = new_config.ValueOr<std::string>("input_dtype", input_dtype_);
for (auto& c : dtype) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
input_dtype_ = std::move(dtype);
if (const SimpleJson* norm = new_config.Find("normalize"); norm && norm->IsObject()) {
bool use_ms = false;
if (const SimpleJson* mean = norm->Find("mean"); mean && mean->IsArray() && mean->AsArray().size() >= 3) {
for (int i = 0; i < 3; ++i) {
norm_mean_[static_cast<size_t>(i)] = static_cast<float>(mean->AsArray()[static_cast<size_t>(i)].AsNumber(norm_mean_[static_cast<size_t>(i)]));
}
use_ms = true;
}
if (const SimpleJson* st = norm->Find("std"); st && st->IsArray() && st->AsArray().size() >= 3) {
for (int i = 0; i < 3; ++i) {
norm_std_[static_cast<size_t>(i)] = static_cast<float>(st->AsArray()[static_cast<size_t>(i)].AsNumber(norm_std_[static_cast<size_t>(i)]));
}
use_ms = true;
}
norm_use_mean_std_ = use_ms;
norm_scale_ = norm->ValueOr<float>("scale", norm_scale_);
norm_bias_ = norm->ValueOr<float>("bias", norm_bias_);
}
if (const SimpleJson* pri = new_config.Find("prior"); pri && pri->IsObject()) {
if (const SimpleJson* steps = pri->Find("steps"); steps && steps->IsArray()) {
std::vector<int> new_steps;
@ -497,12 +543,37 @@ private:
}
InferInput input;
input.data = input_ptr;
input.size = in_size;
input.width = in_w;
input.height = in_h;
input.is_nhwc = true;
// Default: keep existing UINT8 behavior.
if (input_dtype_ == "float" || input_dtype_ == "f32" || input_dtype_ == "float32") {
float_input_buf_.resize(static_cast<size_t>(in_w) * static_cast<size_t>(in_h) * 3);
const size_t pix = static_cast<size_t>(in_w) * static_cast<size_t>(in_h);
const uint8_t* p = reinterpret_cast<const uint8_t*>(input_ptr);
for (size_t i = 0; i < pix; ++i) {
for (int c = 0; c < 3; ++c) {
float x = static_cast<float>(p[i * 3 + static_cast<size_t>(c)]);
if (norm_use_mean_std_) {
const float st = std::fabs(norm_std_[static_cast<size_t>(c)]) < 1e-6f ? 1.0f : norm_std_[static_cast<size_t>(c)];
x = (x - norm_mean_[static_cast<size_t>(c)]) / st;
} else {
x = x * norm_scale_ + norm_bias_;
}
float_input_buf_[i * 3 + static_cast<size_t>(c)] = x;
}
}
input.data = float_input_buf_.data();
input.size = float_input_buf_.size() * sizeof(float);
input.type = RKNN_TENSOR_FLOAT32;
} else {
input.data = input_ptr;
input.size = in_size;
input.type = RKNN_TENSOR_UINT8;
}
auto r = AiScheduler::Instance().InferBorrowed(model_handle_, input);
if (!r.success) {
std::cerr << "[ai_face_det] inference failed: " << r.error << "\n";
@ -699,6 +770,14 @@ private:
std::string input_format_ = "rgb";
// Model input dtype: "uint8" (default) or "float32".
std::string input_dtype_ = "uint8";
float norm_scale_ = 1.0f;
float norm_bias_ = 0.0f;
bool norm_use_mean_std_ = false;
std::array<float, 3> norm_mean_{{0.0f, 0.0f, 0.0f}};
std::array<float, 3> norm_std_{{1.0f, 1.0f, 1.0f}};
std::vector<int> steps_;
std::vector<std::vector<int>> min_sizes_;
@ -706,6 +785,7 @@ private:
std::vector<std::shared_ptr<SpscQueue<FramePtr>>> output_queues_;
std::vector<uint8_t> input_buf_;
std::vector<float> float_input_buf_;
ModelHandle model_handle_ = kInvalidModelHandle;
int model_w_ = 320;

View File

@ -569,6 +569,26 @@ public:
model_input_format_ = fmt;
for (auto& c : model_input_format_) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
input_dtype_ = config.ValueOr<std::string>("input_dtype", input_dtype_);
for (auto& c : input_dtype_) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
if (const SimpleJson* norm = config.Find("normalize"); norm && norm->IsObject()) {
if (const SimpleJson* mean = norm->Find("mean"); mean && mean->IsArray() && mean->AsArray().size() >= 3) {
for (int i = 0; i < 3; ++i) {
norm_mean_[static_cast<size_t>(i)] = static_cast<float>(mean->AsArray()[static_cast<size_t>(i)].AsNumber(norm_mean_[static_cast<size_t>(i)]));
}
norm_use_mean_std_ = true;
}
if (const SimpleJson* st = norm->Find("std"); st && st->IsArray() && st->AsArray().size() >= 3) {
for (int i = 0; i < 3; ++i) {
norm_std_[static_cast<size_t>(i)] = static_cast<float>(st->AsArray()[static_cast<size_t>(i)].AsNumber(norm_std_[static_cast<size_t>(i)]));
}
norm_use_mean_std_ = true;
}
norm_scale_ = norm->ValueOr<float>("scale", norm_scale_);
norm_bias_ = norm->ValueOr<float>("bias", norm_bias_);
}
// Gallery
if (const SimpleJson* g = config.Find("gallery"); g && g->IsObject()) {
gallery_backend_ = g->ValueOr<std::string>("backend", gallery_backend_);
@ -643,6 +663,29 @@ public:
thr_margin_ = th->ValueOr<float>("margin", thr_margin_);
}
std::string dtype = new_config.ValueOr<std::string>("input_dtype", input_dtype_);
for (auto& c : dtype) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
input_dtype_ = std::move(dtype);
if (const SimpleJson* norm = new_config.Find("normalize"); norm && norm->IsObject()) {
bool use_ms = false;
if (const SimpleJson* mean = norm->Find("mean"); mean && mean->IsArray() && mean->AsArray().size() >= 3) {
for (int i = 0; i < 3; ++i) {
norm_mean_[static_cast<size_t>(i)] = static_cast<float>(mean->AsArray()[static_cast<size_t>(i)].AsNumber(norm_mean_[static_cast<size_t>(i)]));
}
use_ms = true;
}
if (const SimpleJson* st = norm->Find("std"); st && st->IsArray() && st->AsArray().size() >= 3) {
for (int i = 0; i < 3; ++i) {
norm_std_[static_cast<size_t>(i)] = static_cast<float>(st->AsArray()[static_cast<size_t>(i)].AsNumber(norm_std_[static_cast<size_t>(i)]));
}
use_ms = true;
}
norm_use_mean_std_ = use_ms;
norm_scale_ = norm->ValueOr<float>("scale", norm_scale_);
norm_bias_ = norm->ValueOr<float>("bias", norm_bias_);
}
// Gallery updates
bool reload = false;
if (const SimpleJson* g = new_config.Find("gallery"); g && g->IsObject()) {
@ -773,12 +816,36 @@ private:
}
InferInput in;
in.data = face_buf_.data();
in.size = face_buf_.size();
in.width = model_w_;
in.height = model_h_;
in.is_nhwc = true;
if (input_dtype_ == "float" || input_dtype_ == "f32" || input_dtype_ == "float32") {
float_input_buf_.resize(static_cast<size_t>(model_w_) * static_cast<size_t>(model_h_) * 3);
const size_t pix = static_cast<size_t>(model_w_) * static_cast<size_t>(model_h_);
const uint8_t* p = face_buf_.data();
for (size_t ii = 0; ii < pix; ++ii) {
for (int c = 0; c < 3; ++c) {
float x = static_cast<float>(p[ii * 3 + static_cast<size_t>(c)]);
if (norm_use_mean_std_) {
const float st = std::fabs(norm_std_[static_cast<size_t>(c)]) < 1e-6f ? 1.0f : norm_std_[static_cast<size_t>(c)];
x = (x - norm_mean_[static_cast<size_t>(c)]) / st;
} else {
x = x * norm_scale_ + norm_bias_;
}
float_input_buf_[ii * 3 + static_cast<size_t>(c)] = x;
}
}
in.data = float_input_buf_.data();
in.size = float_input_buf_.size() * sizeof(float);
in.type = RKNN_TENSOR_FLOAT32;
} else {
in.data = face_buf_.data();
in.size = face_buf_.size();
in.type = RKNN_TENSOR_UINT8;
}
auto r = AiScheduler::Instance().InferBorrowed(model_handle_, in);
if (!r.success || r.outputs.empty()) {
std::cerr << "[ai_face_recog] inference failed: " << (r.error.empty() ? "unknown" : r.error) << "\n";
@ -831,6 +898,13 @@ private:
std::string model_input_format_ = "rgb";
std::string input_dtype_ = "uint8";
float norm_scale_ = 1.0f;
float norm_bias_ = 0.0f;
bool norm_use_mean_std_ = false;
std::array<float, 3> norm_mean_{{0.0f, 0.0f, 0.0f}};
std::array<float, 3> norm_std_{{1.0f, 1.0f, 1.0f}};
std::string gallery_backend_ = "file";
std::string gallery_path_; // base path without extension: <path>.json / <path>.bin
bool gallery_load_on_start_ = true;
@ -842,6 +916,7 @@ private:
std::vector<std::shared_ptr<SpscQueue<FramePtr>>> output_queues_;
std::vector<uint8_t> face_buf_;
std::vector<float> float_input_buf_;
ModelHandle model_handle_ = kInvalidModelHandle;
int model_w_ = 112;

View File

@ -574,6 +574,8 @@ private:
out_frame->pts = frame->pts;
out_frame->frame_id = frame->frame_id;
out_frame->det = frame->det;
out_frame->face_det = frame->face_det;
out_frame->face_recog = frame->face_recog;
out_frame->user_meta = frame->user_meta;
SetupPlanes(*out_frame, out_fmt);
@ -658,6 +660,8 @@ private:
out_frame->pts = frame->pts;
out_frame->frame_id = frame->frame_id;
out_frame->det = frame->det;
out_frame->face_det = frame->face_det;
out_frame->face_recog = frame->face_recog;
out_frame->user_meta = frame->user_meta;
SetupPlanes(*out_frame, out_fmt);

View File

@ -258,7 +258,7 @@ InferResult AiScheduler::Infer(ModelHandle handle, const InferInput& input) {
rknn_input inputs[1];
memset(inputs, 0, sizeof(inputs));
inputs[0].index = 0;
inputs[0].type = RKNN_TENSOR_UINT8;
inputs[0].type = input.type;
inputs[0].size = input.size;
inputs[0].fmt = input.is_nhwc ? RKNN_TENSOR_NHWC : RKNN_TENSOR_NCHW;
inputs[0].buf = const_cast<void*>(input.data);
@ -358,7 +358,7 @@ AiScheduler::BorrowedInferResult AiScheduler::InferBorrowed(ModelHandle handle,
rknn_input inputs[1];
memset(inputs, 0, sizeof(inputs));
inputs[0].index = 0;
inputs[0].type = RKNN_TENSOR_UINT8;
inputs[0].type = input.type;
inputs[0].size = input.size;
inputs[0].fmt = input.is_nhwc ? RKNN_TENSOR_NHWC : RKNN_TENSOR_NCHW;
inputs[0].buf = const_cast<void*>(input.data);