diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ecb70885b..664459997 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -17,6 +17,7 @@ if(OpenCV_FOUND) include_directories(${CMAKE_CURRENT_BINARY_DIR}/../src) ncnn_add_example(squeezenet) + ncnn_add_example(squeezenet_c_api) ncnn_add_example(fasterrcnn) ncnn_add_example(rfcn) ncnn_add_example(yolov2) diff --git a/examples/squeezenet_c_api.cpp b/examples/squeezenet_c_api.cpp new file mode 100644 index 000000000..2fe268a05 --- /dev/null +++ b/examples/squeezenet_c_api.cpp @@ -0,0 +1,117 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2020 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 "c_api.h" + +#include +#include +#include +#include +#include + +static int detect_squeezenet(const cv::Mat& bgr, std::vector& cls_scores) +{ + ncnn_net_t squeezenet = ncnn_net_create(); + + ncnn_option_t opt = ncnn_option_create(); + ncnn_option_set_use_vulkan_compute(opt, 1); + + ncnn_net_set_option(squeezenet, opt); + + // the ncnn model https://github.com/nihui/ncnn-assets/tree/master/models + ncnn_net_load_param(squeezenet, "squeezenet_v1.1.param"); + ncnn_net_load_model(squeezenet, "squeezenet_v1.1.bin"); + + ncnn_mat_t in = ncnn_mat_from_pixels_resize(bgr.data, NCNN_MAT_PIXEL_BGR, bgr.cols, bgr.rows, bgr.cols * 3, 227, 227); + + const float mean_vals[3] = {104.f, 117.f, 123.f}; + ncnn_mat_substract_mean_normalize(in, mean_vals, 0); + + ncnn_extractor_t ex = ncnn_extractor_create(squeezenet); + + ncnn_extractor_input(ex, "data", in); + + ncnn_mat_t out; + ncnn_extractor_extract(ex, "prob", &out); + + const int out_w = ncnn_mat_get_w(out); + const float* out_data = (const float*)ncnn_mat_get_data(out); + + cls_scores.resize(out_w); + for (int j = 0; j < out_w; j++) + { + cls_scores[j] = out_data[j]; + } + + ncnn_mat_destroy(in); + ncnn_mat_destroy(out); + + ncnn_extractor_destroy(ex); + + ncnn_option_destroy(opt); + + ncnn_net_destroy(squeezenet); + + return 0; +} + +static int print_topk(const std::vector& cls_scores, int topk) +{ + // partial sort topk with index + int size = cls_scores.size(); + std::vector > 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 >()); + + // 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); + } + + 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 cls_scores; + detect_squeezenet(m, cls_scores); + + print_topk(cls_scores, 3); + + return 0; +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4b69ab090..bea9fe38d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,6 +23,7 @@ set(ncnn_SRCS allocator.cpp benchmark.cpp blob.cpp + c_api.cpp command.cpp cpu.cpp datareader.cpp @@ -425,6 +426,7 @@ if(NCNN_INSTALL_SDK) install(FILES allocator.h blob.h + c_api.h command.h cpu.h datareader.h diff --git a/src/c_api.cpp b/src/c_api.cpp new file mode 100644 index 000000000..34224b6aa --- /dev/null +++ b/src/c_api.cpp @@ -0,0 +1,372 @@ +/* Tencent is pleased to support the open source community by making ncnn available. + * + * Copyright (C) 2020 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 "c_api.h" + +#include "mat.h" +#include "option.h" +#include "net.h" + +using ncnn::Blob; +using ncnn::Extractor; +using ncnn::Layer; +using ncnn::Mat; +using ncnn::Net; +using ncnn::Option; + +#ifdef __cplusplus +extern "C" { +#endif + +/* mat api */ +ncnn_mat_t ncnn_mat_create() +{ + return (ncnn_mat_t)(new Mat()); +} + +ncnn_mat_t ncnn_mat_create_1d(int w) +{ + return (ncnn_mat_t)(new Mat(w)); +} + +ncnn_mat_t ncnn_mat_create_2d(int w, int h) +{ + return (ncnn_mat_t)(new Mat(w, h)); +} + +ncnn_mat_t ncnn_mat_create_3d(int w, int h, int c) +{ + return (ncnn_mat_t)(new Mat(w, h, c)); +} + +ncnn_mat_t ncnn_mat_create_1d_packed(int w, size_t elemsize, int elempack) +{ + return (ncnn_mat_t)(new Mat(w, elemsize, elempack)); +} + +ncnn_mat_t ncnn_mat_create_2d_packed(int w, int h, size_t elemsize, int elempack) +{ + return (ncnn_mat_t)(new Mat(w, h, elemsize, elempack)); +} + +ncnn_mat_t ncnn_mat_create_3d_packed(int w, int h, int c, size_t elemsize, int elempack) +{ + return (ncnn_mat_t)(new Mat(w, h, c, elemsize, elempack)); +} + +void ncnn_mat_destroy(ncnn_mat_t mat) +{ + delete (Mat*)mat; +} + +int ncnn_mat_get_dims(ncnn_mat_t mat) +{ + return ((Mat*)mat)->dims; +} + +int ncnn_mat_get_w(ncnn_mat_t mat) +{ + return ((Mat*)mat)->w; +} + +int ncnn_mat_get_h(ncnn_mat_t mat) +{ + return ((Mat*)mat)->h; +} + +int ncnn_mat_get_c(ncnn_mat_t mat) +{ + return ((Mat*)mat)->c; +} + +size_t ncnn_mat_get_elemsize(ncnn_mat_t mat) +{ + return ((Mat*)mat)->elemsize; +} + +int ncnn_mat_get_elempack(ncnn_mat_t mat) +{ + return ((Mat*)mat)->elempack; +} + +size_t ncnn_mat_get_cstep(ncnn_mat_t mat) +{ + return ((Mat*)mat)->cstep; +} + +void* ncnn_mat_get_data(ncnn_mat_t mat) +{ + return ((Mat*)mat)->data; +} + +/* mat pixel api */ +ncnn_mat_t ncnn_mat_from_pixels(const unsigned char* pixels, int type, int w, int h, int stride) +{ + return (ncnn_mat_t)(new Mat(Mat::from_pixels(pixels, type, w, h, stride))); +} + +ncnn_mat_t ncnn_mat_from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height) +{ + return (ncnn_mat_t)(new Mat(Mat::from_pixels_resize(pixels, type, w, h, stride, target_width, target_height))); +} + +void ncnn_mat_to_pixels(ncnn_mat_t mat, unsigned char* pixels, int type, int stride) +{ + ((Mat*)mat)->to_pixels(pixels, type, stride); +} + +void ncnn_mat_to_pixels_resize(ncnn_mat_t mat, unsigned char* pixels, int type, int target_width, int target_height, int target_stride) +{ + ((Mat*)mat)->to_pixels_resize(pixels, type, target_width, target_height, target_stride); +} + +void ncnn_mat_substract_mean_normalize(ncnn_mat_t mat, const float* mean_vals, const float* norm_vals) +{ + ((Mat*)mat)->substract_mean_normalize(mean_vals, norm_vals); +} + +/* option api */ +ncnn_option_t ncnn_option_create() +{ + return (ncnn_option_t)(new Option()); +} + +void ncnn_option_destroy(ncnn_option_t opt) +{ + delete (Option*)opt; +} + +int ncnn_option_get_num_threads(ncnn_option_t opt) +{ + return ((Option*)opt)->num_threads; +} + +void ncnn_option_set_num_threads(ncnn_option_t opt, int num_threads) +{ + ((Option*)opt)->num_threads = num_threads; +} + +int ncnn_option_get_use_vulkan_compute(ncnn_option_t opt) +{ +#if NCNN_VULKAN + return ((Option*)opt)->use_vulkan_compute; +#else + return 0; +#endif +} + +void ncnn_option_set_use_vulkan_compute(ncnn_option_t opt, int use_vulkan_compute) +{ +#if NCNN_VULKAN + ((Option*)opt)->use_vulkan_compute = use_vulkan_compute; +#else + (void)opt; + (void)use_vulkan_compute; +#endif +} + +/* blob api */ +const char* ncnn_blob_get_name(ncnn_blob_t blob) +{ +#if NCNN_STRING + return ((Blob*)blob)->name.c_str(); +#else + return ""; +#endif +} + +int ncnn_blob_get_producer(ncnn_blob_t blob) +{ + return ((Blob*)blob)->producer; +} + +int ncnn_blob_get_consumer_count(ncnn_blob_t blob) +{ + return (int)((Blob*)blob)->consumers.size(); +} + +int ncnn_blob_get_consumer(ncnn_blob_t blob, int i) +{ + return ((Blob*)blob)->consumers[i]; +} + +void ncnn_blob_get_shape(ncnn_blob_t blob, int* dims, int* w, int* h, int* c) +{ + const Mat& shape = ((Blob*)blob)->shape; + *dims = shape.dims; + *w = shape.w; + *h = shape.h; + *c = shape.c; +} + +/* layer api */ +const char* ncnn_layer_get_name(ncnn_layer_t layer) +{ +#if NCNN_STRING + return ((Layer*)layer)->name.c_str(); +#else + return ""; +#endif +} + +int ncnn_layer_get_typeindex(ncnn_layer_t layer) +{ + return ((Layer*)layer)->typeindex; +} + +const char* ncnn_layer_get_type(ncnn_layer_t layer) +{ +#if NCNN_STRING + return ((Layer*)layer)->type.c_str(); +#else + return ""; +#endif +} + +int ncnn_layer_get_bottom_count(ncnn_layer_t layer) +{ + return (int)((Layer*)layer)->bottoms.size(); +} + +int ncnn_layer_get_bottom(ncnn_layer_t layer, int i) +{ + return ((Layer*)layer)->bottoms[i]; +} + +int ncnn_layer_get_top_count(ncnn_layer_t layer) +{ + return (int)((Layer*)layer)->tops.size(); +} + +int ncnn_layer_get_top(ncnn_layer_t layer, int i) +{ + return ((Layer*)layer)->tops[i]; +} + +void ncnn_blob_get_bottom_shape(ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c) +{ + const Mat& shape = ((Layer*)layer)->bottom_shapes[i]; + *dims = shape.dims; + *w = shape.w; + *h = shape.h; + *c = shape.c; +} + +void ncnn_blob_get_top_shape(ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c) +{ + const Mat& shape = ((Layer*)layer)->top_shapes[i]; + *dims = shape.dims; + *w = shape.w; + *h = shape.h; + *c = shape.c; +} + +/* net api */ +ncnn_net_t ncnn_net_create() +{ + return (ncnn_net_t)(new Net); +} + +void ncnn_net_destroy(ncnn_net_t net) +{ + delete (Net*)net; +} + +void ncnn_net_set_option(ncnn_net_t net, ncnn_option_t opt) +{ + ((Net*)net)->opt = *((Option*)opt); +} + +int ncnn_net_load_param(ncnn_net_t net, const char* path) +{ +#if NCNN_STDIO && NCNN_STRING + return ((Net*)net)->load_param(path); +#else + return -1; +#endif +} + +int ncnn_net_load_model(ncnn_net_t net, const char* path) +{ +#if NCNN_STDIO && NCNN_STRING + return ((Net*)net)->load_model(path); +#else + return -1; +#endif +} + +int ncnn_net_get_layer_count(ncnn_net_t net) +{ + return (int)((Net*)net)->layers.size(); +} + +ncnn_layer_t ncnn_net_get_layer(ncnn_net_t net, int i) +{ + return (ncnn_layer_t)((Net*)net)->layers[i]; +} + +int ncnn_net_get_blob_count(ncnn_net_t net) +{ + return (int)((Net*)net)->blobs.size(); +} + +ncnn_blob_t ncnn_net_get_blob(ncnn_net_t net, int i) +{ + return (ncnn_blob_t) & ((Net*)net)->blobs[i]; +} + +/* extractor api */ +ncnn_extractor_t ncnn_extractor_create(ncnn_net_t net) +{ + return (ncnn_extractor_t)(new Extractor(((Net*)net)->create_extractor())); +} + +void ncnn_extractor_destroy(ncnn_extractor_t ex) +{ + delete (Extractor*)ex; +} + +void ncnn_extractor_set_option(ncnn_extractor_t ex, ncnn_option_t opt) +{ + ((Extractor*)ex)->set_num_threads(((Option*)opt)->num_threads); +#if NCNN_VULKAN + ((Extractor*)ex)->set_vulkan_compute(((Option*)opt)->use_vulkan_compute); +#endif +} + +int ncnn_extractor_input(ncnn_extractor_t ex, const char* name, ncnn_mat_t mat) +{ +#if NCNN_STRING + return ((Extractor*)ex)->input(name, *((Mat*)mat)); +#else + return -1; +#endif +} + +int ncnn_extractor_extract(ncnn_extractor_t ex, const char* name, ncnn_mat_t* mat) +{ +#if NCNN_STRING + Mat mat0; + int ret = ((Extractor*)ex)->extract(name, mat0); + *mat = (ncnn_mat_t)(new Mat(mat0)); + return ret; +#else + return -1; +#endif +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif diff --git a/src/c_api.h b/src/c_api.h new file mode 100644 index 000000000..1ed4b7f05 --- /dev/null +++ b/src/c_api.h @@ -0,0 +1,130 @@ +/* Tencent is pleased to support the open source community by making ncnn available. + * + * Copyright (C) 2020 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. + */ + +#ifndef NCNN_C_API_H +#define NCNN_C_API_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* mat api */ +typedef struct __ncnn_mat_t* ncnn_mat_t; + +ncnn_mat_t ncnn_mat_create(); +ncnn_mat_t ncnn_mat_create_1d(int w); +ncnn_mat_t ncnn_mat_create_2d(int w, int h); +ncnn_mat_t ncnn_mat_create_3d(int w, int h, int c); +ncnn_mat_t ncnn_mat_create_1d_packed(int w, size_t elemsize, int elempack); +ncnn_mat_t ncnn_mat_create_2d_packed(int w, int h, size_t elemsize, int elempack); +ncnn_mat_t ncnn_mat_create_3d_packed(int w, int h, int c, size_t elemsize, int elempack); +void ncnn_mat_destroy(ncnn_mat_t mat); + +int ncnn_mat_get_dims(ncnn_mat_t mat); +int ncnn_mat_get_w(ncnn_mat_t mat); +int ncnn_mat_get_h(ncnn_mat_t mat); +int ncnn_mat_get_c(ncnn_mat_t mat); +size_t ncnn_mat_get_elemsize(ncnn_mat_t mat); +int ncnn_mat_get_elempack(ncnn_mat_t mat); +size_t ncnn_mat_get_cstep(ncnn_mat_t mat); +void* ncnn_mat_get_data(ncnn_mat_t mat); + +/* mat pixel api */ +#define NCNN_MAT_PIXEL_RGB 1 +#define NCNN_MAT_PIXEL_BGR 2 +#define NCNN_MAT_PIXEL_GRAY 3 +#define NCNN_MAT_PIXEL_RGBA 4 +#define NCNN_MAT_PIXEL_BGRA 5 +#define NCNN_MAT_PIXEL_X2Y(X, Y) (X | (Y << 16)) +ncnn_mat_t ncnn_mat_from_pixels(const unsigned char* pixels, int type, int w, int h, int stride); +ncnn_mat_t ncnn_mat_from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height); +void ncnn_mat_to_pixels(ncnn_mat_t mat, unsigned char* pixels, int type, int stride); +void ncnn_mat_to_pixels_resize(ncnn_mat_t mat, unsigned char* pixels, int type, int target_width, int target_height, int target_stride); + +void ncnn_mat_substract_mean_normalize(ncnn_mat_t mat, const float* mean_vals, const float* norm_vals); + +/* option api */ +typedef struct __ncnn_option_t* ncnn_option_t; + +ncnn_option_t ncnn_option_create(); +void ncnn_option_destroy(ncnn_option_t opt); + +int ncnn_option_get_num_threads(ncnn_option_t opt); +void ncnn_option_set_num_threads(ncnn_option_t opt, int num_threads); + +int ncnn_option_get_use_vulkan_compute(ncnn_option_t opt); +void ncnn_option_set_use_vulkan_compute(ncnn_option_t opt, int use_vulkan_compute); + +/* blob api */ +typedef struct __ncnn_blob_t* ncnn_blob_t; + +const char* ncnn_blob_get_name(ncnn_blob_t blob); + +int ncnn_blob_get_producer(ncnn_blob_t blob); +int ncnn_blob_get_consumer_count(ncnn_blob_t blob); +int ncnn_blob_get_consumer(ncnn_blob_t blob, int i); + +void ncnn_blob_get_shape(ncnn_blob_t blob, int* dims, int* w, int* h, int* c); + +/* layer api */ +typedef struct __ncnn_layer_t* ncnn_layer_t; + +const char* ncnn_layer_get_name(ncnn_layer_t layer); + +int ncnn_layer_get_typeindex(ncnn_layer_t layer); +const char* ncnn_layer_get_type(ncnn_layer_t layer); + +int ncnn_layer_get_bottom_count(ncnn_layer_t layer); +int ncnn_layer_get_bottom(ncnn_layer_t layer, int i); +int ncnn_layer_get_top_count(ncnn_layer_t layer); +int ncnn_layer_get_top(ncnn_layer_t layer, int i); + +void ncnn_blob_get_bottom_shape(ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); +void ncnn_blob_get_top_shape(ncnn_layer_t layer, int i, int* dims, int* w, int* h, int* c); + +/* net api */ +typedef struct __ncnn_net_t* ncnn_net_t; + +ncnn_net_t ncnn_net_create(); +void ncnn_net_destroy(ncnn_net_t net); + +void ncnn_net_set_option(ncnn_net_t net, ncnn_option_t opt); + +int ncnn_net_load_param(ncnn_net_t net, const char* path); +int ncnn_net_load_model(ncnn_net_t net, const char* path); + +int ncnn_net_get_layer_count(ncnn_net_t net); +ncnn_layer_t ncnn_net_get_layer(ncnn_net_t net, int i); +int ncnn_net_get_blob_count(ncnn_net_t net); +ncnn_blob_t ncnn_net_get_blob(ncnn_net_t net, int i); + +/* extractor api */ +typedef struct __ncnn_extractor_t* ncnn_extractor_t; + +ncnn_extractor_t ncnn_extractor_create(ncnn_net_t net); +void ncnn_extractor_destroy(ncnn_extractor_t ex); + +void ncnn_extractor_set_option(ncnn_extractor_t ex, ncnn_option_t opt); + +int ncnn_extractor_input(ncnn_extractor_t ex, const char* name, ncnn_mat_t mat); +int ncnn_extractor_extract(ncnn_extractor_t ex, const char* name, ncnn_mat_t* mat); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // NCNN_C_API_H diff --git a/src/net.h b/src/net.h index 93b0a3bd9..c450c3b92 100644 --- a/src/net.h +++ b/src/net.h @@ -123,6 +123,10 @@ public: // construct an Extractor from network Extractor create_extractor() const; +public: + std::vector blobs; + std::vector layers; + protected: // parse the structure of network // fuse int8 op dequantize and quantize by requantize @@ -154,9 +158,6 @@ protected: #endif // NCNN_VULKAN protected: - std::vector blobs; - std::vector layers; - std::vector custom_layer_registry; #if NCNN_VULKAN