Upload first version
This commit is contained in:
parent
f95d5a63b0
commit
3bdf2003ec
898 changed files with 1405811 additions and 1 deletions
41
examples/retinaface/cpp/src/CMakeLists.txt
Executable file
41
examples/retinaface/cpp/src/CMakeLists.txt
Executable file
|
|
@ -0,0 +1,41 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
project(retinaface_demo)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# Set NNSDK path
|
||||
set(NNSDK_ROOT "${CMAKE_SOURCE_DIR}/../../../../dependency/nnsdk")
|
||||
include_directories(${NNSDK_ROOT}/include)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/../../../../common)
|
||||
|
||||
# Set dependency path
|
||||
set(3RDPARTY_DIR "${CMAKE_SOURCE_DIR}/../../../../dependency")
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
if (ANDROID_ABI STREQUAL "arm64-v8a")
|
||||
link_directories(${NNSDK_ROOT}/lib/android/arm64-v8a)
|
||||
else()
|
||||
link_directories(${NNSDK_ROOT}/lib/android/armeabi-v7a)
|
||||
endif()
|
||||
# Android needs log
|
||||
link_libraries(log)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
link_directories(${NNSDK_ROOT}/lib/linux/lib64_yocto)
|
||||
endif()
|
||||
|
||||
# Find OpenCV
|
||||
message(STATUS "OpenCV_DIR: ${OpenCV_DIR}")
|
||||
find_package(OpenCV REQUIRED)
|
||||
include_directories(${OpenCV_INCLUDE_DIRS})
|
||||
|
||||
|
||||
add_executable(retinaface_demo
|
||||
main.cpp
|
||||
postprocess.cpp
|
||||
${CMAKE_SOURCE_DIR}/../../../../common/model_loader.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(retinaface_demo
|
||||
${OpenCV_LIBS}
|
||||
nnsdk
|
||||
)
|
||||
99
examples/retinaface/cpp/src/main.cpp
Executable file
99
examples/retinaface/cpp/src/main.cpp
Executable file
|
|
@ -0,0 +1,99 @@
|
|||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include "nn_sdk.h"
|
||||
#include "postprocess.h"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
static void hwc_to_chw(const cv::Mat& src, float* dst) {
|
||||
int h = src.rows, w = src.cols;
|
||||
for (int k = 0; k < 3; ++k) {
|
||||
for (int i = 0; i < h; ++i) {
|
||||
for (int j = 0; j < w; ++j) {
|
||||
dst[k * h * w + i * w + j] = src.at<cv::Vec3f>(i, j)[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 3) { std::cout << "Usage: " << argv[0] << " <model.adla> <image_dir>\n"; return 0; }
|
||||
|
||||
aml_config cfg{};
|
||||
cfg.typeSize = sizeof(cfg); cfg.modelType = ADLA_LOADABLE; cfg.nbgType = NN_ADLA_FILE; cfg.path = argv[1];
|
||||
void* ctx = aml_module_create(&cfg);
|
||||
auto priors = generate_priors();
|
||||
size_t num_priors = priors.size();
|
||||
std::vector<float> chw_buffer(kInputW * kInputH * 3);
|
||||
|
||||
fs::create_directory("retinaface_result");
|
||||
|
||||
for (auto& it : fs::directory_iterator(argv[2])) {
|
||||
cv::Mat img = cv::imread(it.path().string());
|
||||
if (img.empty()) continue;
|
||||
|
||||
float scale = std::min((float)kInputW / img.cols, (float)kInputH / img.rows);
|
||||
int nw = img.cols * scale, nh = img.rows * scale;
|
||||
int px = (kInputW - nw) / 2, py = (kInputH - nh) / 2;
|
||||
cv::Mat res, canvas = cv::Mat::zeros(kInputH, kInputW, CV_32FC3);
|
||||
cv::resize(img, res, {nw, nh}); res.convertTo(res, CV_32FC3);
|
||||
res.copyTo(canvas(cv::Rect(px, py, nw, nh)));
|
||||
hwc_to_chw(canvas, chw_buffer.data());
|
||||
|
||||
nn_input in{}; in.typeSize = sizeof(in); in.input_type = BINARY_RAW_DATA;
|
||||
in.input = (unsigned char*)chw_buffer.data(); in.size = chw_buffer.size() * 4;
|
||||
in.info.valid = 1; in.info.input_format = AML_INPUT_MODEL_NCHW; in.info.input_data_type = AML_INPUT_FP32;
|
||||
aml_module_input_set(ctx, &in);
|
||||
|
||||
aml_output_config_t outcfg{}; outcfg.typeSize = sizeof(outcfg); outcfg.format = AML_OUTDATA_FLOAT32;
|
||||
nn_output* out = (nn_output*)aml_module_output_get(ctx, outcfg);
|
||||
if (!out) continue;
|
||||
|
||||
float *loc = nullptr, *conf = nullptr, *landm = nullptr;
|
||||
for (int i = 0; i < out->num; i++) {
|
||||
if (out->out[i].size == num_priors * 4 * 4) loc = (float*)out->out[i].buf;
|
||||
else if (out->out[i].size == num_priors * 2 * 4) conf = (float*)out->out[i].buf;
|
||||
else if (out->out[i].size == num_priors * 10 * 4) landm = (float*)out->out[i].buf;
|
||||
}
|
||||
if (!loc || !conf || !landm) continue;
|
||||
|
||||
bool is_planar = (conf[0] > 2.0 || conf[1] > 2.0);
|
||||
std::vector<std::array<float, 4>> boxes;
|
||||
std::vector<std::array<float, 10>> lms;
|
||||
std::vector<float> scores_vec;
|
||||
|
||||
for (size_t i = 0; i < num_priors; i++) {
|
||||
float sc = is_planar ? conf[num_priors + i] : conf[i * 2 + 1];
|
||||
if (sc > 0.5f) {
|
||||
boxes.push_back(decode_box(loc, i, num_priors, is_planar, priors[i]));
|
||||
lms.push_back(decode_landm(landm, i, num_priors, is_planar, priors[i]));
|
||||
scores_vec.push_back(sc);
|
||||
}
|
||||
}
|
||||
|
||||
auto keep = nms(boxes, scores_vec, 0.4f);
|
||||
for (int k : keep) {
|
||||
auto& b = boxes[k];
|
||||
int x1 = (b[0] * kInputW - px) / scale, y1 = (b[1] * kInputH - py) / scale;
|
||||
int x2 = (b[2] * kInputW - px) / scale, y2 = (b[3] * kInputH - py) / scale;
|
||||
|
||||
cv::rectangle(img, {x1, y1}, {x2, y2}, {0, 255, 0}, 2);
|
||||
|
||||
char score_text[16];
|
||||
std::snprintf(score_text, sizeof(score_text), "%.2f", scores_vec[k]);
|
||||
cv::putText(img, score_text, {x1, std::max(y1 - 5, 5)}, cv::FONT_HERSHEY_SIMPLEX, 0.5, {0, 255, 0}, 1, cv::LINE_AA);
|
||||
|
||||
auto& lm = lms[k];
|
||||
for (int j = 0; j < 5; j++) {
|
||||
int lx = (lm[2 * j] * kInputW - px) / scale;
|
||||
int ly = (lm[2 * j + 1] * kInputH - py) / scale;
|
||||
cv::circle(img, {lx, ly}, 2, {0, 0, 255}, -1);
|
||||
}
|
||||
}
|
||||
cv::imwrite("retinaface_result/" + it.path().filename().string(), img);
|
||||
std::cout << "Detected: " << it.path().filename() << " (" << keep.size() << " faces)\n";
|
||||
}
|
||||
aml_module_destroy(ctx); return 0;
|
||||
}
|
||||
78
examples/retinaface/cpp/src/postprocess.cpp
Executable file
78
examples/retinaface/cpp/src/postprocess.cpp
Executable file
|
|
@ -0,0 +1,78 @@
|
|||
#include "postprocess.h"
|
||||
#include <cmath>
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
|
||||
std::vector<std::array<float, 4>> generate_priors() {
|
||||
std::vector<std::array<float, 4>> priors;
|
||||
std::vector<int> steps = {8, 16, 32};
|
||||
std::vector<std::vector<int>> min_sizes = {{16, 32}, {64, 128}, {256, 512}};
|
||||
for (size_t k = 0; k < steps.size(); ++k) {
|
||||
int fm_h = std::ceil((float)kInputH / steps[k]);
|
||||
int fm_w = std::ceil((float)kInputW / steps[k]);
|
||||
for (int i = 0; i < fm_h; i++) {
|
||||
for (int j = 0; j < fm_w; j++) {
|
||||
for (int ms : min_sizes[k]) {
|
||||
float cx = (j + 0.5f) * steps[k] / kInputW;
|
||||
float cy = (i + 0.5f) * steps[k] / kInputH;
|
||||
float sx = (float)ms / kInputW;
|
||||
float sy = (float)ms / kInputH;
|
||||
priors.push_back({cx, cy, sx, sy});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return priors;
|
||||
}
|
||||
|
||||
std::array<float, 10> decode_landm(const float* lm, int idx, int total, bool is_planar, const std::array<float, 4>& p) {
|
||||
std::array<float, 10> out{};
|
||||
float raw[10];
|
||||
if (is_planar) {
|
||||
for (int j = 0; j < 10; ++j) raw[j] = lm[j * total + idx];
|
||||
} else {
|
||||
for (int j = 0; j < 10; ++j) raw[j] = lm[idx * 10 + j];
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
out[2 * i] = p[0] + raw[2 * i] * 0.1f * p[2];
|
||||
out[2 * i + 1] = p[1] + raw[2 * i + 1] * 0.1f * p[3];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::array<float, 4> decode_box(const float* loc, int idx, int total, bool is_planar, const std::array<float, 4>& p) {
|
||||
float l[4];
|
||||
if (is_planar) {
|
||||
l[0] = loc[0 * total + idx]; l[1] = loc[1 * total + idx];
|
||||
l[2] = loc[2 * total + idx]; l[3] = loc[3 * total + idx];
|
||||
} else {
|
||||
l[0] = loc[idx * 4 + 0]; l[1] = loc[idx * 4 + 1];
|
||||
l[2] = loc[idx * 4 + 2]; l[3] = loc[idx * 4 + 3];
|
||||
}
|
||||
float cx = p[0] + l[0] * 0.1f * p[2];
|
||||
float cy = p[1] + l[1] * 0.1f * p[3];
|
||||
float w = p[2] * std::exp(l[2] * 0.2f);
|
||||
float h = p[3] * std::exp(l[3] * 0.2f);
|
||||
return { cx - w * 0.5f, cy - h * 0.5f, cx + w * 0.5f, cy + h * 0.5f };
|
||||
}
|
||||
|
||||
float iou(const std::array<float, 4>& a, const std::array<float, 4>& b) {
|
||||
float xx1 = std::max(a[0], b[0]), yy1 = std::max(a[1], b[1]);
|
||||
float xx2 = std::min(a[2], b[2]), yy2 = std::min(a[3], b[3]);
|
||||
float w = std::max(0.f, xx2 - xx1), h = std::max(0.f, yy2 - yy1);
|
||||
float inter = w * h;
|
||||
float areaA = (a[2] - a[0]) * (a[3] - a[1]), areaB = (b[2] - b[0]) * (b[3] - b[1]);
|
||||
return inter / (areaA + areaB - inter);
|
||||
}
|
||||
|
||||
std::vector<int> nms(const std::vector<std::array<float, 4>>& boxes, const std::vector<float>& scores, float thresh) {
|
||||
std::vector<int> order(boxes.size());
|
||||
std::iota(order.begin(), order.end(), 0);
|
||||
std::stable_sort(order.begin(), order.end(), [&](int a, int b) { return scores[a] > scores[b]; });
|
||||
std::vector<int> keep;
|
||||
while (!order.empty()) {
|
||||
int i = order[0]; keep.push_back(i); order.erase(order.begin());
|
||||
order.erase(std::remove_if(order.begin(), order.end(), [&](int j) { return iou(boxes[i], boxes[j]) > thresh; }), order.end());
|
||||
}
|
||||
return keep;
|
||||
}
|
||||
21
examples/retinaface/cpp/src/postprocess.h
Executable file
21
examples/retinaface/cpp/src/postprocess.h
Executable file
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef RETINAFACE_POSTPROCESS_H
|
||||
#define RETINAFACE_POSTPROCESS_H
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
static constexpr int kInputW = 320;
|
||||
static constexpr int kInputH = 320;
|
||||
|
||||
std::vector<std::array<float, 4>> generate_priors();
|
||||
|
||||
std::array<float, 10> decode_landm(const float* lm, int idx, int total, bool is_planar, const std::array<float, 4>& p);
|
||||
|
||||
std::array<float, 4> decode_box(const float* loc, int idx, int total, bool is_planar, const std::array<float, 4>& p);
|
||||
|
||||
float iou(const std::array<float, 4>& a, const std::array<float, 4>& b);
|
||||
|
||||
std::vector<int> nms(const std::vector<std::array<float, 4>>& boxes, const std::vector<float>& scores, float thresh);
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue