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. 检测服务

  1. Cmakefiles.txt 增加c++14 支持
    add_compile_options(-std=c++14 -fexceptions)

  2. 添加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;
}

`