diff --git a/inference/demo.cpp b/inference/demo.cpp index 657d4f4244069d0a59c4dee7827d047a375f2741..2202b31b739bf18682fdf468b36ffe4e9e434726 100644 --- a/inference/demo.cpp +++ b/inference/demo.cpp @@ -1,3 +1,17 @@ +// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 #include #include @@ -9,7 +23,8 @@ int main(int argc, char** argv) { // 0. parse args google::ParseCommandLineFlags(&argc, &argv, true); if (FLAGS_conf.empty() || FLAGS_input_dir.empty()) { - std::cout << "Usage: ./predictor --conf=/config/path/to/your/model --input_dir=/directory/of/your/input/images"; + std::cout << "Usage: ./predictor --conf=/config/path/to/your/model " + << "--input_dir=/directory/of/your/input/images"; return -1; } // 1. create a predictor and init it with conf @@ -20,7 +35,8 @@ int main(int argc, char** argv) { } // 2. get all the images with extension '.jpeg' at input_dir - auto imgs = PaddleSolution::utils::get_directory_images(FLAGS_input_dir, ".jpeg|.jpg"); + auto imgs = PaddleSolution::utils::get_directory_images(FLAGS_input_dir, + ".jpeg|.jpg"); // 3. predict predictor.predict(imgs); return 0; diff --git a/inference/docs/linux_build.md b/inference/docs/linux_build.md index 613317c5279a142df3990acb20c60fb424be046f..75a16bbea7499eaa007884b0b1f16126eacca56a 100644 --- a/inference/docs/linux_build.md +++ b/inference/docs/linux_build.md @@ -6,7 +6,8 @@ ## 前置条件 * G++ 4.8.2 ~ 4.9.4 * CMake 3.0+ -* CUDA 8.0 / CUDA 9.0 / CUDA 10.0, cudnn 7+ (仅在使用GPU版本的预测库时需要) +* CUDA 9.0 / CUDA 10.0, cudnn 7+ (仅在使用GPU版本的预测库时需要) +* CentOS 7.6, Ubuntu 16.04, Ubuntu 18.04 (均在以上系统验证过) 请确保系统已经安装好上述基本软件,**下面所有示例以工作目录为 `/root/projects/`演示**。 @@ -20,17 +21,16 @@ ### Step2: 下载PaddlePaddle C++ 预测库 fluid_inference -PaddlePaddle C++ 预测库主要分为CPU版本和GPU版本。其中,针对不同的CUDA版本,GPU版本预测库又分为三个版本预测库:CUDA 8、CUDA 9和CUDA 10版本预测库。以下为各版本C++预测库的下载链接: +PaddlePaddle C++ 预测库主要分为CPU版本和GPU版本。其中,针对不同的CUDA版本,GPU版本预测库又分为两个版本预测库:CUDA 9.0和CUDA 10.0版本预测库。以下为各版本C++预测库的下载链接: | 版本 | 链接 | | ---- | ---- | -| CPU版本 | [fluid_inference.tgz](https://paddle-inference-lib.bj.bcebos.com/latest-cpu-avx-mkl/fluid_inference.tgz) | -| CUDA 8版本 | [fluid_inference.tgz](https://paddle-inference-lib.bj.bcebos.com/latest-gpu-cuda8-cudnn7-avx-mkl/fluid_inference.tgz) | -| CUDA 9版本 | [fluid_inference.tgz](https://paddle-inference-lib.bj.bcebos.com/latest-gpu-cuda9-cudnn7-avx-mkl/fluid_inference.tgz) | -| CUDA 10版本 | [fluid_inference.tgz](https://paddle-inference-lib.bj.bcebos.com/latest-gpu-cuda10-cudnn7-avx-mkl/fluid_inference.tgz) | +| CPU版本 | [fluid_inference.tgz](https://bj.bcebos.com/paddlehub/paddle_inference_lib/fluid_inference_linux_cpu_1.6.1.tgz) | +| CUDA 9.0版本 | [fluid_inference.tgz](https://bj.bcebos.com/paddlehub/paddle_inference_lib/fluid_inference_linux_cuda97_1.6.1.tgz) | +| CUDA 10.0版本 | [fluid_inference.tgz](https://bj.bcebos.com/paddlehub/paddle_inference_lib/fluid_inference_linux_cuda10_1.6.1.tgz) | -针对不同的CPU类型、不同的指令集,官方提供更多可用的预测库版本,目前已经推出1.6版本的预测库,具体请参考以下链接:[C++预测库下载列表](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/advanced_usage/deploy/inference/build_and_install_lib_cn.html) +针对不同的CPU类型、不同的指令集,官方提供更多可用的预测库版本,目前已经推出1.6版本的预测库。其余版本具体请参考以下链接:[C++预测库下载列表](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/advanced_usage/deploy/inference/build_and_install_lib_cn.html) 下载并解压后`/root/projects/fluid_inference`目录包含内容为: @@ -63,7 +63,7 @@ make install ### Step4: 编译 -`CMake`编译时,涉及到四个编译参数用于指定核心依赖库的路径, 他们的定义如下:(带*表示仅在使用**GPU版本**预测库时指定) +`CMake`编译时,涉及到四个编译参数用于指定核心依赖库的路径, 他们的定义如下:(带*表示仅在使用**GPU版本**预测库时指定,其中CUDA库版本尽量对齐,**使用9.0、10.0版本,不使用9.2、10.1版本CUDA库**) | 参数名 | 含义 | | ---- | ---- | @@ -84,6 +84,7 @@ make 在使用**CPU版本**预测库进行编译时,可执行下列操作。 ```shell cd /root/projects/PaddleSeg/inference + mkdir build && cd build cmake .. -DWITH_GPU=OFF -DPADDLE_DIR=/root/projects/fluid_inference -DOPENCV_DIR=/root/projects/opencv3/ -DWITH_STATIC_LIB=OFF make @@ -97,4 +98,4 @@ make ./demo --conf=/path/to/your/conf --input_dir=/path/to/your/input/data/directory ``` -更详细说明请参考README文档: [预测和可视化部分](../README.md) +更详细说明请参考README文档: [预测和可视化部分](../README.md) \ No newline at end of file diff --git a/inference/docs/windows_vs2015_build.md b/inference/docs/windows_vs2015_build.md index 360e70558d06765863bab0d0ae652847befbabd4..f0c96a18b1204b434653be8cd29dce57d229d10c 100644 --- a/inference/docs/windows_vs2015_build.md +++ b/inference/docs/windows_vs2015_build.md @@ -5,7 +5,7 @@ ## 前置条件 * Visual Studio 2015 -* CUDA 8.0/ CUDA 9.0/ CUDA 10.0,cudnn 7+ (仅在使用GPU版本的预测库时需要) +* CUDA 9.0 / CUDA 10.0,cudnn 7+ (仅在使用GPU版本的预测库时需要) * CMake 3.0+ 请确保系统已经安装好上述基本软件,**下面所有示例以工作目录为 `D:\projects`演示**。 @@ -20,14 +20,13 @@ ### Step2: 下载PaddlePaddle C++ 预测库 fluid_inference -PaddlePaddle C++ 预测库主要分为两大版本:CPU版本和GPU版本。其中,针对不同的CUDA版本,GPU版本预测库又分为三个版本预测库:CUDA 8、CUDA 9和CUDA 10版本预测库。根据Windows环境,下载相应版本的PaddlePaddle预测库,并解压到`D:\projects\`目录。以下为各版本C++预测库(CUDA 8版本基于1.5版本的预测库,其余均基于1.6版本的预测库)的下载链接: +PaddlePaddle C++ 预测库主要分为两大版本:CPU版本和GPU版本。其中,针对不同的CUDA版本,GPU版本预测库又分为两个版本预测库:CUDA 9.0和CUDA 10.0版本预测库。根据Windows环境,下载相应版本的PaddlePaddle预测库,并解压到`D:\projects\`目录。以下为各版本C++预测库的下载链接: | 版本 | 链接 | | ---- | ---- | -| CPU版本 | [fluid_inference_install_dir.zip](https://paddle-wheel.bj.bcebos.com/1.6.0/win-infer/mkl/cpu/fluid_inference_install_dir.zip) | -| CUDA 8版本 | [fluid_inference_install_dir.zip](https://paddle-inference-lib.bj.bcebos.com/1.5.1-win/gpu_mkl_avx_8.0/fluid_inference_install_dir.zip) | -| CUDA 9版本 | [fluid_inference_install_dir.zip](https://paddle-wheel.bj.bcebos.com/1.6.0/win-infer/mkl/post97/fluid_inference_install_dir.zip) | -| CUDA 10版本 | [fluid_inference_install_dir.zip](https://paddle-wheel.bj.bcebos.com/1.6.0/win-infer/mkl/post107/fluid_inference_install_dir.zip) | +| CPU版本 | [fluid_inference_install_dir.zip](https://bj.bcebos.com/paddlehub/paddle_inference_lib/fluid_install_dir_win_cpu_1.6.zip) | +| CUDA 9.0版本 | [fluid_inference_install_dir.zip](https://bj.bcebos.com/paddlehub/paddle_inference_lib/fluid_inference_install_dir_win_cuda9_1.6.1.zip) | +| CUDA 10.0版本 | [fluid_inference_install_dir.zip](https://bj.bcebos.com/paddlehub/paddle_inference_lib/fluid_inference_install_dir_win_cuda10_1.6.1.zip) | 解压后`D:\projects\fluid_inference`目录包含内容为: ``` @@ -59,31 +58,36 @@ fluid_inference call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64 ``` -* CMAKE编译工程 (带*表示仅在使用**GPU版本**预测库时指定) - * PADDLE_DIR: fluid_inference预测库路径 - * *CUDA_LIB: CUDA动态库目录, 请根据实际安装情况调整 - * OPENCV_DIR: OpenCV解压目录 +三个编译参数的含义说明如下(带*表示仅在使用**GPU版本**预测库时指定, 其中CUDA库版本尽量对齐,**使用9.0、10.0版本,不使用9.2、10.1等版本CUDA库**): -在使用**GPU版本**预测库进行编译时,可执行下列操作。 -``` +| 参数名 | 含义 | +| ---- | ---- | +| *CUDA_LIB | CUDA的库路径 | +| OPENCV_DIR | OpenCV的安装路径 | +| PADDLE_DIR | Paddle预测库的路径 | + +在使用**GPU版本**预测库进行编译时,可执行下列操作。**注意**把对应的参数改为你的上述依赖库实际路径: + +```bash # 切换到预测库所在目录 cd /d D:\projects\PaddleSeg\inference\ # 创建构建目录, 重新构建只需要删除该目录即可 mkdir build cd build # cmake构建VS项目 -D:\projects\PaddleSeg\inference\build> cmake .. -G "Visual Studio 14 2015 Win64" -DWITH_GPU=ON -DPADDLE_DIR=D:\projects\fluid_inference -DCUDA_LIB=D:\projects\cudalib\v8.0\lib\x64 -DOPENCV_DIR=D:\projects\opencv -T host=x64 +D:\projects\PaddleSeg\inference\build> cmake .. -G "Visual Studio 14 2015 Win64" -DWITH_GPU=ON -DPADDLE_DIR=D:\projects\fluid_inference -DCUDA_LIB=D:\projects\cudalib\v9.0\lib\x64 -DOPENCV_DIR=D:\projects\opencv -T host=x64 ``` 在使用**CPU版本**预测库进行编译时,可执行下列操作。 -``` + +```bash # 切换到预测库所在目录 cd /d D:\projects\PaddleSeg\inference\ # 创建构建目录, 重新构建只需要删除该目录即可 mkdir build cd build # cmake构建VS项目 -D:\projects\PaddleSeg\inference\build> cmake .. -G "Visual Studio 14 2015 Win64" -DWITH_GPU=ON -DPADDLE_DIR=D:\projects\fluid_inference -DOPENCV_DIR=D:\projects\opencv -T host=x64 +D:\projects\PaddleSeg\inference\build> cmake .. -G "Visual Studio 14 2015 Win64" -DWITH_GPU=OFF -DPADDLE_DIR=D:\projects\fluid_inference -DOPENCV_DIR=D:\projects\opencv -T host=x64 ``` 这里的`cmake`参数`-G`, 表示生成对应的VS版本的工程,可以根据自己的`VS`版本调整,具体请参考[cmake文档](https://cmake.org/cmake/help/v3.15/manual/cmake-generators.7.html) diff --git a/inference/docs/windows_vs2019_build.md b/inference/docs/windows_vs2019_build.md index d7bf5d022d1c166aac58f0f6fb305964d0efb4d0..890844674db848177c4f859f4a8b8ef8d7360fa7 100644 --- a/inference/docs/windows_vs2019_build.md +++ b/inference/docs/windows_vs2019_build.md @@ -6,7 +6,7 @@ Windows 平台下,我们使用`Visual Studio 2015` 和 `Visual Studio 2019 Com ## 前置条件 * Visual Studio 2019 -* CUDA 8.0/ CUDA 9.0/ CUDA 10.0,cudnn 7+ (仅在使用GPU版本的预测库时需要) +* CUDA 9.0/ CUDA 10.0,cudnn 7+ (仅在使用GPU版本的预测库时需要) * CMake 3.0+ 请确保系统已经安装好上述基本软件,我们使用的是`VS2019`的社区版。 @@ -15,7 +15,7 @@ Windows 平台下,我们使用`Visual Studio 2015` 和 `Visual Studio 2019 Com ### Step1: 下载代码 -1. 点击下载源代码:[下载地址](https://github.com/PaddlePaddle/PaddleSeg/archive/master.zip) +1. 点击下载源代码:[下载地址](https://github.com/PaddlePaddle/PaddleSeg/archive/release/v0.2.0.zip) 2. 解压,解压后目录重命名为`PaddleSeg` 以下代码目录路径为`D:\projects\PaddleSeg` 为例。 @@ -23,14 +23,13 @@ Windows 平台下,我们使用`Visual Studio 2015` 和 `Visual Studio 2019 Com ### Step2: 下载PaddlePaddle C++ 预测库 fluid_inference -PaddlePaddle C++ 预测库主要分为两大版本:CPU版本和GPU版本。其中,针对不同的CUDA版本,GPU版本预测库又分为三个版本预测库:CUDA 8、CUDA 9和CUDA 10版本预测库。根据Windows环境,下载相应版本的PaddlePaddle预测库,并解压到`D:\projects\`目录。以下为各版本C++预测库(CUDA 8版本基于1.5版本的预测库,其余均基于1.6版本的预测库)的下载链接: +PaddlePaddle C++ 预测库主要分为两大版本:CPU版本和GPU版本。其中,针对不同的CUDA版本,GPU版本预测库又分为三个版本预测库:CUDA 9.0和CUDA 10.0版本预测库。根据Windows环境,下载相应版本的PaddlePaddle预测库,并解压到`D:\projects\`目录。以下为各版本C++预测库的下载链接: | 版本 | 链接 | | ---- | ---- | -| CPU版本 | [fluid_inference_install_dir.zip](https://paddle-wheel.bj.bcebos.com/1.6.0/win-infer/mkl/cpu/fluid_inference_install_dir.zip) | -| CUDA 8版本 | [fluid_inference_install_dir.zip](https://paddle-inference-lib.bj.bcebos.com/1.5.1-win/gpu_mkl_avx_8.0/fluid_inference_install_dir.zip) | -| CUDA 9版本 | [fluid_inference_install_dir.zip](https://paddle-wheel.bj.bcebos.com/1.6.0/win-infer/mkl/post97/fluid_inference_install_dir.zip) | -| CUDA 10版本 | [fluid_inference_install_dir.zip](https://paddle-wheel.bj.bcebos.com/1.6.0/win-infer/mkl/post107/fluid_inference_install_dir.zip) | +| CPU版本 | [fluid_inference_install_dir.zip](https://bj.bcebos.com/paddlehub/paddle_inference_lib/fluid_install_dir_win_cpu_1.6.zip) | +| CUDA 9.0版本 | [fluid_inference_install_dir.zip](https://bj.bcebos.com/paddlehub/paddle_inference_lib/fluid_inference_install_dir_win_cuda9_1.6.1.zip) | +| CUDA 10.0版本 | [fluid_inference_install_dir.zip](https://bj.bcebos.com/paddlehub/paddle_inference_lib/fluid_inference_install_dir_win_cuda10_1.6.1.zip) | 解压后`D:\projects\fluid_inference`目录包含内容为: ``` @@ -68,12 +67,12 @@ fluid_inference 4. 点击`浏览`,分别设置编译选项指定`CUDA`、`OpenCV`、`Paddle预测库`的路径 -三个编译参数的含义说明如下(带*表示仅在使用**GPU版本**预测库时指定): +三个编译参数的含义说明如下(带*表示仅在使用**GPU版本**预测库时指定, 其中CUDA库版本尽量对齐,**使用9.0、10.0版本,不使用9.2、10.1等版本CUDA库**): | 参数名 | 含义 | | ---- | ---- | -| *CUDA_LIB | cuda的库路径 | -| OPENCV_DIR | OpenCV的安装路径, | +| *CUDA_LIB | CUDA的库路径 | +| OPENCV_DIR | OpenCV的安装路径 | | PADDLE_DIR | Paddle预测库的路径 | **注意**在使用CPU版本预测库时,需要把CUDA_LIB的勾去掉。 ![step4](https://paddleseg.bj.bcebos.com/inference/vs2019_step5.png) @@ -90,7 +89,7 @@ fluid_inference 上述`Visual Studio 2019`编译产出的可执行文件在`out\build\x64-Release`目录下,打开`cmd`,并切换到该目录: ``` -cd /d D:\projects\PaddleSeg\inference\out\x64-Release +cd /d D:\projects\PaddleSeg\inference\out\build\x64-Release ``` 之后执行命令: diff --git a/inference/predictor/seg_predictor.cpp b/inference/predictor/seg_predictor.cpp index 5488ec946c96aaed543221a9f5d64be77092fba2..ca7673edb13afcbbb0fe35ed154729009993c01b 100644 --- a/inference/predictor/seg_predictor.cpp +++ b/inference/predictor/seg_predictor.cpp @@ -1,275 +1,317 @@ +// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 "seg_predictor.h" #include #undef min namespace PaddleSolution { + using std::chrono::duration_cast; + int Predictor::init(const std::string& conf) { + if (!_model_config.load_config(conf)) { + LOG(FATAL) << "Fail to load config file: [" << conf << "]"; + return -1; + } + _preprocessor = PaddleSolution::create_processor(conf); + if (_preprocessor == nullptr) { + LOG(FATAL) << "Failed to create_processor"; + return -1; + } - int Predictor::init(const std::string& conf) { - if (!_model_config.load_config(conf)) { - LOG(FATAL) << "Fail to load config file: [" << conf << "]"; - return -1; - } - _preprocessor = PaddleSolution::create_processor(conf); - if (_preprocessor == nullptr) { - LOG(FATAL) << "Failed to create_processor"; - return -1; - } - - _mask.resize(_model_config._resize[0] * _model_config._resize[1]); - _scoremap.resize(_model_config._resize[0] * _model_config._resize[1]); + int res_size = _model_config._resize[0] * _model_config._resize[1]; + _mask.resize(res_size); + _scoremap.resize(res_size); - bool use_gpu = _model_config._use_gpu; - const auto& model_dir = _model_config._model_path; - const auto& model_filename = _model_config._model_file_name; - const auto& params_filename = _model_config._param_file_name; + bool use_gpu = _model_config._use_gpu; + const auto& model_dir = _model_config._model_path; + const auto& model_filename = _model_config._model_file_name; + const auto& params_filename = _model_config._param_file_name; - // load paddle model file - if (_model_config._predictor_mode == "NATIVE") { - paddle::NativeConfig config; - auto prog_file = utils::path_join(model_dir, model_filename); - auto param_file = utils::path_join(model_dir, params_filename); - config.prog_file = prog_file; - config.param_file = param_file; - config.fraction_of_gpu_memory = 0; - config.use_gpu = use_gpu; - config.device = 0; - _main_predictor = paddle::CreatePaddlePredictor(config); - } - else if (_model_config._predictor_mode == "ANALYSIS") { - paddle::AnalysisConfig config; - if (use_gpu) { - config.EnableUseGpu(100, 0); - } - auto prog_file = utils::path_join(model_dir, model_filename); - auto param_file = utils::path_join(model_dir, params_filename); - config.SetModel(prog_file, param_file); - config.SwitchUseFeedFetchOps(false); - config.SwitchSpecifyInputNames(true); - config.EnableMemoryOptim(); - _main_predictor = paddle::CreatePaddlePredictor(config); + // load paddle model file + if (_model_config._predictor_mode == "NATIVE") { + paddle::NativeConfig config; + auto prog_file = utils::path_join(model_dir, model_filename); + auto param_file = utils::path_join(model_dir, params_filename); + config.prog_file = prog_file; + config.param_file = param_file; + config.fraction_of_gpu_memory = 0; + config.use_gpu = use_gpu; + config.device = 0; + _main_predictor = paddle::CreatePaddlePredictor(config); + } else if (_model_config._predictor_mode == "ANALYSIS") { + paddle::AnalysisConfig config; + if (use_gpu) { + config.EnableUseGpu(100, 0); } - else { - return -1; - } - return 0; + auto prog_file = utils::path_join(model_dir, model_filename); + auto param_file = utils::path_join(model_dir, params_filename); + config.SetModel(prog_file, param_file); + config.SwitchUseFeedFetchOps(false); + config.SwitchSpecifyInputNames(true); + config.EnableMemoryOptim(); + _main_predictor = paddle::CreatePaddlePredictor(config); + } else { + return -1; + } + return 0; + } + int Predictor::predict(const std::vector& imgs) { + if (_model_config._predictor_mode == "NATIVE") { + return native_predict(imgs); + } else if (_model_config._predictor_mode == "ANALYSIS") { + return analysis_predict(imgs); } + return -1; + } - int Predictor::predict(const std::vector& imgs) { - if (_model_config._predictor_mode == "NATIVE") { - return native_predict(imgs); - } - else if (_model_config._predictor_mode == "ANALYSIS") { - return analysis_predict(imgs); - } + int Predictor::output_mask(const std::string& fname, float* p_out, + int length, int* height, int* width) { + int eval_width = _model_config._resize[0]; + int eval_height = _model_config._resize[1]; + int eval_num_class = _model_config._class_num; + + int blob_out_len = length; + int seg_out_len = eval_height * eval_width * eval_num_class; + + if (blob_out_len != seg_out_len) { + LOG(ERROR) << " [FATAL] unequal: input vs output [" << + seg_out_len << "|" << blob_out_len << "]" << std::endl; return -1; } + // post process + _mask.clear(); + _scoremap.clear(); + std::vector out_shape{eval_num_class, eval_height, eval_width}; + utils::argmax(p_out, out_shape, _mask, _scoremap); + cv::Mat mask_png = cv::Mat(eval_height, eval_width, CV_8UC1); + mask_png.data = _mask.data(); + std::string nname(fname); + auto pos = fname.find("."); + nname[pos] = '_'; + std::string mask_save_name = nname + ".png"; + cv::imwrite(mask_save_name, mask_png); + cv::Mat scoremap_png = cv::Mat(eval_height, eval_width, CV_8UC1); + scoremap_png.data = _scoremap.data(); + std::string scoremap_save_name = nname + + std::string("_scoremap.png"); + cv::imwrite(scoremap_save_name, scoremap_png); + std::cout << "save mask of [" << fname << "] done" << std::endl; - int Predictor::output_mask(const std::string& fname, float* p_out, int length, int* height, int* width) { - int eval_width = _model_config._resize[0]; - int eval_height = _model_config._resize[1]; - int eval_num_class = _model_config._class_num; + if (height && width) { + int recover_height = *height; + int recover_width = *width; + cv::Mat recover_png = cv::Mat(recover_height, + recover_width, CV_8UC1); + cv::resize(scoremap_png, recover_png, + cv::Size(recover_width, recover_height), + 0, 0, cv::INTER_CUBIC); + std::string recover_name = nname + std::string("_recover.png"); + cv::imwrite(recover_name, recover_png); + } + return 0; + } - int blob_out_len = length; - int seg_out_len = eval_height * eval_width * eval_num_class; + int Predictor::native_predict(const std::vector& imgs) { + if (imgs.size() == 0) { + LOG(ERROR) << "No image found"; + return -1; + } + int config_batch_size = _model_config._batch_size; - if (blob_out_len != seg_out_len) { - LOG(ERROR) << " [FATAL] unequal: input vs output [" << - seg_out_len << "|" << blob_out_len << "]" << std::endl; - return -1; - } + int channels = _model_config._channels; + int eval_width = _model_config._resize[0]; + int eval_height = _model_config._resize[1]; + std::size_t total_size = imgs.size(); + int default_batch_size = std::min(config_batch_size, + static_cast(total_size)); + int batch = total_size / default_batch_size + + ((total_size % default_batch_size) != 0); + int batch_buffer_size = default_batch_size * channels + * eval_width * eval_height; - //post process - _mask.clear(); - _scoremap.clear(); - std::vector out_shape{eval_num_class, eval_height, eval_width}; - utils::argmax(p_out, out_shape, _mask, _scoremap); - cv::Mat mask_png = cv::Mat(eval_height, eval_width, CV_8UC1); - mask_png.data = _mask.data(); - std::string nname(fname); - auto pos = fname.find("."); - nname[pos] = '_'; - std::string mask_save_name = nname + ".png"; - cv::imwrite(mask_save_name, mask_png); - cv::Mat scoremap_png = cv::Mat(eval_height, eval_width, CV_8UC1); - scoremap_png.data = _scoremap.data(); - std::string scoremap_save_name = nname + std::string("_scoremap.png"); - cv::imwrite(scoremap_save_name, scoremap_png); - std::cout << "save mask of [" << fname << "] done" << std::endl; + auto& input_buffer = _buffer; + auto& org_width = _org_width; + auto& org_height = _org_height; + auto& imgs_batch = _imgs_batch; - if (height && width) { - int recover_height = *height; - int recover_width = *width; - cv::Mat recover_png = cv::Mat(recover_height, recover_width, CV_8UC1); - cv::resize(scoremap_png, recover_png, cv::Size(recover_width, recover_height), - 0, 0, cv::INTER_CUBIC); - std::string recover_name = nname + std::string("_recover.png"); - cv::imwrite(recover_name, recover_png); + input_buffer.resize(batch_buffer_size); + org_width.resize(default_batch_size); + org_height.resize(default_batch_size); + for (int u = 0; u < batch; ++u) { + int batch_size = default_batch_size; + if (u == (batch - 1) && (total_size % default_batch_size)) { + batch_size = total_size % default_batch_size; } - return 0; - } - int Predictor::native_predict(const std::vector& imgs) - { - if (imgs.size() == 0) { - LOG(ERROR) << "No image found"; + int real_buffer_size = batch_size * channels + * eval_width * eval_height; + std::vector feeds; + input_buffer.resize(real_buffer_size); + org_height.resize(batch_size); + org_width.resize(batch_size); + for (int i = 0; i < batch_size; ++i) { + org_width[i] = org_height[i] = 0; + } + imgs_batch.clear(); + for (int i = 0; i < batch_size; ++i) { + int idx = u * default_batch_size + i; + imgs_batch.push_back(imgs[idx]); + } + if (!_preprocessor->batch_process(imgs_batch, + input_buffer.data(), + org_width.data(), + org_height.data())) { return -1; } - int config_batch_size = _model_config._batch_size; - - int channels = _model_config._channels; - int eval_width = _model_config._resize[0]; - int eval_height = _model_config._resize[1]; - std::size_t total_size = imgs.size(); - int default_batch_size = std::min(config_batch_size, (int)total_size); - int batch = total_size / default_batch_size + ((total_size % default_batch_size) != 0); - int batch_buffer_size = default_batch_size * channels * eval_width * eval_height; - - auto& input_buffer = _buffer; - auto& org_width = _org_width; - auto& org_height = _org_height; - auto& imgs_batch = _imgs_batch; - - input_buffer.resize(batch_buffer_size); - org_width.resize(default_batch_size); - org_height.resize(default_batch_size); - for (int u = 0; u < batch; ++u) { - int batch_size = default_batch_size; - if (u == (batch - 1) && (total_size % default_batch_size)) { - batch_size = total_size % default_batch_size; - } - - int real_buffer_size = batch_size * channels * eval_width * eval_height; - std::vector feeds; - input_buffer.resize(real_buffer_size); - org_height.resize(batch_size); - org_width.resize(batch_size); - for (int i = 0; i < batch_size; ++i) { - org_width[i] = org_height[i] = 0; - } - imgs_batch.clear(); - for (int i = 0; i < batch_size; ++i) { - int idx = u * default_batch_size + i; - imgs_batch.push_back(imgs[idx]); - } - if (!_preprocessor->batch_process(imgs_batch, input_buffer.data(), org_width.data(), org_height.data())) { - return -1; - } - paddle::PaddleTensor im_tensor; - im_tensor.name = "image"; - im_tensor.shape = std::vector({ batch_size, channels, eval_height, eval_width }); - im_tensor.data.Reset(input_buffer.data(), real_buffer_size * sizeof(float)); - im_tensor.dtype = paddle::PaddleDType::FLOAT32; - feeds.push_back(im_tensor); - _outputs.clear(); - auto t1 = std::chrono::high_resolution_clock::now(); - if (!_main_predictor->Run(feeds, &_outputs, batch_size)) { - LOG(ERROR) << "Failed: NativePredictor->Run() return false at batch: " << u; - continue; - } - auto t2 = std::chrono::high_resolution_clock::now(); - auto duration = std::chrono::duration_cast(t2 - t1).count(); - std::cout << "runtime = " << duration << std::endl; - int out_num = 1; - // print shape of first output tensor for debugging - std::cout << "size of outputs[" << 0 << "]: ("; - for (int j = 0; j < _outputs[0].shape.size(); ++j) { - out_num *= _outputs[0].shape[j]; - std::cout << _outputs[0].shape[j] << ","; - } - std::cout << ")" << std::endl; - const size_t nums = _outputs.front().data.length() / sizeof(float); - if (out_num % batch_size != 0 || out_num != nums) { - LOG(ERROR) << "outputs data size mismatch with shape size."; - return -1; - } - - for (int i = 0; i < batch_size; ++i) { - float* output_addr = (float*)(_outputs[0].data.data()) + i * (out_num / batch_size); - output_mask(imgs_batch[i], output_addr, out_num / batch_size, &org_height[i], &org_width[i]); - } + paddle::PaddleTensor im_tensor; + im_tensor.name = "image"; + im_tensor.shape = std::vector{ batch_size, channels, + eval_height, eval_width }; + im_tensor.data.Reset(input_buffer.data(), + real_buffer_size * sizeof(float)); + im_tensor.dtype = paddle::PaddleDType::FLOAT32; + feeds.push_back(im_tensor); + _outputs.clear(); + auto t1 = std::chrono::high_resolution_clock::now(); + if (!_main_predictor->Run(feeds, &_outputs, batch_size)) { + LOG(ERROR) << + "Failed: NativePredictor->Run() return false at batch: " + << u; + continue; + } + auto t2 = std::chrono::high_resolution_clock::now(); + auto duration = duration_cast + (t2 - t1).count(); + std::cout << "runtime = " << duration << std::endl; + int out_num = 1; + // print shape of first output tensor for debugging + std::cout << "size of outputs[" << 0 << "]: ("; + for (int j = 0; j < _outputs[0].shape.size(); ++j) { + out_num *= _outputs[0].shape[j]; + std::cout << _outputs[0].shape[j] << ","; + } + std::cout << ")" << std::endl; + const size_t nums = _outputs.front().data.length() + / sizeof(float); + if (out_num % batch_size != 0 || out_num != nums) { + LOG(ERROR) << "outputs data size mismatch with shape size."; + return -1; } - return 0; + for (int i = 0; i < batch_size; ++i) { + float* output_addr = reinterpret_cast( + _outputs[0].data.data()) + + i * (out_num / batch_size); + output_mask(imgs_batch[i], output_addr, + out_num / batch_size, + &org_height[i], + &org_width[i]); + } } - int Predictor::analysis_predict(const std::vector& imgs) { + return 0; + } - if (imgs.size() == 0) { - LOG(ERROR) << "No image found"; - return -1; - } + int Predictor::analysis_predict(const std::vector& imgs) { + if (imgs.size() == 0) { + LOG(ERROR) << "No image found"; + return -1; + } - int config_batch_size = _model_config._batch_size; - int channels = _model_config._channels; - int eval_width = _model_config._resize[0]; - int eval_height = _model_config._resize[1]; - auto total_size = imgs.size(); - int default_batch_size = std::min(config_batch_size, (int)total_size); - int batch = total_size / default_batch_size + ((total_size % default_batch_size) != 0); - int batch_buffer_size = default_batch_size * channels * eval_width * eval_height; + int config_batch_size = _model_config._batch_size; + int channels = _model_config._channels; + int eval_width = _model_config._resize[0]; + int eval_height = _model_config._resize[1]; + auto total_size = imgs.size(); + int default_batch_size = std::min(config_batch_size, + static_cast(total_size)); + int batch = total_size / default_batch_size + + ((total_size % default_batch_size) != 0); + int batch_buffer_size = default_batch_size * channels + * eval_width * eval_height; - auto& input_buffer = _buffer; - auto& org_width = _org_width; - auto& org_height = _org_height; - auto& imgs_batch = _imgs_batch; + auto& input_buffer = _buffer; + auto& org_width = _org_width; + auto& org_height = _org_height; + auto& imgs_batch = _imgs_batch; - input_buffer.resize(batch_buffer_size); - org_width.resize(default_batch_size); - org_height.resize(default_batch_size); + input_buffer.resize(batch_buffer_size); + org_width.resize(default_batch_size); + org_height.resize(default_batch_size); - for (int u = 0; u < batch; ++u) { - int batch_size = default_batch_size; - if (u == (batch - 1) && (total_size % default_batch_size)) { - batch_size = total_size % default_batch_size; - } + for (int u = 0; u < batch; ++u) { + int batch_size = default_batch_size; + if (u == (batch - 1) && (total_size % default_batch_size)) { + batch_size = total_size % default_batch_size; + } - int real_buffer_size = batch_size * channels * eval_width * eval_height; - std::vector feeds; - input_buffer.resize(real_buffer_size); - org_height.resize(batch_size); - org_width.resize(batch_size); - for (int i = 0; i < batch_size; ++i) { - org_width[i] = org_height[i] = 0; - } - imgs_batch.clear(); - for (int i = 0; i < batch_size; ++i) { - int idx = u * default_batch_size + i; - imgs_batch.push_back(imgs[idx]); - } + int real_buffer_size = batch_size * channels + * eval_width * eval_height; + std::vector feeds; + input_buffer.resize(real_buffer_size); + org_height.resize(batch_size); + org_width.resize(batch_size); + for (int i = 0; i < batch_size; ++i) { + org_width[i] = org_height[i] = 0; + } + imgs_batch.clear(); + for (int i = 0; i < batch_size; ++i) { + int idx = u * default_batch_size + i; + imgs_batch.push_back(imgs[idx]); + } - if (!_preprocessor->batch_process(imgs_batch, input_buffer.data(), org_width.data(), org_height.data())) { - return -1; - } - auto im_tensor = _main_predictor->GetInputTensor("image"); - im_tensor->Reshape({ batch_size, channels, eval_height, eval_width }); - im_tensor->copy_from_cpu(input_buffer.data()); + if (!_preprocessor->batch_process(imgs_batch, + input_buffer.data(), + org_width.data(), + org_height.data())) { + return -1; + } + auto im_tensor = _main_predictor->GetInputTensor("image"); + im_tensor->Reshape({ batch_size, channels, + eval_height, eval_width }); + im_tensor->copy_from_cpu(input_buffer.data()); - auto t1 = std::chrono::high_resolution_clock::now(); - _main_predictor->ZeroCopyRun(); - auto t2 = std::chrono::high_resolution_clock::now(); - auto duration = std::chrono::duration_cast(t2 - t1).count(); - std::cout << "runtime = " << duration << std::endl; + auto t1 = std::chrono::high_resolution_clock::now(); + _main_predictor->ZeroCopyRun(); + auto t2 = std::chrono::high_resolution_clock::now(); + auto duration = duration_cast + (t2 - t1).count(); + std::cout << "runtime = " << duration << std::endl; - auto output_names = _main_predictor->GetOutputNames(); - auto output_t = _main_predictor->GetOutputTensor(output_names[0]); - std::vector out_data; - std::vector output_shape = output_t->shape(); + auto output_names = _main_predictor->GetOutputNames(); + auto output_t = _main_predictor->GetOutputTensor( + output_names[0]); + std::vector out_data; + std::vector output_shape = output_t->shape(); - int out_num = 1; - std::cout << "size of outputs[" << 0 << "]: ("; - for (int j = 0; j < output_shape.size(); ++j) { - out_num *= output_shape[j]; - std::cout << output_shape[j] << ","; - } - std::cout << ")" << std::endl; + int out_num = 1; + std::cout << "size of outputs[" << 0 << "]: ("; + for (int j = 0; j < output_shape.size(); ++j) { + out_num *= output_shape[j]; + std::cout << output_shape[j] << ","; + } + std::cout << ")" << std::endl; - out_data.resize(out_num); - output_t->copy_to_cpu(out_data.data()); - for (int i = 0; i < batch_size; ++i) { - float* out_addr = out_data.data() + (out_num / batch_size) * i; - output_mask(imgs_batch[i], out_addr, out_num / batch_size, &org_height[i], &org_width[i]); - } + out_data.resize(out_num); + output_t->copy_to_cpu(out_data.data()); + for (int i = 0; i < batch_size; ++i) { + float* out_addr = out_data.data() + + (out_num / batch_size) * i; + output_mask(imgs_batch[i], out_addr, out_num / batch_size, + &org_height[i], &org_width[i]); } - return 0; } -} + return 0; + } +} // namespace PaddleSolution diff --git a/inference/predictor/seg_predictor.h b/inference/predictor/seg_predictor.h index 0217115b81391a9a4d8daa9471f2b50f677fcbe1..ade8c0478830971e0f02f633fef508aefc46bb79 100644 --- a/inference/predictor/seg_predictor.h +++ b/inference/predictor/seg_predictor.h @@ -1,49 +1,59 @@ +// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + #pragma once +#include +#include + #include #include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include "utils/seg_conf_parser.h" +#include "utils/utils.h" +#include "preprocessor/preprocessor.h" namespace PaddleSolution { - class Predictor { - public: - // init a predictor with a yaml config file - int init(const std::string& conf); - // predict api - int predict(const std::vector& imgs); - - private: - int output_mask( - const std::string& fname, - float* p_out, - int length, - int* height = NULL, - int* width = NULL); - int native_predict(const std::vector& imgs); - int analysis_predict(const std::vector& imgs); - private: - std::vector _buffer; - std::vector _org_width; - std::vector _org_height; - std::vector _imgs_batch; - std::vector _outputs; +class Predictor { + public: + // init a predictor with a yaml config file + int init(const std::string& conf); + // predict api + int predict(const std::vector& imgs); + private: + int output_mask(const std::string& fname, float* p_out, int length, + int* height = NULL, int* width = NULL); + int native_predict(const std::vector& imgs); + int analysis_predict(const std::vector& imgs); + private: + std::vector _buffer; + std::vector _org_width; + std::vector _org_height; + std::vector _imgs_batch; + std::vector _outputs; - std::vector _mask; - std::vector _scoremap; + std::vector _mask; + std::vector _scoremap; - PaddleSolution::PaddleSegModelConfigPaser _model_config; - std::shared_ptr _preprocessor; - std::unique_ptr _main_predictor; - }; -} + PaddleSolution::PaddleSegModelConfigPaser _model_config; + std::shared_ptr _preprocessor; + std::unique_ptr _main_predictor; +}; +} // namespace PaddleSolution diff --git a/inference/preprocessor/preprocessor.cpp b/inference/preprocessor/preprocessor.cpp index f3ce82dc122308941357e1de13fb156459782bc7..9d6d20b5fb69a8d00596f9125b8d84f541bd279e 100644 --- a/inference/preprocessor/preprocessor.cpp +++ b/inference/preprocessor/preprocessor.cpp @@ -1,3 +1,17 @@ +// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 @@ -7,9 +21,10 @@ namespace PaddleSolution { - std::shared_ptr create_processor(const std::string& conf_file) { - - auto config = std::make_shared(); + std::shared_ptr create_processor( + const std::string& conf_file) { + auto config = std::make_shared(); if (!config->load_config(conf_file)) { LOG(FATAL) << "fail to laod conf file [" << conf_file << "]"; return nullptr; @@ -23,9 +38,9 @@ namespace PaddleSolution { return p; } - LOG(FATAL) << "unknown processor_name [" << config->_pre_processor << "]"; + LOG(FATAL) << "unknown processor_name [" << config->_pre_processor + << "]"; return nullptr; } -} - +} // namespace PaddleSolution diff --git a/inference/preprocessor/preprocessor.h b/inference/preprocessor/preprocessor.h index d94809f008be3da4d66dcab948ba2aa6a8f085c0..4a1372de612e851759ea7f384bc555423f1b237d 100644 --- a/inference/preprocessor/preprocessor.h +++ b/inference/preprocessor/preprocessor.h @@ -1,3 +1,17 @@ +// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + #pragma once #include #include @@ -12,18 +26,19 @@ namespace PaddleSolution { class ImagePreProcessor { -protected: - ImagePreProcessor() {}; - -public: + protected: + ImagePreProcessor() {} + public: virtual ~ImagePreProcessor() {} - virtual bool single_process(const std::string& fname, float* data, int* ori_w, int* ori_h) = 0; - - virtual bool batch_process(const std::vector& imgs, float* data, int* ori_w, int* ori_h) = 0; + virtual bool single_process(const std::string& fname, float* data, + int* ori_w, int* ori_h) = 0; -}; // end of class ImagePreProcessor + virtual bool batch_process(const std::vector& imgs, + float* data, int* ori_w, int* ori_h) = 0; +}; // end of class ImagePreProcessor -std::shared_ptr create_processor(const std::string &config_file); +std::shared_ptr create_processor( + const std::string &config_file); -} // end of namespace paddle_solution +} // namespace PaddleSolution diff --git a/inference/preprocessor/preprocessor_seg.cpp b/inference/preprocessor/preprocessor_seg.cpp index c2d056bfd2706ad441b96d76165804c0d81cdfaf..7c74042071143be53e11f1e7915531ea9354f356 100644 --- a/inference/preprocessor/preprocessor_seg.cpp +++ b/inference/preprocessor/preprocessor_seg.cpp @@ -1,18 +1,33 @@ -#include +// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 "preprocessor_seg.h" #include -#include "preprocessor_seg.h" +#include + namespace PaddleSolution { - bool SegPreProcessor::single_process(const std::string& fname, float* data, int* ori_w, int* ori_h) { + bool SegPreProcessor::single_process(const std::string& fname, + float* data, int* ori_w, int* ori_h) { cv::Mat im = cv::imread(fname, -1); if (im.data == nullptr || im.empty()) { LOG(ERROR) << "Failed to open image: " << fname; return false; } - int channels = im.channels(); *ori_w = im.cols; *ori_h = im.rows; @@ -36,7 +51,8 @@ namespace PaddleSolution { return true; } - bool SegPreProcessor::batch_process(const std::vector& imgs, float* data, int* ori_w, int* ori_h) { + bool SegPreProcessor::batch_process(const std::vector& imgs, + float* data, int* ori_w, int* ori_h) { auto ic = _config->_channels; auto iw = _config->_resize[0]; auto ih = _config->_resize[1]; @@ -58,9 +74,9 @@ namespace PaddleSolution { return true; } - bool SegPreProcessor::init(std::shared_ptr config) { + bool SegPreProcessor::init( + std::shared_ptr config) { _config = config; return true; } - -} +} // namespace PaddleSolution diff --git a/inference/preprocessor/preprocessor_seg.h b/inference/preprocessor/preprocessor_seg.h index eba904b8949b3c000799ee84541699989fea425a..5eba23e555c9b335ac1ee2cee4e51098546c5fe1 100644 --- a/inference/preprocessor/preprocessor_seg.h +++ b/inference/preprocessor/preprocessor_seg.h @@ -1,24 +1,40 @@ +// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + #pragma once +#include +#include +#include #include "preprocessor.h" #include "utils/utils.h" namespace PaddleSolution { class SegPreProcessor : public ImagePreProcessor { + public: + SegPreProcessor() : _config(nullptr) {} -public: - SegPreProcessor() : _config(nullptr){ - }; - - bool init(std::shared_ptr config); + bool init( + std::shared_ptr config); - bool single_process(const std::string &fname, float* data, int* ori_w, int* ori_h); + bool single_process(const std::string &fname, float* data, + int* ori_w, int* ori_h); - bool batch_process(const std::vector& imgs, float* data, int* ori_w, int* ori_h); - -private: + bool batch_process(const std::vector& imgs, float* data, + int* ori_w, int* ori_h); + private: std::shared_ptr _config; }; - -} +} // namespace PaddleSolution diff --git a/inference/tools/visualize.py b/inference/tools/visualize.py index 3939342baf907846a45d3bd0e8ab87e6c35699f4..c249a1db73144ba15960a5949589a9e2bc5d9734 100644 --- a/inference/tools/visualize.py +++ b/inference/tools/visualize.py @@ -1,27 +1,41 @@ -import cv2 -import sys - -# ColorMap for visualization more clearly -color_map = [[128, 64, 128], [244, 35, 231], [69, 69, 69], [102, 102, 156], - [190, 153, 153], [153, 153, 153], [250, 170, 29], [219, 219, 0], - [106, 142, 35], [152, 250, 152], [69, 129, 180], [219, 19, 60], - [255, 0, 0], [0, 0, 142], [0, 0, 69], [0, 60, 100], [0, 79, 100], +# Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# 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. + +import cv2 +import sys + +# ColorMap for visualization more clearly +color_map = [[128, 64, 128], [244, 35, 231], [69, 69, 69], [102, 102, 156], + [190, 153, 153], [153, 153, 153], [250, 170, 29], [219, 219, 0], + [106, 142, 35], [152, 250, 152], [69, 129, 180], [219, 19, 60], + [255, 0, 0], [0, 0, 142], [0, 0, 69], [0, 60, 100], [0, 79, 100], [0, 0, 230], [119, 10, 32]] -# python visualize.py demo1.jpg demo1_jpg.png vis_result.png -if __name__ == "__main__": - if len(sys.argv) != 4: - print( - "Usage: python visualize.py demo1.jpg demo1_jpg.png vis_result.png") - else: - ori_im = cv2.imread(sys.argv[1]) - ori_shape = ori_im.shape - print(ori_shape) - im = cv2.imread(sys.argv[2]) - shape = im.shape - print("visualizing...") - for i in range(0, shape[0]): - for j in range(0, shape[1]): - im[i, j] = color_map[im[i, j, 0]] - im = cv2.resize(im, (ori_shape[1], ori_shape[0])) - cv2.imwrite(sys.argv[3], im) - print("visualizing done!") +# python visualize.py demo1.jpg demo1_jpg.png vis_result.png +if __name__ == "__main__": + if len(sys.argv) != 4: + print( + "Usage: python visualize.py demo1.jpg demo1_jpg.png vis_result.png") + else: + ori_im = cv2.imread(sys.argv[1]) + ori_shape = ori_im.shape + print(ori_shape) + im = cv2.imread(sys.argv[2]) + shape = im.shape + print("visualizing...") + for i in range(0, shape[0]): + for j in range(0, shape[1]): + im[i, j] = color_map[im[i, j, 0]] + im = cv2.resize(im, (ori_shape[1], ori_shape[0])) + cv2.imwrite(sys.argv[3], im) + print("visualizing done!") diff --git a/inference/utils/seg_conf_parser.h b/inference/utils/seg_conf_parser.h index 078d04f3eb9dcd1763f69a8eb770c0853f9f1b24..b1e40ff84bf0ac9e4e932875b341ee9741efb4ff 100644 --- a/inference/utils/seg_conf_parser.h +++ b/inference/utils/seg_conf_parser.h @@ -1,165 +1,178 @@ -#pragma once -#include -#include -#include - -#include -namespace PaddleSolution { - - class PaddleSegModelConfigPaser { - public: - PaddleSegModelConfigPaser() - :_class_num(0), - _channels(0), - _use_gpu(0), - _batch_size(1), - _model_file_name("__model__"), - _param_file_name("__params__") { - } - ~PaddleSegModelConfigPaser() { - } - - void reset() { - _resize.clear(); - _mean.clear(); - _std.clear(); - _img_type.clear(); - _class_num = 0; - _channels = 0; - _use_gpu = 0; - _batch_size = 1; - _model_file_name.clear(); - _model_path.clear(); - _param_file_name.clear(); - } - - std::string process_parenthesis(const std::string& str) { - if (str.size() < 2) { - return str; - } - std::string nstr(str); - if (str[0] == '(' && str.back() == ')') { - nstr[0] = '['; - nstr[str.size() - 1] = ']'; - } - return nstr; - } - - template - std::vector parse_str_to_vec(const std::string& str) { - std::vector data; - auto node = YAML::Load(str); - for (const auto& item : node) { - data.push_back(item.as()); - } - return data; - } - - bool load_config(const std::string& conf_file) { - - reset(); - - YAML::Node config = YAML::LoadFile(conf_file); - // 1. get resize - auto str = config["DEPLOY"]["EVAL_CROP_SIZE"].as(); - _resize = parse_str_to_vec(process_parenthesis(str)); - - // 2. get mean - for (const auto& item : config["DEPLOY"]["MEAN"]) { - _mean.push_back(item.as()); - } - - // 3. get std - for (const auto& item : config["DEPLOY"]["STD"]) { - _std.push_back(item.as()); - } - - // 4. get image type - _img_type = config["DEPLOY"]["IMAGE_TYPE"].as(); - // 5. get class number - _class_num = config["DEPLOY"]["NUM_CLASSES"].as(); - // 7. set model path - _model_path = config["DEPLOY"]["MODEL_PATH"].as(); - // 8. get model file_name - _model_file_name = config["DEPLOY"]["MODEL_FILENAME"].as(); - // 9. get model param file name - _param_file_name = config["DEPLOY"]["PARAMS_FILENAME"].as(); - // 10. get pre_processor - _pre_processor = config["DEPLOY"]["PRE_PROCESSOR"].as(); - // 11. use_gpu - _use_gpu = config["DEPLOY"]["USE_GPU"].as(); - // 12. predictor_mode - _predictor_mode = config["DEPLOY"]["PREDICTOR_MODE"].as(); - // 13. batch_size - _batch_size = config["DEPLOY"]["BATCH_SIZE"].as(); - // 14. channels - _channels = config["DEPLOY"]["CHANNELS"].as(); - return true; - } - - void debug() const { - - std::cout << "EVAL_CROP_SIZE: (" << _resize[0] << ", " << _resize[1] << ")" << std::endl; - - std::cout << "MEAN: ["; - for (int i = 0; i < _mean.size(); ++i) { - if (i != _mean.size() - 1) { - std::cout << _mean[i] << ", "; - } else { - std::cout << _mean[i]; - } - } - std::cout << "]" << std::endl; - - std::cout << "STD: ["; - for (int i = 0; i < _std.size(); ++i) { - if (i != _std.size() - 1) { - std::cout << _std[i] << ", "; - } - else { - std::cout << _std[i]; - } - } - std::cout << "]" << std::endl; - - std::cout << "DEPLOY.IMAGE_TYPE: " << _img_type << std::endl; - std::cout << "DEPLOY.NUM_CLASSES: " << _class_num << std::endl; - std::cout << "DEPLOY.CHANNELS: " << _channels << std::endl; - std::cout << "DEPLOY.MODEL_PATH: " << _model_path << std::endl; - std::cout << "DEPLOY.MODEL_FILENAME: " << _model_file_name << std::endl; - std::cout << "DEPLOY.PARAMS_FILENAME: " << _param_file_name << std::endl; - std::cout << "DEPLOY.PRE_PROCESSOR: " << _pre_processor << std::endl; - std::cout << "DEPLOY.USE_GPU: " << _use_gpu << std::endl; - std::cout << "DEPLOY.PREDICTOR_MODE: " << _predictor_mode << std::endl; - std::cout << "DEPLOY.BATCH_SIZE: " << _batch_size << std::endl; - } - - // DEPLOY.EVAL_CROP_SIZE - std::vector _resize; - // DEPLOY.MEAN - std::vector _mean; - // DEPLOY.STD - std::vector _std; - // DEPLOY.IMAGE_TYPE - std::string _img_type; - // DEPLOY.NUM_CLASSES - int _class_num; - // DEPLOY.CHANNELS - int _channels; - // DEPLOY.MODEL_PATH - std::string _model_path; - // DEPLOY.MODEL_FILENAME - std::string _model_file_name; - // DEPLOY.PARAMS_FILENAME - std::string _param_file_name; - // DEPLOY.PRE_PROCESSOR - std::string _pre_processor; - // DEPLOY.USE_GPU - int _use_gpu; - // DEPLOY.PREDICTOR_MODE - std::string _predictor_mode; - // DEPLOY.BATCH_SIZE - int _batch_size; - }; - -} +// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +#pragma once +#include +#include +#include +#include + +namespace PaddleSolution { +class PaddleSegModelConfigPaser { + public: + PaddleSegModelConfigPaser() + :_class_num(0), + _channels(0), + _use_gpu(0), + _batch_size(1), + _model_file_name("__model__"), + _param_file_name("__params__") { + } + ~PaddleSegModelConfigPaser() { + } + + void reset() { + _resize.clear(); + _mean.clear(); + _std.clear(); + _img_type.clear(); + _class_num = 0; + _channels = 0; + _use_gpu = 0; + _batch_size = 1; + _model_file_name.clear(); + _model_path.clear(); + _param_file_name.clear(); + } + + std::string process_parenthesis(const std::string& str) { + if (str.size() < 2) { + return str; + } + std::string nstr(str); + if (str[0] == '(' && str.back() == ')') { + nstr[0] = '['; + nstr[str.size() - 1] = ']'; + } + return nstr; + } + + template + std::vector parse_str_to_vec(const std::string& str) { + std::vector data; + auto node = YAML::Load(str); + for (const auto& item : node) { + data.push_back(item.as()); + } + return data; + } + + bool load_config(const std::string& conf_file) { + reset(); + + YAML::Node config = YAML::LoadFile(conf_file); + // 1. get resize + auto str = config["DEPLOY"]["EVAL_CROP_SIZE"].as(); + _resize = parse_str_to_vec(process_parenthesis(str)); + + // 2. get mean + for (const auto& item : config["DEPLOY"]["MEAN"]) { + _mean.push_back(item.as()); + } + + // 3. get std + for (const auto& item : config["DEPLOY"]["STD"]) { + _std.push_back(item.as()); + } + + // 4. get image type + _img_type = config["DEPLOY"]["IMAGE_TYPE"].as(); + // 5. get class number + _class_num = config["DEPLOY"]["NUM_CLASSES"].as(); + // 7. set model path + _model_path = config["DEPLOY"]["MODEL_PATH"].as(); + // 8. get model file_name + _model_file_name = config["DEPLOY"]["MODEL_FILENAME"].as(); + // 9. get model param file name + _param_file_name = + config["DEPLOY"]["PARAMS_FILENAME"].as(); + // 10. get pre_processor + _pre_processor = config["DEPLOY"]["PRE_PROCESSOR"].as(); + // 11. use_gpu + _use_gpu = config["DEPLOY"]["USE_GPU"].as(); + // 12. predictor_mode + _predictor_mode = config["DEPLOY"]["PREDICTOR_MODE"].as(); + // 13. batch_size + _batch_size = config["DEPLOY"]["BATCH_SIZE"].as(); + // 14. channels + _channels = config["DEPLOY"]["CHANNELS"].as(); + return true; + } + + void debug() const { + std::cout << "EVAL_CROP_SIZE: (" + << _resize[0] << ", " << _resize[1] + << ")" << std::endl; + std::cout << "MEAN: ["; + for (int i = 0; i < _mean.size(); ++i) { + if (i != _mean.size() - 1) { + std::cout << _mean[i] << ", "; + } else { + std::cout << _mean[i]; + } + } + std::cout << "]" << std::endl; + + std::cout << "STD: ["; + for (int i = 0; i < _std.size(); ++i) { + if (i != _std.size() - 1) { + std::cout << _std[i] << ", "; + } else { + std::cout << _std[i]; + } + } + std::cout << "]" << std::endl; + + std::cout << "DEPLOY.IMAGE_TYPE: " << _img_type << std::endl; + std::cout << "DEPLOY.NUM_CLASSES: " << _class_num << std::endl; + std::cout << "DEPLOY.CHANNELS: " << _channels << std::endl; + std::cout << "DEPLOY.MODEL_PATH: " << _model_path << std::endl; + std::cout << "DEPLOY.MODEL_FILENAME: " << _model_file_name << std::endl; + std::cout << "DEPLOY.PARAMS_FILENAME: " + << _param_file_name << std::endl; + std::cout << "DEPLOY.PRE_PROCESSOR: " << _pre_processor << std::endl; + std::cout << "DEPLOY.USE_GPU: " << _use_gpu << std::endl; + std::cout << "DEPLOY.PREDICTOR_MODE: " << _predictor_mode << std::endl; + std::cout << "DEPLOY.BATCH_SIZE: " << _batch_size << std::endl; + } + + // DEPLOY.EVAL_CROP_SIZE + std::vector _resize; + // DEPLOY.MEAN + std::vector _mean; + // DEPLOY.STD + std::vector _std; + // DEPLOY.IMAGE_TYPE + std::string _img_type; + // DEPLOY.NUM_CLASSES + int _class_num; + // DEPLOY.CHANNELS + int _channels; + // DEPLOY.MODEL_PATH + std::string _model_path; + // DEPLOY.MODEL_FILENAME + std::string _model_file_name; + // DEPLOY.PARAMS_FILENAME + std::string _param_file_name; + // DEPLOY.PRE_PROCESSOR + std::string _pre_processor; + // DEPLOY.USE_GPU + int _use_gpu; + // DEPLOY.PREDICTOR_MODE + std::string _predictor_mode; + // DEPLOY.BATCH_SIZE + int _batch_size; +}; + +} // namespace PaddleSolution diff --git a/inference/utils/utils.h b/inference/utils/utils.h index 894636499bb55b9018cd40072455ae5cedd8a63f..7e322daa03c02e704509f032d5709684a341060f 100644 --- a/inference/utils/utils.h +++ b/inference/utils/utils.h @@ -1,3 +1,17 @@ +// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + #pragma once #include @@ -16,105 +30,110 @@ #endif namespace PaddleSolution { - namespace utils { - inline std::string path_join(const std::string& dir, const std::string& path) { - std::string seperator = "/"; - #ifdef _WIN32 - seperator = "\\"; - #endif - return dir + seperator + path; +namespace utils { + inline std::string path_join(const std::string& dir, + const std::string& path) { + std::string seperator = "/"; + #ifdef _WIN32 + seperator = "\\"; + #endif + return dir + seperator + path; + } + #ifndef _WIN32 + // scan a directory and get all files with input extensions + inline std::vector get_directory_images( + const std::string& path, const std::string& exts) { + std::vector imgs; + struct dirent *entry; + DIR *dir = opendir(path.c_str()); + if (dir == NULL) { + closedir(dir); + return imgs; } - #ifndef _WIN32 - // scan a directory and get all files with input extensions - inline std::vector get_directory_images(const std::string& path, const std::string& exts) - { - std::vector imgs; - struct dirent *entry; - DIR *dir = opendir(path.c_str()); - if (dir == NULL) { - closedir(dir); - return imgs; - } - while ((entry = readdir(dir)) != NULL) { - std::string item = entry->d_name; - auto ext = strrchr(entry->d_name, '.'); - if (!ext || std::string(ext) == "." || std::string(ext) == "..") { - continue; - } - if (exts.find(ext) != std::string::npos) { - imgs.push_back(path_join(path, entry->d_name)); - } + while ((entry = readdir(dir)) != NULL) { + std::string item = entry->d_name; + auto ext = strrchr(entry->d_name, '.'); + if (!ext || std::string(ext) == "." || std::string(ext) == "..") { + continue; + } + if (exts.find(ext) != std::string::npos) { + imgs.push_back(path_join(path, entry->d_name)); } - return imgs; } - #else - // scan a directory and get all files with input extensions - inline std::vector get_directory_images(const std::string& path, const std::string& exts) - { - std::vector imgs; - for (const auto& item : std::experimental::filesystem::directory_iterator(path)) { - auto suffix = item.path().extension().string(); - if (exts.find(suffix) != std::string::npos && suffix.size() > 0) { - auto fullname = path_join(path, item.path().filename().string()); - imgs.push_back(item.path().string()); - } + return imgs; + } + #else + // scan a directory and get all files with input extensions + inline std::vector get_directory_images( + const std::string& path, const std::string& exts) { + std::vector imgs; + for (const auto& item : + std::experimental::filesystem::directory_iterator(path)) { + auto suffix = item.path().extension().string(); + if (exts.find(suffix) != std::string::npos && suffix.size() > 0) { + auto fullname = path_join(path, + item.path().filename().string()); + imgs.push_back(item.path().string()); } - return imgs; } - #endif + return imgs; + } + #endif - // normalize and HWC_BGR -> CHW_RGB - inline void normalize(cv::Mat& im, float* data, std::vector& fmean, std::vector& fstd) { - int rh = im.rows; - int rw = im.cols; - int rc = im.channels(); - double normf = (double)1.0 / 255.0; - #pragma omp parallel for - for (int h = 0; h < rh; ++h) { - const uchar* ptr = im.ptr(h); - int im_index = 0; - for (int w = 0; w < rw; ++w) { - for (int c = 0; c < rc; ++c) { - int top_index = (c * rh + h) * rw + w; - float pixel = static_cast(ptr[im_index++]); - pixel = (pixel * normf - fmean[c]) / fstd[c]; - data[top_index] = pixel; - } + // normalize and HWC_BGR -> CHW_RGB + inline void normalize(cv::Mat& im, float* data, std::vector& fmean, + std::vector& fstd) { + int rh = im.rows; + int rw = im.cols; + int rc = im.channels(); + double normf = static_cast(1.0) / 255.0; + #pragma omp parallel for + for (int h = 0; h < rh; ++h) { + const uchar* ptr = im.ptr(h); + int im_index = 0; + for (int w = 0; w < rw; ++w) { + for (int c = 0; c < rc; ++c) { + int top_index = (c * rh + h) * rw + w; + float pixel = static_cast(ptr[im_index++]); + pixel = (pixel * normf - fmean[c]) / fstd[c]; + data[top_index] = pixel; } } } + } - // argmax - inline void argmax(float* out, std::vector& shape, std::vector& mask, std::vector& scoremap) { - int out_img_len = shape[1] * shape[2]; - int blob_out_len = out_img_len * shape[0]; - /* - Eigen::TensorMap> out_3d(out, shape[0], shape[1], shape[2]); - Eigen::Tensor argmax = out_3d.argmax(0); - */ - float max_value = -1; - int label = 0; - #pragma omp parallel private(label) - for (int i = 0; i < out_img_len; ++i) { - max_value = -1; - label = 0; - #pragma omp for reduction(max : max_value) - for (int j = 0; j < shape[0]; ++j) { - int index = i + j * out_img_len; - if (index >= blob_out_len) { - continue; - } - float value = out[index]; - if (value > max_value) { - max_value = value; - label = j; - } + // argmax + inline void argmax(float* out, std::vector& shape, + std::vector& mask, std::vector& scoremap) { + int out_img_len = shape[1] * shape[2]; + int blob_out_len = out_img_len * shape[0]; + /* + Eigen::TensorMap> out_3d(out, shape[0], shape[1], shape[2]); + Eigen::Tensor argmax = out_3d.argmax(0); + */ + float max_value = -1; + int label = 0; + #pragma omp parallel private(label) + for (int i = 0; i < out_img_len; ++i) { + max_value = -1; + label = 0; + #pragma omp for reduction(max : max_value) + for (int j = 0; j < shape[0]; ++j) { + int index = i + j * out_img_len; + if (index >= blob_out_len) { + continue; + } + float value = out[index]; + if (value > max_value) { + max_value = value; + label = j; } - if (label == 0) max_value = 0; - mask[i] = uchar(label); - scoremap[i] = uchar(max_value * 255); } + if (label == 0) max_value = 0; + mask[i] = uchar(label); + scoremap[i] = uchar(max_value * 255); } } -} +} // namespace utils +} // namespace PaddleSolution