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