ncnn server mobilessd
原文链接: ncnn server mobilessd
1. 增加http服务
#include <httplib.h>
using namespace httplib;
int main(void) {
Server svr;
std::string s;
s += "================================\n";
svr.Get("/", [](const Request &req, Response &res) {
char buf[BUFSIZ];
snprintf(buf, sizeof(buf), "%s %s %s", req.method.c_str(),
req.version.c_str(), req.path.c_str());
res.set_content(buf, "text/plain");
});
svr.listen("localhost", 80);
}
g++ -o hello hello.cc -pthread -I.. --std=c++14 -Wall -Wextra
2. 检测服务
Cmakefiles.txt 增加c++14 支持
add_compile_options(-std=c++14 -fexceptions)添加httplib.h
#include "httplib.h"
using namespace httplib;
#include <stdio.h>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "platform.h"
#include "net.h"
#if NCNN_VULKAN
#include "gpu.h"
#endif // NCNN_VULKAN
struct Object
{
cv::Rect_<float> rect;
int label;
float prob;
};
static int g_loop_count = 4;
void benchmark(const char* comment, void (*init)(ncnn::Net&), void (*run)(const ncnn::Net&))
{
ncnn::Net net;
init(net);
net.load_model();
run(net);
// double time_min = DBL_MAX;
// double time_max = -DBL_MAX;
// double time_avg = 0;
// // for (int i=0; i<g_loop_count; i++)
// // {
// // // double start = ncnn::get_current_time();
// // run(net);
// // // double end = ncnn::get_current_time();
// // // double time = end - start;
// // time_min = std::min(time_min, time);
// // time_max = std::max(time_max, time);
// // time_avg += time;
// // }
// time_avg /= g_loop_count;
// fprintf(stderr, "%-20s min = %7.2f max = %7.2f avg = %7.2f\n", comment, time_min, time_max, time_avg);
}
void mobilenet_v2_init(ncnn::Net& mobilenet)
{
// net.load_param("mobilenet_v2.param");
mobilenet.load_param("mobilenet_ssd_voc_ncnn.param");
mobilenet.load_model("mobilenet_ssd_voc_ncnn.bin");
}
void mobilenet_v2_run(const ncnn::Net& net)
{
ncnn::Extractor ex = net.create_extractor();
ncnn::Mat in(224, 224, 3);
ex.input("data", in);
ncnn::Mat out;
ex.extract("prob", out);
}
static int detect_mobilenet(ncnn::Net& net,const cv::Mat& bgr, std::vector<Object>& objects)
{
// ncnn::Net mobilenet;
#if NCNN_VULKAN
mobilenet.opt.use_vulkan_compute = true;
#endif // NCNN_VULKAN
// model is converted from https://github.com/chuanqi305/MobileNet-SSD
// and can be downloaded from https://drive.google.com/open?id=0ByaKLD9QaPtucWk0Y0dha1VVY0U
// net.load_param("mobilenet_ssd_voc_ncnn.param");
// net.load_model("mobilenet_ssd_voc_ncnn.bin");
const int target_size = 300;
int img_w = bgr.cols;
int img_h = bgr.rows;
ncnn::Mat in = ncnn::Mat::from_pixels_resize(bgr.data, ncnn::Mat::PIXEL_BGR, bgr.cols, bgr.rows, target_size, target_size);
const float mean_vals[3] = {127.5f, 127.5f, 127.5f};
const float norm_vals[3] = {1.0/127.5,1.0/127.5,1.0/127.5};
in.substract_mean_normalize(mean_vals, norm_vals);
ncnn::Extractor ex = net.create_extractor();
// ex.set_num_threads(4);
ex.input("data", in);
ncnn::Mat out;
ex.extract("detection_out",out);
// printf("%d %d %d\n", out.w, out.h, out.c);
objects.clear();
for (int i=0; i<out.h; i++)
{
const float* values = out.row(i);
Object object;
object.label = values[0];
object.prob = values[1];
object.rect.x = values[2] * img_w;
object.rect.y = values[3] * img_h;
object.rect.width = values[4] * img_w - object.rect.x;
object.rect.height = values[5] * img_h - object.rect.y;
objects.push_back(object);
}
//
// return 0;
}
static void draw_objects(const cv::Mat& bgr, const std::vector<Object>& objects)
{
static const char* class_names[] = {"background",
"aeroplane", "bicycle", "bird", "boat",
"bottle", "bus", "car", "cat", "chair",
"cow", "diningtable", "dog", "horse",
"motorbike", "person", "pottedplant",
"sheep", "sofa", "train", "tvmonitor"};
cv::Mat image = bgr.clone();
for (size_t i = 0; i < objects.size(); i++)
{
const Object& obj = objects[i];
fprintf(stderr, "%d = %.5f at %.2f %.2f %.2f x %.2f\n", obj.label, obj.prob,
obj.rect.x, obj.rect.y, obj.rect.width, obj.rect.height);
cv::rectangle(image, obj.rect, cv::Scalar(255, 0, 0));
char text[256];
sprintf(text, "%s %.1f%%", class_names[obj.label], obj.prob * 100);
int baseLine = 0;
cv::Size label_size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
int x = obj.rect.x;
int y = obj.rect.y - label_size.height - baseLine;
if (y < 0)
y = 0;
if (x + label_size.width > image.cols)
x = image.cols - label_size.width;
cv::rectangle(image, cv::Rect(cv::Point(x, y),
cv::Size(label_size.width, label_size.height + baseLine)),
cv::Scalar(255, 255, 255), -1);
cv::putText(image, text, cv::Point(x, y + label_size.height),
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
}
cv::imshow("image", image);
cv::waitKey(0);
}
int main(int argc, char** argv)
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s [imagepath]\n", argv[0]);
return -1;
}
const char* imagepath = argv[1];
cv::Mat m = cv::imread(imagepath, 1);
if (m.empty())
{
fprintf(stderr, "cv::imread %s failed\n", imagepath);
return -1;
}
#if NCNN_VULKAN
ncnn::create_gpu_instance();
#endif // NCNN_VULKAN
// 初始化
ncnn::Net mobilenet;
mobilenet_v2_init(mobilenet);
std::vector<Object> objects;
detect_mobilenet(mobilenet,m, objects);
#if NCNN_VULKAN
ncnn::destroy_gpu_instance();
#endif // NCNN_VULKAN
draw_objects(m, objects);
return 0;
}
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// #include <io.h>
#include <stdio.h>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "platform.h"
#include "net.h"
#if NCNN_VULKAN
#include "gpu.h"
#endif // NCNN_VULKAN
#include "httplib.h"
using namespace httplib;
struct Object
{
cv::Rect_<float> rect;
int label;
float prob;
};
static int g_loop_count = 4;
void benchmark(const char* comment, void (*init)(ncnn::Net&), void (*run)(const ncnn::Net&))
{
// ncnn::Net net;
// init(net);
// net.load_model();
// run(net);
// double time_min = DBL_MAX;
// double time_max = -DBL_MAX;
// double time_avg = 0;
// // for (int i=0; i<g_loop_count; i++)
// // {
// // // double start = ncnn::get_current_time();
// // run(net);
// // // double end = ncnn::get_current_time();
// // // double time = end - start;
// // time_min = std::min(time_min, time);
// // time_max = std::max(time_max, time);
// // time_avg += time;
// // }
// time_avg /= g_loop_count;
// fprintf(stderr, "%-20s min = %7.2f max = %7.2f avg = %7.2f\n", comment, time_min, time_max, time_avg);
}
void mobilenet_v2_init(ncnn::Net& mobilenet)
{
// net.load_param("mobilenet_v2.param");
mobilenet.load_param("mobilenet_ssd_voc_ncnn.param");
mobilenet.load_model("mobilenet_ssd_voc_ncnn.bin");
}
void mobilenet_v2_run(const ncnn::Net& net)
{
ncnn::Extractor ex = net.create_extractor();
ncnn::Mat in(224, 224, 3);
ex.input("data", in);
ncnn::Mat out;
ex.extract("prob", out);
}
static int detect_mobilenet(ncnn::Net& net,const cv::Mat& bgr, std::vector<Object>& objects)
{
// ncnn::Net mobilenet;
// #if NCNN_VULKAN
// mobilenet.opt.use_vulkan_compute = true;
// #endif // NCNN_VULKAN
// model is converted from https://github.com/chuanqi305/MobileNet-SSD
// and can be downloaded from https://drive.google.com/open?id=0ByaKLD9QaPtucWk0Y0dha1VVY0U
// net.load_param("mobilenet_ssd_voc_ncnn.param");
// net.load_model("mobilenet_ssd_voc_ncnn.bin");
int target_size = 300;
int img_w = bgr.cols;
int img_h = bgr.rows;
fprintf(stdout, "1. img\n");
ncnn::Mat in = ncnn::Mat::from_pixels_resize(bgr.data, ncnn::Mat::PIXEL_BGR, bgr.cols, bgr.rows, target_size, target_size);
fprintf(stdout, "2. Mat\n");
const float mean_vals[3] = {127.5f, 127.5f, 127.5f};
const float norm_vals[3] = {1.0/127.5,1.0/127.5,1.0/127.5};
in.substract_mean_normalize(mean_vals, norm_vals);
fprintf(stdout, "3. Extractor\n");
ncnn::Extractor ex = net.create_extractor();
// ex.set_num_threads(4);
ex.input("data", in);
ncnn::Mat out;
ex.extract("detection_out",out);
// pFrame=NULL
// printf("%d %d %d\n", out.w, out.h, out.c);
objects.clear();
for (int i=0; i<out.h; i++)
{
const float* values = out.row(i);
Object object;
object.label = values[0];
object.prob = values[1];
object.rect.x = values[2] * img_w;
object.rect.y = values[3] * img_h;
object.rect.width = values[4] * img_w - object.rect.x;
object.rect.height = values[5] * img_h - object.rect.y;
objects.push_back(object);
}
//
// return 0;
}
static void draw_objects(const cv::Mat& bgr, const std::vector<Object>& objects)
{
static const char* class_names[] = {"background",
"aeroplane", "bicycle", "bird", "boat",
"bottle", "bus", "car", "cat", "chair",
"cow", "diningtable", "dog", "horse",
"motorbike", "person", "pottedplant",
"sheep", "sofa", "train", "tvmonitor"};
cv::Mat image = bgr.clone();
for (size_t i = 0; i < objects.size(); i++)
{
const Object& obj = objects[i];
fprintf(stderr, "%d = %.5f at %.2f %.2f %.2f x %.2f\n", obj.label, obj.prob,
obj.rect.x, obj.rect.y, obj.rect.width, obj.rect.height);
cv::rectangle(image, obj.rect, cv::Scalar(255, 0, 0));
char text[256];
sprintf(text, "%s %.1f%%", class_names[obj.label], obj.prob * 100);
int baseLine = 0;
cv::Size label_size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
int x = obj.rect.x;
int y = obj.rect.y - label_size.height - baseLine;
if (y < 0)
y = 0;
if (x + label_size.width > image.cols)
x = image.cols - label_size.width;
cv::rectangle(image, cv::Rect(cv::Point(x, y),
cv::Size(label_size.width, label_size.height + baseLine)),
cv::Scalar(255, 255, 255), -1);
cv::putText(image, text, cv::Point(x, y + label_size.height),
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
}
cv::imshow("image", image);
cv::waitKey(0);
}
int main(int argc, char** argv)
{
// if (argc != 2)
// {
// fprintf(stderr, "Usage: %s [imagepath]\n", argv[0]);
// return -1;
// }
// const char* imagepath = argv[1];
// cv::Mat m = cv::imread(imagepath, 1);
// if (m.empty())
// {
// fprintf(stderr, "cv::imread %s failed\n", imagepath);
// return -1;
// }
#if NCNN_VULKAN
ncnn::create_gpu_instance();
#endif // NCNN_VULKAN
// 初始化
Server svr;
ncnn::Net mobilenet;
mobilenet_v2_init(mobilenet);
cv::Mat m ;
char buf[BUFSIZ];
std::vector<Object> objects;
svr.Get(R"(.*)", [&](const Request &req, Response &res) {
snprintf(buf, sizeof(buf), "%s %s %s", req.method.c_str(),
req.version.c_str(), req.path.c_str());
const char *fname = req.path.c_str();
fprintf(stdout, "cv::imread %s \n", fname);
m = cv::imread("/Users/pytool/ncnn/MobileNet-SSD/a.jpg", 1);
fprintf(stdout, "1. img\n");
if (m.empty())
{
fprintf(stdout, "cv::imread %s failed\n", fname);
return -1;
}
detect_mobilenet(mobilenet,m, objects);
fprintf(stdout, "检测 %s \n", fname);
// #if NCNN_VULKAN
// ncnn::destroy_gpu_instance();
// #endif // NCNN_VULKAN
draw_objects(m, objects);
res.set_content(buf, "text/plain");
});
svr.listen("localhost", 8080);
return 0;
}
void Loop(){
std::string s;
s += "================================\n";
}
//refer to official demo,add load_labels to display classification
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "platform.h"
#include "net.h"
using namespace std;
using namespace cv;
static int detect_squeezenet(const cv::Mat& bgr, std::vector<float>& cls_scores)
{
ncnn::Net squeezenet;
#if NCNN_VULKAN
squeezenet.opt.use_vulkan_compute = true;
#endif // NCNN_VULKAN
squeezenet.load_param("mobilenetv2.param");
squeezenet.load_model("mobilenetv2.bin");
ncnn::Mat in = ncnn::Mat::from_pixels_resize(bgr.data, ncnn::Mat::PIXEL_BGR, bgr.cols, bgr.rows, 227, 227);
const float mean_vals[3] = {104.f, 117.f, 123.f};
in.substract_mean_normalize(mean_vals, 0);
ncnn::Extractor ex = squeezenet.create_extractor();
ex.input("data", in);
ncnn::Mat out;
ex.extract("prob", out);
cls_scores.resize(out.w);
for (int j=0; j<out.w; j++)
{
cls_scores[j] = out[j];
}
return 0;
}
//添加load labels函数,读取synset_words.txt
static int load_labels(string path, std::vector<string>& labels)
{
FILE* fp = fopen(path.c_str(), "r");
while (!feof(fp))
{
char str[1024];
fgets(str, 1024, fp);
string str_s(str);
if (str_s.length() > 0)
{
for (int i = 0; i < str_s.length(); i++)
{
if (str_s[i] == ' ')
{
string strr = str_s.substr(i, str_s.length() - i - 1);
labels.push_back(strr);
i = str_s.length();
}
}
}
}
return 0;
}
static int print_topk(const cv::Mat& bgr,const std::vector<float>& cls_scores, int topk)
{
//load labels
cv::Mat image = bgr.clone();
vector<string> labels;
vector<int> index_result;
load_labels("synset.txt", labels);
// partial sort topk with index
int size = cls_scores.size();
std::vector< std::pair<float, int> > vec;
vec.resize(size);
for (int i=0; i<size; i++)
{
vec[i] = std::make_pair(cls_scores[i], i);
}
std::partial_sort(vec.begin(), vec.begin() + topk, vec.end(),
std::greater< std::pair<float, int> >());
// print topk and score
for (int i=0; i<topk; i++)
{
float score = vec[i].first;
int index = vec[i].second;
//fprintf(stderr, "%d = %f\n", index, score);
index_result.push_back(index);
fprintf(stderr, "%d = %f (%s)\n", index, score, labels[index].c_str());
}
//在图片上标注类别信息
for (int i = 0;i<index_result.size()-2;i++)
{
cv::putText(image, labels[index_result[i]], Point(50, 50 + 30 * i), CV_FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 255,255), 2, 8);
}
// imshow("image", image);
imwrite("squezenet_new.jpg", image);
waitKey(0);
return 0;
}
int main(int argc, char** argv)
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s [imagepath]\n", argv[0]);
return -1;
}
const char* imagepath = argv[1];
cv::Mat m = cv::imread(imagepath, 1);
if (m.empty())
{
fprintf(stderr, "cv::imread %s failed\n", imagepath);
return -1;
}
std::vector<float> cls_scores;
detect_squeezenet(m, cls_scores);
print_topk(m,cls_scores, 3);
return 0;
}