修复人脸画框4
This commit is contained in:
parent
63f448c108
commit
c1d4162d08
@ -24,8 +24,8 @@
|
||||
"type": "preprocess",
|
||||
"role": "filter",
|
||||
"enable": true,
|
||||
"dst_w": 640,
|
||||
"dst_h": 640,
|
||||
"dst_w": 1280,
|
||||
"dst_h": 720,
|
||||
"dst_format": "rgb",
|
||||
"keep_ratio": false,
|
||||
"use_rga": true
|
||||
@ -36,12 +36,13 @@
|
||||
"role": "filter",
|
||||
"enable": true,
|
||||
"model_path": "./models/RetinaFace_mobile320.rknn",
|
||||
"conf": 0.2,
|
||||
"conf": 0.3,
|
||||
"nms": 0.4,
|
||||
"max_faces": 10,
|
||||
"output_landmarks": true,
|
||||
"input_format": "bgr",
|
||||
"face_class_index": -1
|
||||
"face_class_index": 1,
|
||||
"letterbox": true
|
||||
},
|
||||
{
|
||||
"id": "osd_cam1",
|
||||
|
||||
@ -368,6 +368,42 @@ void ResizeRgbBilinear(const uint8_t* src, int src_w, int src_h, int src_stride,
|
||||
}
|
||||
}
|
||||
|
||||
struct LetterboxInfo {
|
||||
float scale = 1.0f;
|
||||
int pad_x = 0;
|
||||
int pad_y = 0;
|
||||
};
|
||||
|
||||
void LetterboxRgb(const uint8_t* src, int src_w, int src_h, int src_stride,
|
||||
uint8_t* dst, int dst_w, int dst_h, bool swap_rb,
|
||||
uint8_t pad_value, LetterboxInfo& info) {
|
||||
info = {};
|
||||
if (!src || !dst || src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0 || src_stride <= 0) return;
|
||||
|
||||
const float s = std::min(static_cast<float>(dst_w) / static_cast<float>(src_w),
|
||||
static_cast<float>(dst_h) / static_cast<float>(src_h));
|
||||
const int rw = std::max(1, static_cast<int>(std::round(static_cast<float>(src_w) * s)));
|
||||
const int rh = std::max(1, static_cast<int>(std::round(static_cast<float>(src_h) * s)));
|
||||
const int px = (dst_w - rw) / 2;
|
||||
const int py = (dst_h - rh) / 2;
|
||||
|
||||
info.scale = s;
|
||||
info.pad_x = px;
|
||||
info.pad_y = py;
|
||||
|
||||
// fill background
|
||||
std::fill(dst, dst + static_cast<size_t>(dst_w) * static_cast<size_t>(dst_h) * 3, pad_value);
|
||||
|
||||
std::vector<uint8_t> tmp(static_cast<size_t>(rw) * static_cast<size_t>(rh) * 3);
|
||||
ResizeRgbBilinear(src, src_w, src_h, src_stride, tmp.data(), rw, rh, swap_rb);
|
||||
|
||||
for (int y = 0; y < rh; ++y) {
|
||||
uint8_t* drow = dst + (static_cast<size_t>(py + y) * static_cast<size_t>(dst_w) + static_cast<size_t>(px)) * 3;
|
||||
const uint8_t* srow = tmp.data() + static_cast<size_t>(y) * static_cast<size_t>(rw) * 3;
|
||||
memcpy(drow, srow, static_cast<size_t>(rw) * 3);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class AiFaceDetNode : public INode {
|
||||
@ -382,6 +418,7 @@ 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);
|
||||
letterbox_ = config.ValueOr<bool>("letterbox", letterbox_);
|
||||
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
|
||||
@ -541,6 +578,8 @@ private:
|
||||
|
||||
const uint8_t* input_ptr = nullptr;
|
||||
|
||||
LetterboxInfo lb;
|
||||
if (!letterbox_) {
|
||||
// Fast path: already packed, correct size, no channel swap.
|
||||
if (!need_swap && src_w == in_w && src_h == in_h &&
|
||||
static_cast<size_t>(src_stride) == src_row && frame->data_size >= src_row * static_cast<size_t>(src_h)) {
|
||||
@ -559,6 +598,12 @@ private:
|
||||
}
|
||||
input_ptr = input_buf_.data();
|
||||
}
|
||||
} else {
|
||||
input_buf_.resize(in_size);
|
||||
LetterboxRgb(src, src_w, src_h, src_stride, input_buf_.data(), in_w, in_h,
|
||||
need_swap, 0, lb);
|
||||
input_ptr = input_buf_.data();
|
||||
}
|
||||
|
||||
InferInput input;
|
||||
input.data = input_ptr;
|
||||
@ -609,7 +654,7 @@ private:
|
||||
det.img_h = src_h;
|
||||
det.model_name = "retinaface";
|
||||
|
||||
DecodeRetinaFace(tensors, src_w, src_h, in_w, in_h, det);
|
||||
DecodeRetinaFace(tensors, src_w, src_h, in_w, in_h, lb, det);
|
||||
if (!logged_decode_.exchange(true)) {
|
||||
LogInfo("[ai_face_det] decoded faces=" + std::to_string(det.faces.size()));
|
||||
}
|
||||
@ -619,6 +664,7 @@ private:
|
||||
void DecodeRetinaFace(const std::vector<Tensor>& outs,
|
||||
int orig_w, int orig_h,
|
||||
int in_w, int in_h,
|
||||
const LetterboxInfo& lb,
|
||||
FaceDetResult& out) {
|
||||
// Find loc/conf/landms tensors.
|
||||
std::vector<NcTensor> locs;
|
||||
@ -681,6 +727,8 @@ private:
|
||||
int face_idx = face_class_index_;
|
||||
float max_p0 = 0.0f;
|
||||
float max_p1 = 0.0f;
|
||||
double sum_p0 = 0.0;
|
||||
double sum_p1 = 0.0;
|
||||
if (face_idx < 0) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
const float s0 = conf.data[static_cast<size_t>(i) * 2 + 0];
|
||||
@ -694,8 +742,13 @@ private:
|
||||
const float p0 = 1.0f - p1;
|
||||
if (p0 > max_p0) max_p0 = p0;
|
||||
if (p1 > max_p1) max_p1 = p1;
|
||||
sum_p0 += p0;
|
||||
sum_p1 += p1;
|
||||
}
|
||||
face_idx = (max_p1 >= max_p0) ? 1 : 0;
|
||||
const double mean_p0 = sum_p0 / static_cast<double>(n);
|
||||
const double mean_p1 = sum_p1 / static_cast<double>(n);
|
||||
// Face channel is typically sparse (low mean). Background channel has high mean.
|
||||
face_idx = (mean_p1 <= mean_p0) ? 1 : 0;
|
||||
}
|
||||
|
||||
if (!logged_conf_probe_.exchange(true)) {
|
||||
@ -712,8 +765,8 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
const float sx = static_cast<float>(orig_w) / static_cast<float>(in_w);
|
||||
const float sy = static_cast<float>(orig_h) / static_cast<float>(in_h);
|
||||
const bool use_lb = letterbox_ && lb.scale > 0.0f;
|
||||
const float inv_s = use_lb ? (1.0f / lb.scale) : 1.0f;
|
||||
|
||||
std::vector<Rect> boxes;
|
||||
std::vector<float> scores;
|
||||
@ -756,10 +809,19 @@ private:
|
||||
float x2 = (cx + ww * 0.5f) * static_cast<float>(in_w);
|
||||
float y2 = (cy + hh * 0.5f) * static_cast<float>(in_h);
|
||||
|
||||
if (use_lb) {
|
||||
x1 = (x1 - static_cast<float>(lb.pad_x)) * inv_s;
|
||||
x2 = (x2 - static_cast<float>(lb.pad_x)) * inv_s;
|
||||
y1 = (y1 - static_cast<float>(lb.pad_y)) * inv_s;
|
||||
y2 = (y2 - static_cast<float>(lb.pad_y)) * inv_s;
|
||||
} else {
|
||||
const float sx = static_cast<float>(orig_w) / static_cast<float>(in_w);
|
||||
const float sy = static_cast<float>(orig_h) / static_cast<float>(in_h);
|
||||
x1 *= sx;
|
||||
x2 *= sx;
|
||||
y1 *= sy;
|
||||
y2 *= sy;
|
||||
}
|
||||
|
||||
Rect bb;
|
||||
bb.x = static_cast<float>(ClampInt(static_cast<int>(x1), 0, orig_w - 1));
|
||||
@ -778,8 +840,17 @@ private:
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
const float lx = lmk.data[static_cast<size_t>(i) * 10 + k * 2 + 0];
|
||||
const float ly = lmk.data[static_cast<size_t>(i) * 10 + k * 2 + 1];
|
||||
const float px = (p.cx + lx * var0 * p.w) * static_cast<float>(in_w) * sx;
|
||||
const float py = (p.cy + ly * var0 * p.h) * static_cast<float>(in_h) * sy;
|
||||
float px = (p.cx + lx * var0 * p.w) * static_cast<float>(in_w);
|
||||
float py = (p.cy + ly * var0 * p.h) * static_cast<float>(in_h);
|
||||
if (use_lb) {
|
||||
px = (px - static_cast<float>(lb.pad_x)) * inv_s;
|
||||
py = (py - static_cast<float>(lb.pad_y)) * inv_s;
|
||||
} else {
|
||||
const float sx = static_cast<float>(orig_w) / static_cast<float>(in_w);
|
||||
const float sy = static_cast<float>(orig_h) / static_cast<float>(in_h);
|
||||
px *= sx;
|
||||
py *= sy;
|
||||
}
|
||||
pts[k].x = static_cast<float>(ClampInt(static_cast<int>(px), 0, orig_w - 1));
|
||||
pts[k].y = static_cast<float>(ClampInt(static_cast<int>(py), 0, orig_h - 1));
|
||||
}
|
||||
@ -825,6 +896,7 @@ private:
|
||||
int max_faces_ = 10;
|
||||
bool output_landmarks_ = true;
|
||||
int face_class_index_ = -1; // -1=auto, 0/1=explicit
|
||||
bool letterbox_ = false;
|
||||
|
||||
std::string input_format_ = "rgb";
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user