|
|
|
@ -221,6 +221,48 @@ bool YoloV5Ncnn_Init(const std::string& paramFile, const std::string& binFile)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool YoloV5Ncnn_Init(ncnn::Net& net, const std::string& paramFile, const std::string& binFile)
|
|
|
|
|
{
|
|
|
|
|
ncnn::Option opt;
|
|
|
|
|
opt.lightmode = true;
|
|
|
|
|
opt.num_threads = 4;
|
|
|
|
|
opt.blob_allocator = &g_blob_pool_allocator;
|
|
|
|
|
opt.workspace_allocator = &g_workspace_pool_allocator;
|
|
|
|
|
opt.use_packing_layout = true;
|
|
|
|
|
|
|
|
|
|
// use vulkan compute
|
|
|
|
|
if (ncnn::get_gpu_count() != 0)
|
|
|
|
|
opt.use_vulkan_compute = true;
|
|
|
|
|
|
|
|
|
|
// AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
|
|
|
|
|
|
|
|
|
|
net.opt = opt;
|
|
|
|
|
|
|
|
|
|
net.register_custom_layer("YoloV5Focus", YoloV5Focus_layer_creator);
|
|
|
|
|
|
|
|
|
|
// init param
|
|
|
|
|
{
|
|
|
|
|
int ret = net.load_param(paramFile.c_str());
|
|
|
|
|
if (ret != 0)
|
|
|
|
|
{
|
|
|
|
|
// __android_log_print(ANDROID_LOG_DEBUG, "YoloV5Ncnn", "load_param failed");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// init bin
|
|
|
|
|
{
|
|
|
|
|
int ret = net.load_model(binFile.c_str());
|
|
|
|
|
if (ret != 0)
|
|
|
|
|
{
|
|
|
|
|
// __android_log_print(ANDROID_LOG_DEBUG, "YoloV5Ncnn", "load_model failed");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// public native Obj[] Detect(Bitmap bitmap, boolean use_gpu);
|
|
|
|
|
bool YoloV5NcnnDetect( ncnn::Mat& mat, bool use_gpu, std::vector<IDevice::RECOG_OBJECT>& objects)
|
|
|
|
|
{
|
|
|
|
@ -601,3 +643,159 @@ bool YoloV5NcnnDetect( cv::Mat& mat, bool use_gpu, const std::string& blobName8,
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool YoloV5NcnnDetect( ncnn::Net& net, cv::Mat& mat, bool use_gpu, const std::string& blobName8, const std::string& blobName16, const std::string& blobName32, std::vector<IDevice::RECOG_OBJECT>& objects)
|
|
|
|
|
{
|
|
|
|
|
if (use_gpu && ncnn::get_gpu_count() == 0)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
//return env->NewStringUTF("no vulkan capable gpu");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AndroidBitmapInfo info;
|
|
|
|
|
// AndroidBitmap_getInfo(env, bitmap, &info);
|
|
|
|
|
const int width = mat.cols;
|
|
|
|
|
const int height = mat.rows;
|
|
|
|
|
// if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888)
|
|
|
|
|
// return NULL;
|
|
|
|
|
|
|
|
|
|
// ncnn from bitmap
|
|
|
|
|
const int target_size = 640;
|
|
|
|
|
|
|
|
|
|
// letterbox pad to multiple of 32
|
|
|
|
|
int w = width;
|
|
|
|
|
int h = height;
|
|
|
|
|
float scale = 1.f;
|
|
|
|
|
if (w > h)
|
|
|
|
|
{
|
|
|
|
|
scale = (float)target_size / w;
|
|
|
|
|
w = target_size;
|
|
|
|
|
h = h * scale;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
scale = (float)target_size / h;
|
|
|
|
|
h = target_size;
|
|
|
|
|
w = w * scale;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ncnn::Mat in = ncnn::Mat::from_pixels_resize(mat.data, ncnn::Mat::PIXEL_BGR2RGB, mat.cols, mat.rows, w, h);
|
|
|
|
|
|
|
|
|
|
// pad to target_size rectangle
|
|
|
|
|
// yolov5/utils/datasets.py letterbox
|
|
|
|
|
int wpad = (w + 31) / 32 * 32 - w;
|
|
|
|
|
int hpad = (h + 31) / 32 * 32 - h;
|
|
|
|
|
ncnn::Mat in_pad;
|
|
|
|
|
ncnn::copy_make_border(in, in_pad, hpad / 2, hpad - hpad / 2, wpad / 2, wpad - wpad / 2, ncnn::BORDER_CONSTANT, 114.f);
|
|
|
|
|
|
|
|
|
|
// yolov5
|
|
|
|
|
{
|
|
|
|
|
const float prob_threshold = 0.25f;
|
|
|
|
|
const float nms_threshold = 0.45f;
|
|
|
|
|
|
|
|
|
|
const float norm_vals[3] = {1 / 255.f, 1 / 255.f, 1 / 255.f};
|
|
|
|
|
in_pad.substract_mean_normalize(0, norm_vals);
|
|
|
|
|
|
|
|
|
|
ncnn::Extractor ex = net.create_extractor();
|
|
|
|
|
|
|
|
|
|
ex.set_vulkan_compute(use_gpu);
|
|
|
|
|
|
|
|
|
|
ex.input("images", in_pad);
|
|
|
|
|
|
|
|
|
|
std::vector<IDevice::RECOG_OBJECT> proposals;
|
|
|
|
|
|
|
|
|
|
// anchor setting from yolov5/models/yolov5s.yaml
|
|
|
|
|
|
|
|
|
|
// stride 8
|
|
|
|
|
{
|
|
|
|
|
ncnn::Mat out;
|
|
|
|
|
ex.extract(blobName8.c_str(), out);
|
|
|
|
|
|
|
|
|
|
ncnn::Mat anchors(6);
|
|
|
|
|
anchors[0] = 10.f;
|
|
|
|
|
anchors[1] = 13.f;
|
|
|
|
|
anchors[2] = 16.f;
|
|
|
|
|
anchors[3] = 30.f;
|
|
|
|
|
anchors[4] = 33.f;
|
|
|
|
|
anchors[5] = 23.f;
|
|
|
|
|
|
|
|
|
|
std::vector<IDevice::RECOG_OBJECT> objects8;
|
|
|
|
|
generate_proposals(anchors, 8, in_pad, out, prob_threshold, objects8);
|
|
|
|
|
|
|
|
|
|
proposals.insert(proposals.end(), objects8.begin(), objects8.end());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// stride 16
|
|
|
|
|
{
|
|
|
|
|
ncnn::Mat out;
|
|
|
|
|
ex.extract(blobName16.c_str(), out);
|
|
|
|
|
|
|
|
|
|
ncnn::Mat anchors(6);
|
|
|
|
|
anchors[0] = 30.f;
|
|
|
|
|
anchors[1] = 61.f;
|
|
|
|
|
anchors[2] = 62.f;
|
|
|
|
|
anchors[3] = 45.f;
|
|
|
|
|
anchors[4] = 59.f;
|
|
|
|
|
anchors[5] = 119.f;
|
|
|
|
|
|
|
|
|
|
std::vector<IDevice::RECOG_OBJECT> objects16;
|
|
|
|
|
generate_proposals(anchors, 16, in_pad, out, prob_threshold, objects16);
|
|
|
|
|
|
|
|
|
|
proposals.insert(proposals.end(), objects16.begin(), objects16.end());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// stride 32
|
|
|
|
|
{
|
|
|
|
|
ncnn::Mat out;
|
|
|
|
|
ex.extract(blobName32.c_str(), out);
|
|
|
|
|
|
|
|
|
|
ncnn::Mat anchors(6);
|
|
|
|
|
anchors[0] = 116.f;
|
|
|
|
|
anchors[1] = 90.f;
|
|
|
|
|
anchors[2] = 156.f;
|
|
|
|
|
anchors[3] = 198.f;
|
|
|
|
|
anchors[4] = 373.f;
|
|
|
|
|
anchors[5] = 326.f;
|
|
|
|
|
|
|
|
|
|
std::vector<IDevice::RECOG_OBJECT> objects32;
|
|
|
|
|
generate_proposals(anchors, 32, in_pad, out, prob_threshold, objects32);
|
|
|
|
|
|
|
|
|
|
proposals.insert(proposals.end(), objects32.begin(), objects32.end());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// sort all proposals by score from highest to lowest
|
|
|
|
|
qsort_descent_inplace(proposals);
|
|
|
|
|
|
|
|
|
|
// apply nms with nms_threshold
|
|
|
|
|
std::vector<int> picked;
|
|
|
|
|
nms_sorted_bboxes(proposals, picked, nms_threshold);
|
|
|
|
|
|
|
|
|
|
int count = picked.size();
|
|
|
|
|
|
|
|
|
|
objects.resize(count);
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
objects[i] = proposals[picked[i]];
|
|
|
|
|
|
|
|
|
|
// adjust offset to original unpadded
|
|
|
|
|
float x0 = (objects[i].x - (wpad / 2)) / scale;
|
|
|
|
|
float y0 = (objects[i].y - (hpad / 2)) / scale;
|
|
|
|
|
float x1 = (objects[i].x + objects[i].w - (wpad / 2)) / scale;
|
|
|
|
|
float y1 = (objects[i].y + objects[i].h - (hpad / 2)) / scale;
|
|
|
|
|
|
|
|
|
|
// clip
|
|
|
|
|
x0 = std::max(std::min(x0, (float)(width - 1)), 0.f);
|
|
|
|
|
y0 = std::max(std::min(y0, (float)(height - 1)), 0.f);
|
|
|
|
|
x1 = std::max(std::min(x1, (float)(width - 1)), 0.f);
|
|
|
|
|
y1 = std::max(std::min(y1, (float)(height - 1)), 0.f);
|
|
|
|
|
|
|
|
|
|
objects[i].x = x0;
|
|
|
|
|
objects[i].y = y0;
|
|
|
|
|
objects[i].w = x1 - x0;
|
|
|
|
|
objects[i].h = y1 - y0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|