|
@@ -83,25 +83,58 @@ bool PoseDetector::load(const string& model_path, int input_size,
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// FP16 <-> FP32 转换(板载 RKNN FP16 模型用)
|
|
|
|
|
+static inline uint16_t floatToFp16(float x) {
|
|
|
|
|
+ uint32_t f;
|
|
|
|
|
+ memcpy(&f, &x, 4);
|
|
|
|
|
+ uint32_t sign = (f >> 16) & 0x8000;
|
|
|
|
|
+ int32_t e = (int32_t)((f >> 23) & 0xff) - 127 + 15;
|
|
|
|
|
+ uint32_t m = f & 0x7fffff;
|
|
|
|
|
+ if (((f >> 23) & 0xff) == 0xff) return sign | 0x7c00; // inf/nan
|
|
|
|
|
+ if (e >= 31) return sign | 0x7c00; // 溢出
|
|
|
|
|
+ if (e <= 0) {
|
|
|
|
|
+ if (e < -10) return sign; // 下溢为0
|
|
|
|
|
+ m = (m | 0x800000) >> (1 - e);
|
|
|
|
|
+ return sign | m;
|
|
|
|
|
+ }
|
|
|
|
|
+ return sign | ((uint32_t)e << 10) | (m >> 13);
|
|
|
|
|
+}
|
|
|
|
|
+static inline float fp16ToFloat(uint16_t h) {
|
|
|
|
|
+ uint32_t sign = ((uint32_t)h & 0x8000) << 16;
|
|
|
|
|
+ uint32_t e = (h >> 10) & 0x1f, m = h & 0x3ff;
|
|
|
|
|
+ uint32_t f;
|
|
|
|
|
+ if (e == 0) {
|
|
|
|
|
+ if (m == 0) { f = sign; }
|
|
|
|
|
+ else { e = 1; m = (m << 1) + 1; f = sign | ((e + 112) << 23) | (m << 13); }
|
|
|
|
|
+ } else if (e == 31) {
|
|
|
|
|
+ f = sign | 0x7f800000 | (m << 13);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ f = sign | ((e + 112) << 23) | (m << 13);
|
|
|
|
|
+ }
|
|
|
|
|
+ float r;
|
|
|
|
|
+ memcpy(&r, &f, 4);
|
|
|
|
|
+ return r;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
vector<PersonPose> PoseDetector::detect(const float* rgb_data, int img_w, int img_h,
|
|
vector<PersonPose> PoseDetector::detect(const float* rgb_data, int img_w, int img_h,
|
|
|
float scale, int pad_x, int pad_y) {
|
|
float scale, int pad_x, int pad_y) {
|
|
|
if (!loaded_ || !rgb_data) return {};
|
|
if (!loaded_ || !rgb_data) return {};
|
|
|
|
|
|
|
|
int num_pixels = input_size_ * input_size_ * 3;
|
|
int num_pixels = input_size_ * input_size_ * 3;
|
|
|
|
|
|
|
|
- vector<int8_t> input_i8(num_pixels);
|
|
|
|
|
|
|
+ // FP16 输入: 直接转 float32 rgb [0,1] -> fp16
|
|
|
|
|
+ vector<uint16_t> input_fp16(num_pixels);
|
|
|
for (int i = 0; i < num_pixels; i++) {
|
|
for (int i = 0; i < num_pixels; i++) {
|
|
|
- int v = (int)(rgb_data[i] * 255.0f) - 128;
|
|
|
|
|
- input_i8[i] = (int8_t)(v < -128 ? -128 : (v > 127 ? 127 : v));
|
|
|
|
|
|
|
+ input_fp16[i] = floatToFp16(rgb_data[i]);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
rknn_input inputs[1];
|
|
rknn_input inputs[1];
|
|
|
memset(&inputs[0], 0, sizeof(rknn_input));
|
|
memset(&inputs[0], 0, sizeof(rknn_input));
|
|
|
inputs[0].index = 0;
|
|
inputs[0].index = 0;
|
|
|
- inputs[0].type = RKNN_TENSOR_INT8;
|
|
|
|
|
|
|
+ inputs[0].type = RKNN_TENSOR_FLOAT16;
|
|
|
inputs[0].fmt = RKNN_TENSOR_NHWC;
|
|
inputs[0].fmt = RKNN_TENSOR_NHWC;
|
|
|
- inputs[0].size = input_i8.size() * sizeof(int8_t);
|
|
|
|
|
- inputs[0].buf = input_i8.data();
|
|
|
|
|
|
|
+ inputs[0].size = input_fp16.size() * sizeof(uint16_t);
|
|
|
|
|
+ inputs[0].buf = input_fp16.data();
|
|
|
inputs[0].pass_through = 1;
|
|
inputs[0].pass_through = 1;
|
|
|
|
|
|
|
|
int ret = rknn_inputs_set(ctx_, 1, inputs);
|
|
int ret = rknn_inputs_set(ctx_, 1, inputs);
|
|
@@ -119,7 +152,7 @@ vector<PersonPose> PoseDetector::detect(const float* rgb_data, int img_w, int im
|
|
|
vector<rknn_output> outputs(n_output_);
|
|
vector<rknn_output> outputs(n_output_);
|
|
|
for (uint32_t i = 0; i < n_output_; i++) {
|
|
for (uint32_t i = 0; i < n_output_; i++) {
|
|
|
memset(&outputs[i], 0, sizeof(rknn_output));
|
|
memset(&outputs[i], 0, sizeof(rknn_output));
|
|
|
- outputs[i].want_float = 1;
|
|
|
|
|
|
|
+ outputs[i].want_float = 0; // FP16 模型: 拿原始 fp16 数据自己转
|
|
|
}
|
|
}
|
|
|
ret = rknn_outputs_get(ctx_, n_output_, outputs.data(), nullptr);
|
|
ret = rknn_outputs_get(ctx_, n_output_, outputs.data(), nullptr);
|
|
|
if (ret < 0) {
|
|
if (ret < 0) {
|
|
@@ -131,36 +164,20 @@ vector<PersonPose> PoseDetector::detect(const float* rgb_data, int img_w, int im
|
|
|
|
|
|
|
|
if (n_output_ == 1) {
|
|
if (n_output_ == 1) {
|
|
|
auto& attr = output_attrs_[0];
|
|
auto& attr = output_attrs_[0];
|
|
|
- int num_preds = attr.dims[1];
|
|
|
|
|
- int num_attrs = attr.dims[2];
|
|
|
|
|
- float* data = static_cast<float*>(outputs[0].buf);
|
|
|
|
|
-
|
|
|
|
|
- // YOLOv8-pose 输出: num_preds x (4 + 1 + num_cls + 17*3)
|
|
|
|
|
- // 其中 17*3 = 每个关键点 (x, y, conf)
|
|
|
|
|
- int num_cls = num_attrs - 4 - 1 - 17 * 3;
|
|
|
|
|
- if (num_cls >= 1) {
|
|
|
|
|
|
|
+ // RKNN FP16 输出: [1, 56, 8400] NCHW (通道在前), 原始 fp16
|
|
|
|
|
+ // YOLOv8-pose: 56 = 4(bbox cx,cy,w,h) + 1(class) + 17*3(kpt x,y,conf)
|
|
|
|
|
+ int ch = attr.dims[1];
|
|
|
|
|
+ int num_preds = attr.dims[2];
|
|
|
|
|
+ uint16_t* data = static_cast<uint16_t*>(outputs[0].buf);
|
|
|
|
|
+ if (ch >= 4 + 1 + 17 * 3 && num_preds > 0) {
|
|
|
for (int i = 0; i < num_preds; i++) {
|
|
for (int i = 0; i < num_preds; i++) {
|
|
|
- float* pred = data + i * num_attrs;
|
|
|
|
|
-
|
|
|
|
|
- float box_conf = pred[4];
|
|
|
|
|
- float max_score = 0;
|
|
|
|
|
- int max_id = -1;
|
|
|
|
|
- for (int c = 5; c < 5 + num_cls; c++) {
|
|
|
|
|
- if (pred[c] > max_score) {
|
|
|
|
|
- max_score = pred[c];
|
|
|
|
|
- max_id = c - 5;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- // 类别0(person)之外的只当背景处理
|
|
|
|
|
- if (max_id != 0) continue;
|
|
|
|
|
-
|
|
|
|
|
- float final_score = box_conf * max_score;
|
|
|
|
|
- if (final_score < conf_thresh_) continue;
|
|
|
|
|
|
|
+ float cx = fp16ToFloat(data[0 * num_preds + i]);
|
|
|
|
|
+ float cy = fp16ToFloat(data[1 * num_preds + i]);
|
|
|
|
|
+ float w = fp16ToFloat(data[2 * num_preds + i]);
|
|
|
|
|
+ float h = fp16ToFloat(data[3 * num_preds + i]);
|
|
|
|
|
|
|
|
- float cx = pred[0];
|
|
|
|
|
- float cy = pred[1];
|
|
|
|
|
- float w = pred[2];
|
|
|
|
|
- float h = pred[3];
|
|
|
|
|
|
|
+ float cls = fp16ToFloat(data[4 * num_preds + i]);
|
|
|
|
|
+ if (cls < conf_thresh_) continue;
|
|
|
|
|
|
|
|
float x1 = (cx - w * 0.5f - pad_x) / scale;
|
|
float x1 = (cx - w * 0.5f - pad_x) / scale;
|
|
|
float y1 = (cy - h * 0.5f - pad_y) / scale;
|
|
float y1 = (cy - h * 0.5f - pad_y) / scale;
|
|
@@ -177,16 +194,16 @@ vector<PersonPose> PoseDetector::detect(const float* rgb_data, int img_w, int im
|
|
|
|
|
|
|
|
PersonPose pp;
|
|
PersonPose pp;
|
|
|
pp.bbox = cv::Rect(ix1, iy1, bw, bh);
|
|
pp.bbox = cv::Rect(ix1, iy1, bw, bh);
|
|
|
- pp.confidence = final_score;
|
|
|
|
|
|
|
+ pp.confidence = cls;
|
|
|
|
|
|
|
|
- float* kp = pred + 5 + num_cls;
|
|
|
|
|
pp.keypoints.resize(17);
|
|
pp.keypoints.resize(17);
|
|
|
pp.keypoint_conf.resize(17);
|
|
pp.keypoint_conf.resize(17);
|
|
|
for (int k = 0; k < 17; k++) {
|
|
for (int k = 0; k < 17; k++) {
|
|
|
- float kx = (kp[k * 3] - pad_x) / scale;
|
|
|
|
|
- float ky = (kp[k * 3 + 1] - pad_y) / scale;
|
|
|
|
|
|
|
+ int base = 5 + k * 3;
|
|
|
|
|
+ float kx = (fp16ToFloat(data[(base + 0) * num_preds + i]) - pad_x) / scale;
|
|
|
|
|
+ float ky = (fp16ToFloat(data[(base + 1) * num_preds + i]) - pad_y) / scale;
|
|
|
pp.keypoints[k] = cv::Point2f(kx, ky);
|
|
pp.keypoints[k] = cv::Point2f(kx, ky);
|
|
|
- pp.keypoint_conf[k] = kp[k * 3 + 2];
|
|
|
|
|
|
|
+ pp.keypoint_conf[k] = fp16ToFloat(data[(base + 2) * num_preds + i]);
|
|
|
}
|
|
}
|
|
|
poses.push_back(std::move(pp));
|
|
poses.push_back(std::move(pp));
|
|
|
}
|
|
}
|