├── README.md ├── bin └── main.cpp ├── docs ├── hdrnet-mobile-cn.md ├── hdrnet.pptx ├── help.md ├── img │ ├── low-res-coeff-predict.png │ ├── tensorflow_model_dir.png │ └── whole-arch.png ├── network_structure.xlsx └── resize.md ├── include ├── cnn │ ├── BaseLayer.h │ ├── ConvolutionLayer.h │ ├── FCLayer.h │ ├── FusionAddLayer.h │ ├── ILayer.h │ ├── ReLULayer.h │ └── TransposeLayer.h ├── hdrnet │ ├── GridNet.h │ ├── HdrnetTask.h │ ├── hdrnet_api.h │ ├── preprocess.h │ └── type.h ├── helper.h └── utils │ └── Utils.h ├── makefile ├── ndk ├── dll │ └── jni │ │ ├── Android.mk │ │ └── Application.mk └── main │ └── jni │ ├── Android.mk │ └── Application.mk ├── python └── README.md ├── script ├── generate_rgb_raw.py ├── get_tfmodel_value.py ├── preprocess.py ├── run.py └── show_rgb.py └── src ├── hdrnet ├── GridNet.cpp ├── HdrnetTask.cpp ├── hdrnet_api.cpp └── preprocess.cpp └── utils └── Utils.cpp /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## hdrnet-mobile 3 | #### Introduction 4 | 5 | A C++ implementation of inference part of the paper: *Gharbi, Michaël, et al. "Deep bilateral learning for real-time image enhancement." ACM Transactions on Graphics (TOG) 36.4 (2017): 118*. 6 | 7 | #### Usage 8 | 9 | 1. create binary model dir from tensorflow ( [pretrained models](https://data.csail.mit.edu/graphics/hdrnet/pretrained_models.zip) ) 10 | ```shell 11 | python script/get_tfmodel_value.py 12 | ``` 13 | 14 | 2. build shared library and c++ executable 15 | ```shell 16 | make -B 17 | ``` 18 | 3. test a picture 19 | ```shell 20 | python script/run.py A_PICTURE(like xxx.jpg) your_binary_model_dir 21 | ``` 22 | 23 | #### To be done 24 | 1. optimize the c++ code 25 | 2. create an Android NDK version 26 | 3. use OpenCL to accelerate 27 | 4. retrain the hdrnet+ model, change it to a post process tensorflow model 28 | 29 | 30 | #### Reference 31 | 1. [MIT hdrnet's webpage](https://groups.csail.mit.edu/graphics/hdrnet/) 32 | 2. [Gharbi's hdrnet_legacy(forked)](https://github.com/itchencheng/hdrnet_legacy) 33 | 3. [Pretrained models](https://data.csail.mit.edu/graphics/hdrnet/pretrained_models.zip) 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /bin/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Filename: main.cpp 4 | * Description: cpp file 5 | * 6 | * Version: 1.0 7 | * Created: 2018-10-10 8 | * Author: chencheng 9 | * 10 | * History: initial draft 11 | ******************************************************************************* 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "hdrnet/hdrnet_api.h" 19 | 20 | 21 | int main(int argc, char ** argv) 22 | { 23 | int ret = 0; 24 | const char * dl_name = argv[1]; 25 | const char * model_dir = argv[2]; 26 | 27 | /* input data param */ 28 | const char * input_file = argv[3]; 29 | const char * output_file = argv[4]; 30 | int height = atoi(argv[5]); 31 | int width = atoi(argv[6]); 32 | 33 | int size = height * width * 3; 34 | 35 | unsigned char * rgb_data = new unsigned char [size]; 36 | 37 | 38 | #if 1 //use dlopen 39 | /* dlopen library */ 40 | void * dl_handle = dlopen(dl_name, RTLD_NOW); 41 | if (NULL == dl_handle) { 42 | printf("Error: dlopen %s failed!\n", dl_name); 43 | return -1; 44 | } 45 | 46 | /* dlopen so, get function pointer */ 47 | Func_HDRNET_read_uchar_data_from_file f_HDRNET_read_uchar_data_from_file = NULL; 48 | *(void **)(&f_HDRNET_read_uchar_data_from_file) = dlsym(dl_handle, "HDRNET_read_uchar_data_from_file"); 49 | 50 | Func_HDRNET_write_uchar_data_to_file f_HDRNET_write_uchar_data_to_file = NULL; 51 | *(void **)(&f_HDRNET_write_uchar_data_to_file) = dlsym(dl_handle, "HDRNET_write_uchar_data_to_file"); 52 | 53 | Func_HDRNET_setup f_HDRNET_setup = NULL; 54 | f_HDRNET_setup = (Func_HDRNET_setup)dlsym(dl_handle, "HDRNET_setup"); 55 | 56 | Func_HDRNET_run f_HDRNET_run = NULL; 57 | f_HDRNET_run = (Func_HDRNET_run)dlsym(dl_handle, "HDRNET_run"); 58 | 59 | Func_HDRNET_clean f_HDRNET_clean = NULL; 60 | f_HDRNET_clean = (Func_HDRNET_clean)dlsym(dl_handle, "HDRNET_clean"); 61 | 62 | 63 | /* 1. get data */ 64 | ret = (*f_HDRNET_read_uchar_data_from_file)(rgb_data, size, input_file); 65 | 66 | /* 2. test hdrnet api */ 67 | void * handle; 68 | 69 | ret = (*f_HDRNET_setup)(&handle, model_dir); 70 | 71 | ret = (*f_HDRNET_run)(&handle, rgb_data, rgb_data, height, width); 72 | 73 | ret = (*f_HDRNET_clean)(&handle); 74 | 75 | /* 3. save data */ 76 | ret = (*f_HDRNET_write_uchar_data_to_file)(rgb_data, size, output_file); 77 | 78 | dlclose(dl_handle); 79 | 80 | #else 81 | /* 1. get data */ 82 | ret = HDRNET_read_uchar_data_from_file(rgb_data, size, input_file); 83 | 84 | /* 2. test hdrnet api */ 85 | void * handle; 86 | 87 | ret = HDRNET_setup(&handle, model_dir); 88 | 89 | ret = HDRNET_run(&handle, rgb_data, rgb_data, height, width); 90 | 91 | ret = HDRNET_clean(&handle); 92 | 93 | /* 3. save data */ 94 | ret = HDRNET_write_uchar_data_to_file(rgb_data, size, output_file); 95 | #endif 96 | 97 | delete [] rgb_data; 98 | 99 | return ret; 100 | } -------------------------------------------------------------------------------- /docs/hdrnet-mobile-cn.md: -------------------------------------------------------------------------------- 1 | ## hdrnet-mobile 2 | 3 | #### 1. 简介 4 | 5 | 本项目为文献*Deep Bilateral Learning for Real-Time Image Enhancement*的C++算法实现。 6 | 7 | #### 2. 算法结构 8 | 9 | 全网络分为低分辨率参数预测(Low-Res Coefficient Prediction)和高分辨率处理(High-Res Precessing)两部分。全分辨率的RGB图像full-res input,经下采样处理成256x256的RGB图像low-res input。 10 | 11 | ![whole-arch](img/whole-arch.png) 12 | 13 | ##### 2.1 Low-Res Coefficient Prediction 14 | 15 | 该部分网络结构是由经典CNN Layer构成。 16 | 17 | ![low-res-coeff-prediction](img/low-res-coeff-predict.png) 18 | 19 | 1. 首先采用4层级联的conv层(kernel_size=3x3, stride=2x2),每个conv层后紧跟ReLU激活层。用于提取low-level特征,并降低空间分辨率。feature map尺寸从256x256降低为32x32,feature map的channel数成倍增加。 20 | 2. 采用两层conv层(kernel_size=3x3, stride=1x1)。,用于提取局部特征。 21 | 3. 采用两层conv层和fc层,采用提取全局特征。 22 | 4. 将局部特征和全局特征融合,进行一次conv层,作为3D bilateral grid。 23 | 24 | ##### 2.2 生成引导图(guided map) 25 | 26 | 采用pixel-wise network将full-res input产生full-res灰度图。 27 | 28 | ##### 2.3 sliced coefficients 29 | 30 | 31 | 32 | ##### 2.4 使用slice coeffcients生成处理后的full-res输出 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /docs/hdrnet.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techxzen/hdrnet-mobile/66d34fe5e4d3ad175b4f114fc8800cd0a9a08a44/docs/hdrnet.pptx -------------------------------------------------------------------------------- /docs/help.md: -------------------------------------------------------------------------------- 1 | #### 典型tensorflow模型文件夹 2 | 3 | ![tf_model_dir](/home/chen/myworkspace/projects/hdrnet-mobile/docs/img/tensorflow_model_dir.png) 4 | 5 | 包括4个文件: 6 | 7 | 1. checkpoint 是检查点文件,文件保存了一个目录下所有的模型文件列表; 8 | 2. model.ckpt.meta文件保存了TensorFlow计算图的结构,可以理解为神经网络的网络结构,该文件可以被 tf.train.import_meta_graph 加载到当前默认的图来使用 9 | 3. ckpt.data保存模型中每个变量的取值 10 | 11 | 12 | #### Reference model 13 | 14 | laplacian strong 2014 tensorflow model 15 | 16 | modelname = HDRNetCurves -------------------------------------------------------------------------------- /docs/img/low-res-coeff-predict.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techxzen/hdrnet-mobile/66d34fe5e4d3ad175b4f114fc8800cd0a9a08a44/docs/img/low-res-coeff-predict.png -------------------------------------------------------------------------------- /docs/img/tensorflow_model_dir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techxzen/hdrnet-mobile/66d34fe5e4d3ad175b4f114fc8800cd0a9a08a44/docs/img/tensorflow_model_dir.png -------------------------------------------------------------------------------- /docs/img/whole-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techxzen/hdrnet-mobile/66d34fe5e4d3ad175b4f114fc8800cd0a9a08a44/docs/img/whole-arch.png -------------------------------------------------------------------------------- /docs/network_structure.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techxzen/hdrnet-mobile/66d34fe5e4d3ad175b4f114fc8800cd0a9a08a44/docs/network_structure.xlsx -------------------------------------------------------------------------------- /docs/resize.md: -------------------------------------------------------------------------------- 1 | 2 | ### Resizing Picture 3 | 4 | Using bilinear interpolation: 5 | 6 | Centered: 7 | 8 | -------------------------------------------------------------------------------- /include/cnn/BaseLayer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __BASELAYER_H 3 | #define __BASELAYER_H 4 | 5 | #include "ILayer.h" 6 | 7 | class BaseLayer : public ILayer 8 | { 9 | public: 10 | BaseLayer(float ** in, float ** out, TensorShape in_shape, TensorShape out_shape) 11 | { 12 | _input = in; 13 | _output = out; 14 | _input_shape = in_shape; 15 | _output_shape = out_shape; 16 | } 17 | 18 | public: 19 | float ** _input; 20 | float ** _output; 21 | TensorShape _input_shape; 22 | TensorShape _output_shape; 23 | }; 24 | 25 | 26 | #endif //__BASELAYER_H -------------------------------------------------------------------------------- /include/cnn/ConvolutionLayer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __CONVOLUTIONLAYER_H 3 | #define __CONVOLUTIONLAYER_H 4 | 5 | #include "cnn/BaseLayer.h" 6 | #include "helper.h" 7 | 8 | class ConvolutionLayer final : public BaseLayer 9 | { 10 | public: 11 | ConvolutionLayer(float ** in, float ** out, TensorShape in_shape, TensorShape out_shape, 12 | int k_h, int k_w, int p_h1, int p_h2, int p_w1, int p_w2, int s_h, int s_w, bool bias_flag, bool relu_flag, 13 | const char * weight_file, const char * bias_file 14 | ) : BaseLayer(in, out, in_shape, out_shape), _kernel_h(k_h), _kernel_w(k_w), 15 | _pad_h_up(p_h1), _pad_h_down(p_h2), _pad_w_left(p_w1), _pad_w_right(p_w2), _stride_h(s_h), _stride_w(s_w), 16 | _bias_flag(bias_flag), _relu_flag(relu_flag) 17 | { 18 | // Initialization 19 | int weight_size = _output_shape.c * _input_shape.c * k_h * k_w; 20 | int bias_size = _output_shape.c; 21 | 22 | _weight = new float [weight_size]; 23 | read_data_from_file(_weight, weight_size, weight_file); 24 | 25 | if (_bias_flag) 26 | { 27 | _bias = new float [bias_size]; 28 | read_data_from_file(_bias, bias_size, bias_file); 29 | } 30 | } 31 | 32 | ~ConvolutionLayer() 33 | { 34 | delete [] _weight; 35 | 36 | if (_bias_flag) 37 | { 38 | delete [] _bias; 39 | } 40 | } 41 | 42 | int run() override; 43 | 44 | public: 45 | int _kernel_h; 46 | int _kernel_w; 47 | int _pad_h_up; 48 | int _pad_h_down; 49 | int _pad_w_left; 50 | int _pad_w_right; 51 | int _stride_h; 52 | int _stride_w; 53 | 54 | bool _bias_flag; 55 | bool _relu_flag; 56 | 57 | float * _weight; 58 | float * _bias; 59 | }; 60 | 61 | 62 | int ConvolutionLayer::run() 63 | { 64 | LOGD("# ConvolutionLayer Run!\n"); 65 | 66 | int k_h_r1 = _kernel_h / 2; 67 | int k_h_r2 = _kernel_h / 2; 68 | int k_w_r1 = _kernel_w / 2; 69 | int k_w_r2 = _kernel_w / 2; 70 | 71 | for (int h = 0; h < _output_shape.h; h++) 72 | { 73 | for (int w = 0; w < _output_shape.w; w++) 74 | { 75 | for (int c = 0; c < _output_shape.c; c++) 76 | { 77 | // NHWC 78 | int output_idx = h * _output_shape.w * _output_shape.c + w * _output_shape.c + c; 79 | 80 | float result = 0; 81 | 82 | /* Core computation begins. */ 83 | for (int in_c = 0; in_c < _input_shape.c; in_c++) 84 | { 85 | /* Per channel */ 86 | for (int y = -k_h_r1; y <= k_h_r2; y++) 87 | { 88 | for (int x = -k_w_r1; x <= k_w_r2; x++) 89 | { 90 | int in_h = (h * _stride_h) + (y + k_h_r1) - _pad_h_up; 91 | int in_w = (w * _stride_w) + (x + k_w_r1) - _pad_w_left; 92 | 93 | float in_value = 0; 94 | float wt_value = 0; 95 | 96 | /* get in_value */ 97 | if (in_w < 0 || in_w > (_input_shape.w - 1) || in_h < 0 || in_h > (_input_shape.h - 1)) 98 | { 99 | in_value = 0; 100 | } 101 | else 102 | { 103 | int in_value_idx = in_h * _input_shape.w * _input_shape.c + in_w * _input_shape.c + in_c; 104 | in_value = (*_input)[in_value_idx]; 105 | } 106 | 107 | /* get wt_value */ 108 | /* 109 | if weight shape: (out_c x in_c x kh x kw) 110 | int wt_value_idx = (c * _input_shape.c * _kernel_h * _kernel_w) + 111 | (in_c * _kernel_w * _kernel_h) + 112 | * _kernel_w + 113 | (x + k_w_r1); 114 | */ 115 | 116 | /* 117 | if weight shape: (kh x kw x in_c x out_c) 118 | */ 119 | int wt_value_idx = ((y + k_h_r1) * _kernel_w * _input_shape.c * _output_shape.c) + 120 | (x + k_w_r1) * _input_shape.c * _output_shape.c + 121 | in_c * _output_shape.c + 122 | c; 123 | 124 | wt_value = _weight[wt_value_idx]; 125 | 126 | result += in_value * wt_value; 127 | } 128 | } 129 | } 130 | 131 | if (_bias_flag) 132 | { 133 | result += _bias[c]; 134 | } 135 | 136 | /* If relu followed */ 137 | if (_relu_flag) 138 | { 139 | result = (result > 0) ? result : 0; 140 | } 141 | 142 | (*_output)[output_idx] = result; 143 | } 144 | } 145 | } 146 | 147 | return 0; 148 | } 149 | 150 | 151 | #endif //__CONVOLUTIONLAYER_H -------------------------------------------------------------------------------- /include/cnn/FCLayer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __FCLAYER_H 3 | #define __FCLAYER_H 4 | 5 | #include "cnn/BaseLayer.h" 6 | 7 | 8 | class FCLayer final : public BaseLayer 9 | { 10 | public: 11 | FCLayer(float ** in, float ** out, TensorShape in_shape, TensorShape out_shape, bool bias_flag, bool relu_flag, 12 | const char * weight_file, const char * bias_file 13 | ) : BaseLayer(in, out, in_shape, out_shape), _bias_flag(bias_flag), _relu_flag(relu_flag) 14 | { 15 | // Initialization 16 | int weight_size = _output_shape.c * _input_shape.c; 17 | int bias_size = _output_shape.c; 18 | 19 | _weight = new float [weight_size]; 20 | read_data_from_file(_weight, weight_size, weight_file); 21 | 22 | if (_bias_flag) 23 | { 24 | _bias = new float [bias_size]; 25 | read_data_from_file(_bias, bias_size, bias_file); 26 | } 27 | } 28 | 29 | ~FCLayer() 30 | { 31 | delete [] _weight; 32 | 33 | if (_bias_flag) 34 | { 35 | delete [] _bias; 36 | } 37 | } 38 | 39 | int run() override; 40 | 41 | public: 42 | bool _bias_flag; 43 | bool _relu_flag; 44 | float * _weight; 45 | float * _bias; 46 | 47 | }; 48 | 49 | 50 | int FCLayer::run() 51 | { 52 | LOGD("# FCLayer run!\n"); 53 | 54 | int in_nodes_num = _input_shape.c; 55 | int out_nodes_num = _output_shape.c; 56 | 57 | for (int o = 0; o < out_nodes_num; o++) 58 | { 59 | float result = 0; 60 | 61 | for (int i = 0; i < in_nodes_num; i++) 62 | { 63 | result += (*_input)[i] * _weight[i * out_nodes_num + o]; 64 | } 65 | 66 | if (_bias_flag) 67 | { 68 | result += _bias[o]; 69 | } 70 | 71 | if (_relu_flag) 72 | { 73 | result = (result > 0) ? result : 0; 74 | } 75 | 76 | (*_output)[o] = result; 77 | } 78 | 79 | return 0; 80 | } 81 | 82 | 83 | #endif //__FCLAYER_H -------------------------------------------------------------------------------- /include/cnn/FusionAddLayer.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __FUSIONADDLAYER_H 4 | #define __FUSIONADDLAYER_H 5 | 6 | #include "cnn/BaseLayer.h" 7 | 8 | 9 | class FusionAddLayer final : public BaseLayer 10 | { 11 | public: 12 | FusionAddLayer(float ** in, float ** out, TensorShape in_shape, TensorShape out_shape 13 | ) : BaseLayer(in, out, in_shape, out_shape) 14 | { 15 | // Initialization 16 | } 17 | 18 | int run() override; 19 | }; 20 | 21 | 22 | int FusionAddLayer::run() 23 | { 24 | LOGD("# FusionAddLayer run!\n"); 25 | 26 | for (int h = 0; h < _output_shape.h; h++) 27 | { 28 | for (int w = 0; w < _output_shape.w; w++) 29 | { 30 | for (int c = 0; c < _output_shape.c; c++) 31 | { 32 | int out_idx = c + w * _output_shape.c + h * _output_shape.c * _output_shape.w; 33 | 34 | (*_output)[out_idx] = (*_output)[out_idx] + (*_input)[c]; 35 | } 36 | } 37 | } 38 | 39 | return 0; 40 | } 41 | 42 | 43 | #endif //__FUSIONLAYER_H -------------------------------------------------------------------------------- /include/cnn/ILayer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __ILAYER_H 3 | #define __ILAYER_H 4 | 5 | #include "helper.h" 6 | 7 | 8 | struct TensorShape 9 | { 10 | int n; /* #batch */ 11 | int h; /* #height */ 12 | int w; /* #width */ 13 | int c; /* #channel */ 14 | 15 | int size() const 16 | { 17 | return n * h * w * c; 18 | } 19 | }; 20 | 21 | 22 | class ILayer 23 | { 24 | public: 25 | ILayer() = default; 26 | virtual ~ILayer() = default; 27 | 28 | virtual int run() = 0; 29 | }; 30 | 31 | #endif //__ILAYER_H -------------------------------------------------------------------------------- /include/cnn/ReLULayer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __RELULAYER_H 3 | #define __RELULAYER_H 4 | 5 | #include "cnn/BaseLayer.h" 6 | 7 | 8 | class ReLULayer final : public BaseLayer 9 | { 10 | public: 11 | ReLULayer(float ** in, float ** out, TensorShape in_shape, TensorShape out_shape 12 | ) : BaseLayer(in, out, in_shape, out_shape) 13 | { 14 | // Initialization 15 | } 16 | 17 | int run() override; 18 | 19 | }; 20 | 21 | 22 | int ReLULayer::run() 23 | { 24 | LOGD("# ReLULayer run!\n"); 25 | 26 | for (int i = 0; i < _output_shape.size(); i++) 27 | { 28 | (*_output)[i] = ((*_input)[i] > 0) ? (*_input)[i] : 0; 29 | } 30 | 31 | return 0; 32 | } 33 | 34 | 35 | #endif //__RELULAYER_H -------------------------------------------------------------------------------- /include/cnn/TransposeLayer.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __TRANSPOSELAYER_H 4 | #define __TRANSPOSELAYER_H 5 | 6 | #include "cnn/BaseLayer.h" 7 | 8 | 9 | class TransposeLayer final : public BaseLayer 10 | { 11 | public: 12 | TransposeLayer(float ** in, float ** out, TensorShape in_shape, TensorShape out_shape, 13 | int idx0, int idx1, int idx2, int idx3) : BaseLayer(in, out, in_shape, out_shape) 14 | { 15 | // Initialization 16 | _idx[0] = idx0; 17 | _idx[1] = idx1; 18 | _idx[2] = idx2; 19 | _idx[3] = idx3; 20 | } 21 | 22 | int run() override; 23 | 24 | public: 25 | int _idx[4]; 26 | }; 27 | 28 | 29 | int TransposeLayer::run() 30 | { 31 | LOGD("# TransposeLayer run!\n"); 32 | 33 | int dims[4] = {_input_shape.n, _input_shape.h, _input_shape.w, _input_shape.c}; 34 | int dim_res[4] = {0}; 35 | dim_res[0] = _input_shape.h * _input_shape.w * _input_shape.c; 36 | dim_res[1] = _input_shape.w * _input_shape.c; 37 | dim_res[2] = _input_shape.c; 38 | dim_res[3] = 1; 39 | 40 | int out_idx = 0; 41 | for (int d0 = 0; d0 < dims[_idx[0]]; d0++) 42 | { 43 | for (int d1 = 0; d1 < dims[_idx[1]]; d1++) 44 | { 45 | for (int d2 = 0; d2 < dims[_idx[2]]; d2++) 46 | { 47 | for (int d3 = 0; d3 < dims[_idx[3]]; d3++) 48 | { 49 | int in_idx = d0 * dim_res[_idx[0]] + d1 * dim_res[_idx[1]] + 50 | d2 * dim_res[_idx[2]] + d3 * dim_res[_idx[3]]; 51 | (*_output)[out_idx++] = (*_input)[in_idx]; 52 | } 53 | } 54 | } 55 | } 56 | 57 | return 0; 58 | } 59 | 60 | 61 | #endif //__TRANSPOSELAYER_H -------------------------------------------------------------------------------- /include/hdrnet/GridNet.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __GRID_NET_H 3 | #define __GRID_NET_H 4 | 5 | #include "cnn/ILayer.h" 6 | #include 7 | #include 8 | 9 | class GridNet 10 | { 11 | public: 12 | GridNet(const char * model_dir); 13 | 14 | ~GridNet(); 15 | 16 | int run_network(float * input, float * output); 17 | 18 | 19 | protected: 20 | inline std::string get_model_path_string(const char * relative_path) 21 | { 22 | return (std::string(_model_dir) + std::string("/") + std::string(relative_path)).c_str(); 23 | } 24 | 25 | const char * _model_dir; 26 | 27 | private: 28 | std::vector _layers; 29 | 30 | float ** _input_ptr_ptr; 31 | float ** _output_ptr_ptr; 32 | float * _input_ptr; 33 | float * _output_ptr; 34 | 35 | float * _buf1; 36 | float * _buf2; 37 | float * _buf3; 38 | }; 39 | 40 | #endif -------------------------------------------------------------------------------- /include/hdrnet/HdrnetTask.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __HDRNET_TASK_H 3 | #define __HDRNET_TASK_H 4 | 5 | #include "hdrnet/GridNet.h" 6 | 7 | 8 | class HdrnetTask : public GridNet 9 | { 10 | public: 11 | HdrnetTask(const char * model_dir); 12 | 13 | ~HdrnetTask(); 14 | 15 | int run_task(float * in, float * out, int height, int width); 16 | 17 | private: 18 | int resize(float * src, float * dst, int src_height, int src_width, int dst_height, int dst_width); 19 | 20 | int generate_bilateral_grid( 21 | float * in, 22 | float * out 23 | ); 24 | 25 | int generate_guide_map( 26 | float * full_res, //full res HWC 27 | float * guide_out, //full res 28 | int height, 29 | int width 30 | ); 31 | 32 | int apply_slicing_layer_and_assemble( 33 | float * img_in, // full_res, HWC format 34 | float * grid, // coeeff, 16x16x8x3x4 35 | float * guide_map, // guide map 36 | float * img_out, 37 | int height, 38 | int width 39 | ); 40 | 41 | private: 42 | float * _ccm; 43 | float * _ccm_bias; 44 | float * _shifts; 45 | float * _slopes; 46 | float * _channel_mix_weight; 47 | float * _channel_mix_bias; 48 | 49 | // buffer 50 | float * _lowres_img_hwc; 51 | float * _bilateral_grid; 52 | }; 53 | 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /include/hdrnet/hdrnet_api.h: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Filename: template.cpp 4 | * Description: cpp file 5 | * 6 | * Version: 1.0 7 | * Created: 2018-07-20 8 | * Author: chencheng 9 | * 10 | * History: initial draft 11 | ******************************************************************************* 12 | */ 13 | 14 | #ifndef __HDRNET_API_H 15 | #define __HDRNET_API_H 16 | 17 | extern "C" 18 | { 19 | /* HDRNET_Setup */ 20 | int HDRNET_setup(void ** handle, const char * model_dir); 21 | 22 | /* HDRNET_Run */ 23 | int HDRNET_run(void ** handle, unsigned char * src_data, unsigned char * dst_data, int height, int width); 24 | 25 | /* HDRNET_Clean */ 26 | int HDRNET_clean(void ** handle); 27 | 28 | /* HDRNET read & write */ 29 | int HDRNET_read_uchar_data_from_file(unsigned char * data, int size, const char * file_name); 30 | 31 | int HDRNET_read_float_data_from_file(float * data, int size, const char * file_name); 32 | 33 | int HDRNET_write_uchar_data_to_file(unsigned char * data, int size, const char * file_name); 34 | 35 | int HDRNET_write_float_data_to_file(float * data, int size, const char * file_name); 36 | 37 | /* function pointer */ 38 | typedef int (* Func_HDRNET_setup)(void ** handle, const char * model_dir); 39 | typedef int (* Func_HDRNET_run)(void ** handle, unsigned char * src_data, unsigned char * dst_data, int height, int width); 40 | typedef int (* Func_HDRNET_clean)(void ** handle); 41 | 42 | typedef int (* Func_HDRNET_read_uchar_data_from_file)(unsigned char * data, int size, const char * file_name); 43 | typedef int (* Func_HDRNET_read_float_data_from_file)(float * data, int size, const char * file_name); 44 | typedef int (* Func_HDRNET_write_uchar_data_to_file)(unsigned char * data, int size, const char * file_name); 45 | typedef int (* Func_HDRNET_write_float_data_to_file)(float * data, int size, const char * file_name); 46 | } 47 | 48 | #endif // __HDRNET_API_H -------------------------------------------------------------------------------- /include/hdrnet/preprocess.h: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Filename: preoprocess.h 4 | * Description: header file 5 | * 6 | * Version: 1.0 7 | * Created: 2018-10-10 8 | * Author: chencheng 9 | * 10 | * History: initial draft 11 | ******************************************************************************* 12 | */ 13 | 14 | #ifndef __PREPROCESS_H 15 | #define __PREPROCESS_H 16 | 17 | #define UINT8 unsigned char 18 | 19 | int normalize_data_to_float(UINT8 * char_data, float * float_data, int size); 20 | 21 | int convert_float_to_char(float * float_data, UINT8 * char_data, int size); 22 | 23 | int resize(float * src, float * dst, int src_height, int src_width, int dst_height, int dst_width); 24 | 25 | 26 | #endif // __PREPROCESS_H -------------------------------------------------------------------------------- /include/hdrnet/type.h: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Filename: type.h 4 | * Description: header file 5 | * 6 | * Version: 1.0 7 | * Created: 2018-10-10 8 | * Author: chencheng 9 | * 10 | * History: initial draft 11 | ******************************************************************************* 12 | */ 13 | 14 | #ifndef __TYPE_H 15 | #define __TYPE_H 16 | 17 | using UINT8 = unsigned char; 18 | 19 | #endif -------------------------------------------------------------------------------- /include/helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Filename: helper.h 4 | * Description: header file 5 | * 6 | * Version: 1.0 7 | * Created: 2018-10-10 8 | * Author: chencheng 9 | * 10 | * History: initial draft 11 | ******************************************************************************* 12 | */ 13 | 14 | #ifndef __HELPER_H 15 | #define __HELPER_H 16 | 17 | #include 18 | 19 | #define LOGE(msg...) printf(msg); 20 | #define LOGD(msg...) printf(msg); 21 | 22 | #endif // __HELPER_H -------------------------------------------------------------------------------- /include/utils/Utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Filename: Utils.h 4 | * Description: header file 5 | * 6 | * Version: 1.0 7 | * Created: 2018-10-10 8 | * Author: chencheng 9 | * 10 | * History: initial draft 11 | ******************************************************************************* 12 | */ 13 | 14 | #ifndef __UTILS_H 15 | #define __UTILS_H 16 | 17 | #define UINT8 unsigned char 18 | 19 | template 20 | int read_data_from_file(Type * data, int size, const char * file_name); 21 | 22 | int write_data_to_file(UINT8 * data, int size, const char * file_name); 23 | 24 | int write_data_to_file(float * data, int size, const char * file_name); 25 | 26 | #endif // __UTILS_H -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | 2 | INC_DIR = ./include 3 | SRC_DIR = ./src 4 | OBJ_DIR = ./obj 5 | LIB_DIR = ./lib 6 | BIN_DIR = ./bin 7 | 8 | UTILS_SRC = $(wildcard ${SRC_DIR}/utils/*.cpp) 9 | UTILS_OBJ = $(patsubst %.cpp,${OBJ_DIR}/%.o,$(notdir ${UTILS_SRC})) 10 | 11 | HDRNET_SRC = $(wildcard ${SRC_DIR}/hdrnet/*.cpp) 12 | HDRNET_OBJ = $(patsubst %.cpp,${OBJ_DIR}/%.o,$(notdir ${HDRNET_SRC})) 13 | 14 | CNN_SRC = $(wildcard ${SRC_DIR}/cnn/*.cpp) 15 | CNN_OBJ = $(patsubst %.cpp,${OBJ_DIR}/%.o,$(notdir ${CNN_SRC})) 16 | 17 | SO_NAME = hdrnet_api 18 | SO_FILE = $(LIB_DIR)/lib$(SO_NAME).so 19 | 20 | TARGET = main 21 | BIN_TARGET = ${BIN_DIR}/${TARGET} 22 | BIN_FILE = $(BIN_DIR)/${TARGET}.cpp 23 | 24 | 25 | CC = g++ 26 | CFLAGS = -std=c++11 -O3 -Wall -fPIC -I${INC_DIR} -DMODEL_DIR=$(MODEL_DIR) -DDEBUG 27 | 28 | 29 | 30 | # build main 31 | ${BIN_TARGET}: $(SO_FILE) 32 | $(CC) $(CFLAGS) $(BIN_FILE) -L $(LIB_DIR) -l$(SO_NAME) -o $@ -ldl 33 | 34 | # so file 35 | $(SO_FILE): $(UTILS_OBJ) $(HDRNET_OBJ) $(CNN_OBJ) 36 | mkdir -p $(LIB_DIR) 37 | ld -shared $^ -o $@ 38 | 39 | # build 40 | ${OBJ_DIR}/%.o:${SRC_DIR}/hdrnet/%.cpp 41 | mkdir -p $(OBJ_DIR) 42 | $(CC) $(CFLAGS) -c $^ -o $@ 43 | 44 | ${OBJ_DIR}/%.o:${SRC_DIR}/utils/%.cpp 45 | mkdir -p $(OBJ_DIR) 46 | $(CC) $(CFLAGS) -c $^ -o $@ 47 | 48 | 49 | ndk-dll: 50 | ndk-build -C ndk/dll/jni -B 51 | 52 | ndk-main: 53 | ndk-build -C ndk/main/jni -B 54 | 55 | .PHONY:clean 56 | clean: 57 | -rm -rf $(OBJ_DIR) 58 | -rm -rf $(LIB_DIR) 59 | -rm $(BIN_TARGET) 60 | -rm *.rgb 61 | -rm *.rgb.jpg 62 | -rm *.so 63 | -rm script/*.pyc 64 | -rm -rf ndk/dll/libs 65 | -rm -rf ndk/dll/obj 66 | -rm -rf ndk/main/libs 67 | -rm -rf ndk/main/obj 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /ndk/dll/jni/Android.mk: -------------------------------------------------------------------------------- 1 | # Android.mk 2 | # Usage: to build NDK shared library 3 | 4 | # Convention 5 | LOCAL_PATH := $(call my-dir) 6 | include $(CLEAR_VARS) 7 | LOCAL_MODULE := hdrnet_api 8 | 9 | # Target Arch Info 10 | #TARGET_PLATFORM := android-27 11 | #TARGET_ARCH_ABI := arm64-v8a 12 | 13 | # Include Files 14 | MY_PROJECT_PATH := $(LOCAL_PATH)/../../../ 15 | LOCAL_C_INCLUDES := $(MY_PROJECT_PATH)/include/ 16 | 17 | # Src Files 18 | SRC_DIR = $(MY_PROJECT_PATH)/src/ 19 | HDRNET_SRC = $(wildcard ${SRC_DIR}/hdrnet/*.cpp) 20 | UTILS_SRC = $(wildcard ${SRC_DIR}/utils/*.cpp) 21 | CNN_SRC = $(wildcard ${SRC_DIR}/cnn/*.cpp) 22 | LOCAL_SRC_FILES := $(HDRNET_SRC) $(UTILS_SRC) $(CNN_SRC) 23 | 24 | # Build Options 25 | LOCAL_CFLAGS += -std=c++11 26 | 27 | 28 | # Needed Shared Libs 29 | #LOCAL_LDLIBS := 30 | 31 | include $(BUILD_SHARED_LIBRARY) 32 | #include $(BUILD_STATIC_LIBRARY) 33 | #include $(BUILD_EXECUTABLE) -------------------------------------------------------------------------------- /ndk/dll/jni/Application.mk: -------------------------------------------------------------------------------- 1 | 2 | APP_OPTIM := release 3 | 4 | APP_STL := c++_static 5 | 6 | APP_PLATFORM := android-27 7 | 8 | NDK_TOOLCHAIN_VERSION := clang 9 | 10 | APP_ABI := arm64-v8a -------------------------------------------------------------------------------- /ndk/main/jni/Android.mk: -------------------------------------------------------------------------------- 1 | # Android.mk 2 | # Usage: to build NDK shared library 3 | 4 | # Convention 5 | LOCAL_PATH := $(call my-dir) 6 | include $(CLEAR_VARS) 7 | LOCAL_MODULE := main 8 | 9 | # Target Arch Info 10 | #TARGET_PLATFORM := android-27 11 | #TARGET_ARCH_ABI := arm64-v8a 12 | 13 | # Include Files 14 | MY_PROJECT_PATH := $(LOCAL_PATH)/../../../ 15 | LOCAL_C_INCLUDES := $(MY_PROJECT_PATH)/include/ 16 | 17 | # Src Files 18 | LOCAL_SRC_FILES := $(MY_PROJECT_PATH)/bin/main.cpp 19 | 20 | # Build Options 21 | LOCAL_CFLAGS += -std=c++11 22 | 23 | 24 | # Needed Shared Libs 25 | LOCAL_LDLIBS := -L$(MY_PROJECT_PATH)/ndk/dll/libs/arm64-v8a/ -lhdrnet_api 26 | 27 | 28 | include $(BUILD_EXECUTABLE) -------------------------------------------------------------------------------- /ndk/main/jni/Application.mk: -------------------------------------------------------------------------------- 1 | 2 | APP_OPTIM := release 3 | 4 | APP_STL := c++_static 5 | 6 | APP_PLATFORM := android-27 7 | 8 | NDK_TOOLCHAIN_VERSION := clang 9 | 10 | APP_ABI := arm64-v8a -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### README.md 3 | 4 | 本目录用于创建python api,调用hdrnet c++ api. -------------------------------------------------------------------------------- /script/generate_rgb_raw.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import sys 4 | import cv2 5 | import numpy as np 6 | import os 7 | 8 | 9 | def generate_rgb_raw(input_path): 10 | input_img = cv2.imread(input_path, -1) 11 | if input_img.shape[2] == 4: 12 | log.info("Input {} has 4 channels, dropping alpha".format(input_path)) 13 | input_img = input_img[:, :, :3] 14 | 15 | input_img = np.flip(input_img, 2) # OpenCV reads BGR, convert back to RGB. 16 | 17 | height, width, channel = input_img.shape 18 | 19 | ''' save to binary file ''' 20 | input_path_dirname = os.path.dirname(input_path) 21 | input_path_basename = os.path.basename(input_path) 22 | input_path_name = input_path_basename.split('.')[0] 23 | input_path_type = input_path_basename.split('.')[1] 24 | output_path = input_path_dirname + '/' + input_path_name + '_%dx%dx%d.rgb' %(height, width, channel) 25 | print(input_img.dtype) 26 | input_img.tofile(output_path) 27 | print(output_path) 28 | 29 | return height, width, output_path 30 | 31 | 32 | 33 | def main(): 34 | input_path = sys.argv[1] 35 | generate_rgb_raw(input_path) 36 | 37 | 38 | 39 | if __name__ == "__main__": 40 | main() -------------------------------------------------------------------------------- /script/get_tfmodel_value.py: -------------------------------------------------------------------------------- 1 | 2 | import tensorflow as tf 3 | 4 | 5 | ckpt_file = "/home/chen/myworkspace/projects/sample_data/pretrained_models/local_laplacian/strong_1024/upgraded_from_sig2017.ckpt-0" 6 | dest_path = '/home/chen/myworkspace/projects/sample_data/pretrained_models/local_laplacian/strong_1024/binaries/' 7 | 8 | 9 | reader = tf.train.NewCheckpointReader(ckpt_file) 10 | var_dict = reader.get_variable_to_shape_map() 11 | 12 | var_tuple = sorted(var_dict.items(), key = lambda v:v[0], reverse=False) 13 | 14 | for key, shape in var_tuple: 15 | include1 = "inference" 16 | include2 = "splat" 17 | include3 = "guide" 18 | exclude = "Adam" 19 | if (include1 in key or include2 in key or include3 in key) and exclude not in key: 20 | print('') 21 | print((key, shape)) 22 | ''' get file_name string ''' 23 | file_name = key.replace('/', '-') 24 | ''' get shape string ''' 25 | shape_str = '' 26 | for i in range(len(shape) - 1): 27 | shape_str += '%dx' %(shape[i]) 28 | shape_str += '%d' %(shape[len(shape) - 1]) 29 | 30 | print((file_name, shape_str)) 31 | weights = reader.get_tensor(key) 32 | print(type(weights.dtype)) 33 | print(weights.dtype) 34 | ''' save to file ''' 35 | weights.tofile(dest_path + file_name + '.float32' + '-' + shape_str) 36 | 37 | print("Transfrom tensorflow-model to binaries.") -------------------------------------------------------------------------------- /script/preprocess.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import cv2 4 | import skimage 5 | import skimage.transform 6 | import numpy as np 7 | 8 | 9 | def main(): 10 | ''' read image ''' 11 | input_file = "/home/chen/myworkspace/projects/hdrnet-mobile/../sample_data/input.png" 12 | input_img = cv2.imread(input_file, -1) 13 | if input_img.shape[2] == 4: 14 | log.info("Input {} has 4 channels, dropping alpha".format(input_path)) 15 | input_img = input_img[:, :, :3] 16 | 17 | input_img = np.flip(input_img, 2) # OpenCV reads BGR, convert back to RGB. 18 | 19 | ''' hack for hdr+, convert to [0, 1], similar to y = x/255.0 ''' 20 | input_img = skimage.img_as_float(input_img) 21 | print(input_img) 22 | 23 | ''' low resolution image ''' 24 | lowres_input = skimage.transform.resize(input_img, [256, 256], order = 0) 25 | print(lowres_input.shape) 26 | 27 | ''' set output name ''' 28 | output_path = input_file + '-output.png' 29 | print(output_path) 30 | 31 | input_img = input_img[np.newaxis, :, :, :] 32 | lowres_input = lowres_input[np.newaxis, :, :, :] 33 | 34 | print(input_img.shape) 35 | print(lowres_input.shape) 36 | 37 | # out_ = sess.run(output, feed_dict=feed_dict) 38 | 39 | 40 | if __name__ == "__main__": 41 | main() 42 | -------------------------------------------------------------------------------- /script/run.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | import os 4 | import re 5 | 6 | import generate_rgb_raw 7 | import show_rgb 8 | 9 | 10 | def main(): 11 | img_file = sys.argv[1] 12 | 13 | if (len(sys.argv) > 2): 14 | model_dir = sys.argv[2] 15 | else: 16 | model_dir = "/home/chen/myworkspace/projects/sample_data/pretrained_models/local_laplacian/strong_1024/binaries/" 17 | 18 | project_dir = "/home/chen/myworkspace/projects/hdrnet-mobile/" 19 | 20 | # create input rgb 21 | h, w, rgb_file = generate_rgb_raw.generate_rgb_raw(img_file) 22 | out_file = rgb_file + '.output' 23 | 24 | # run main 25 | cmd = '' 26 | cmd += project_dir + 'bin/main ' 27 | cmd += project_dir + 'lib/libhdrnet_api.so ' 28 | cmd += '%s ' %(model_dir) 29 | cmd += '%s ' %(rgb_file) 30 | cmd += '%s ' %(out_file) 31 | cmd += '%d ' %(h) 32 | cmd += '%d ' %(w) 33 | os.system(cmd) 34 | 35 | # show output rgb 36 | show_rgb.show_rgb(out_file, h, w) 37 | 38 | # rm rgb 39 | cmd = "rm %s" %(rgb_file) 40 | os.system(cmd) 41 | cmd = "rm %s" %(out_file) 42 | os.system(cmd) 43 | 44 | 45 | if __name__ == "__main__": 46 | main() -------------------------------------------------------------------------------- /script/show_rgb.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import sys 4 | import cv2 5 | import numpy as np 6 | import os 7 | 8 | 9 | def show_rgb(input_path, height, width): 10 | input_file = np.fromfile(input_path, dtype=np.uint8) 11 | input_file.shape = (height, width, 3) 12 | 13 | input_file = np.flip(input_file, 2) # OpenCV reads BGR, convert back to RGB. 14 | 15 | ''' save to binary file ''' 16 | output_path = input_path + '.jpg' 17 | cv2.imwrite(output_path, input_file) 18 | print(output_path) 19 | 20 | 21 | 22 | def main(): 23 | if (len(sys.argv) < 4): 24 | print("Error: use python show_rgb.py xx.rgb h w") 25 | exit(-1) 26 | input_path = sys.argv[1] 27 | height = np.int(sys.argv[2]) 28 | width = np.int(sys.argv[3]) 29 | show_rgb(input_path, height, width) 30 | 31 | 32 | 33 | if __name__ == "__main__": 34 | main() -------------------------------------------------------------------------------- /src/hdrnet/GridNet.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "hdrnet/GridNet.h" 3 | #include "utils/Utils.h" 4 | #include "cnn/ConvolutionLayer.h" 5 | #include "cnn/FCLayer.h" 6 | #include "cnn/ReLULayer.h" 7 | #include "cnn/TransposeLayer.h" 8 | #include "cnn/FusionAddLayer.h" 9 | #include "helper.h" 10 | 11 | #include 12 | 13 | 14 | GridNet::GridNet(const char * model_dir):_model_dir(model_dir) 15 | { 16 | _input_ptr_ptr = &_input_ptr; 17 | _output_ptr_ptr = &_output_ptr; 18 | 19 | /* Allocate tmp buffer */ 20 | _buf1 = new float [1 * 8 * 128 * 128]; 21 | _buf2 = new float [1 * 16 * 64 * 64]; 22 | _buf3 = new float [1 * 64 * 16 * 16]; 23 | 24 | // construct network 25 | /* kh, kw, ph, pw, sh, sw */ 26 | int kh, kw, ph1, ph2, pw1, pw2, sh, sw; 27 | bool relu_flag; 28 | bool bias_flag; 29 | 30 | _layers.clear(); 31 | 32 | /* Low level features */ 33 | ConvolutionLayer * layer1 = new ConvolutionLayer(_input_ptr_ptr, &_buf1, {1,256,256,3}, {1,128,128,8}, 34 | kh=3, kw=3, ph1=0, ph2=1, pw1=0, pw2=1, sh=2, sw=2, bias_flag=true, relu_flag=true, 35 | get_model_path_string("inference-coefficients-splat-conv1-weights.float32-3x3x3x8").c_str(), 36 | get_model_path_string("inference-coefficients-splat-conv1-biases.float32-8").c_str()); 37 | _layers.push_back( layer1 ); 38 | 39 | ConvolutionLayer * layer2 = new ConvolutionLayer(&_buf1, &_buf2, {1,128,128,8}, {1,64,64,16 }, 40 | kh=3, kw=3, ph1=0, ph2=1, pw1=0, pw2=1, sh=2, sw=2, bias_flag=true, relu_flag=true, 41 | get_model_path_string("inference-coefficients-splat-conv2-weights.float32-3x3x8x16").c_str(), 42 | get_model_path_string("inference-coefficients-splat-conv2-biases.float32-16").c_str()); 43 | _layers.push_back( layer2 ); 44 | 45 | ConvolutionLayer * layer3 = new ConvolutionLayer(&_buf2, &_buf1, {1,64,64,16 }, {1,32,32,32 }, 46 | kh=3, kw=3, ph1=0, ph2=1, pw1=0, pw2=1, sh=2, sw=2, bias_flag=true, relu_flag=true, 47 | get_model_path_string("inference-coefficients-splat-conv3-weights.float32-3x3x16x32").c_str(), 48 | get_model_path_string("inference-coefficients-splat-conv3-biases.float32-32").c_str()); 49 | _layers.push_back( layer3 ); 50 | 51 | ConvolutionLayer * layer4 = new ConvolutionLayer(&_buf1, &_buf2, {1,32,32,32 }, {1,16,16,64 }, 52 | kh=3, kw=3, ph1=0, ph2=1, pw1=0, pw2=1, sh=2, sw=2, bias_flag=true, relu_flag=true, 53 | get_model_path_string("inference-coefficients-splat-conv4-weights.float32-3x3x32x64").c_str(), 54 | get_model_path_string("inference-coefficients-splat-conv4-biases.float32-64").c_str()); 55 | _layers.push_back( layer4 ); 56 | 57 | /* Local features */ 58 | // use buf2 as input, buf3 as output 59 | ConvolutionLayer * layer5 = new ConvolutionLayer(&_buf2, &_buf1, {1,16,16,64 }, {1,16,16,64 }, 60 | kh=3, kw=3, ph1=1, ph2=1, pw1=1, pw2=1, sh=1, sw=1, bias_flag=true, relu_flag=true, 61 | get_model_path_string("inference-coefficients-local-conv1-weights.float32-3x3x64x64").c_str(), 62 | get_model_path_string("inference-coefficients-local-conv1-biases.float32-64").c_str()); 63 | _layers.push_back( layer5 ); 64 | 65 | ConvolutionLayer * layer6 = new ConvolutionLayer(&_buf1, &_buf3, {1,16,16,64 }, {1,16,16,64 }, 66 | kh=3, kw=3, ph1=1, ph2=1, pw1=1, pw2=1, sh=1, sw=1, bias_flag=false, relu_flag=false, 67 | get_model_path_string("inference-coefficients-local-conv2-weights.float32-3x3x64x64").c_str(), 68 | nullptr); 69 | _layers.push_back( layer6 ); 70 | 71 | /* Global features */ 72 | // also use buf2 as input, buf1 as output 73 | ConvolutionLayer * layer7 = new ConvolutionLayer(&_buf2, &_buf1, {1,16,16,64 }, {1,8,8,64 }, 74 | kh=3, kw=3, ph1=0, ph2=1, pw1=0, pw2=1, sh=2, sw=2, bias_flag=true, relu_flag=true, 75 | get_model_path_string("inference-coefficients-global-conv1-weights.float32-3x3x64x64").c_str(), 76 | get_model_path_string("inference-coefficients-global-conv1-biases.float32-64").c_str()); 77 | _layers.push_back( layer7 ); 78 | 79 | ConvolutionLayer * layer8 = new ConvolutionLayer(&_buf1, &_buf2, {1,8,8,64 }, {1,4,4,64 }, 80 | kh=3, kw=3, ph1=0, ph2=1, pw1=0, pw2=1, sh=2, sw=2, bias_flag=true, relu_flag=true, 81 | get_model_path_string("inference-coefficients-global-conv2-weights.float32-3x3x64x64").c_str(), 82 | get_model_path_string("inference-coefficients-global-conv2-biases.float32-64").c_str()); 83 | _layers.push_back( layer8 ); 84 | 85 | FCLayer * layer10 = new FCLayer(&_buf2, &_buf1, {1,1,1,1024}, {1,1,1,256}, bias_flag=true, relu_flag=true, 86 | get_model_path_string("inference-coefficients-global-fc1-weights.float32-1024x256").c_str(), 87 | get_model_path_string("inference-coefficients-global-fc1-biases.float32-256").c_str()); 88 | _layers.push_back( layer10 ); 89 | 90 | FCLayer * layer11 = new FCLayer(&_buf1, &_buf2, {1,1,1,256}, {1,1,1,128}, bias_flag=true, relu_flag=true, 91 | get_model_path_string("inference-coefficients-global-fc2-weights.float32-256x128").c_str(), 92 | get_model_path_string("inference-coefficients-global-fc2-biases.float32-128").c_str()); 93 | _layers.push_back( layer11 ); 94 | 95 | FCLayer * layer12 = new FCLayer(&_buf2, &_buf1, {1,1,1,128}, {1,1,1,64}, bias_flag=true, relu_flag=false, 96 | get_model_path_string("inference-coefficients-global-fc3-weights.float32-128x64").c_str(), 97 | get_model_path_string("inference-coefficients-global-fc3-biases.float32-64").c_str()); 98 | _layers.push_back( layer12 ); 99 | 100 | /* Fusion of local and global features */ 101 | // merge buf3 and buf2 to buf2, and relu to buf1 102 | FusionAddLayer * layer13 = new FusionAddLayer(&_buf1, &_buf3, {1,1,1,64}, {1,16,16,64}); 103 | _layers.push_back( layer13 ); 104 | 105 | ReLULayer * layer14 = new ReLULayer(&_buf3, &_buf1, {1,16,16,64}, {1,16,16,64}); 106 | _layers.push_back( layer14 ); 107 | 108 | /* Prediction */ 109 | ConvolutionLayer * layer15 = new ConvolutionLayer(&_buf1, &_buf2, {1,16,16,64}, {1,16,16,96}, 110 | kh=1, kw=1, ph1=0, ph2=0, pw1=0, pw2=0, sh=1, sw=1, bias_flag=true, relu_flag=false, 111 | get_model_path_string("inference-coefficients-prediction-conv1-weights.float32-1x1x64x96").c_str(), 112 | get_model_path_string("inference-coefficients-prediction-conv1-biases.float32-96").c_str()); 113 | _layers.push_back( layer15 ); 114 | 115 | /* Transpose */ 116 | // 16x16x12x8 -> 16x16x8x12 117 | TransposeLayer * layer16 = new TransposeLayer(&_buf2, _output_ptr_ptr, {256, 4, 3, 8}, {256, 8, 3, 4}, 118 | 0, 3, 2, 1); 119 | _layers.push_back( layer16 ); 120 | 121 | } 122 | 123 | 124 | GridNet::~GridNet() 125 | { 126 | for (auto it = _layers.begin(); it != _layers.end(); it++) 127 | { 128 | delete (*it); 129 | } 130 | 131 | _layers.clear(); 132 | 133 | delete [] _buf1; 134 | delete [] _buf2; 135 | delete [] _buf3; 136 | 137 | } 138 | 139 | 140 | int GridNet::run_network(float * input, float * output) 141 | { 142 | _input_ptr = input; 143 | _output_ptr = output; 144 | 145 | // run network 146 | for (auto it = _layers.begin(); it != _layers.end(); it++) 147 | { 148 | (*it)->run(); 149 | } 150 | 151 | return 0; 152 | } 153 | 154 | -------------------------------------------------------------------------------- /src/hdrnet/HdrnetTask.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "hdrnet/HdrnetTask.h" 3 | #include "utils/Utils.h" 4 | 5 | #include 6 | #include 7 | #include "helper.h" 8 | 9 | HdrnetTask::HdrnetTask(const char * model_dir) : GridNet(model_dir) 10 | { 11 | // param 12 | _ccm = new float [3 * 3]; 13 | _ccm_bias = new float [3]; 14 | _shifts = new float [1 * 1 * 3 * 16]; 15 | _slopes = new float [1 * 1 * 1 * 3 * 16]; 16 | _channel_mix_weight = new float [3]; 17 | _channel_mix_bias = new float [1]; 18 | 19 | read_data_from_file(_ccm, 3 * 3, get_model_path_string("inference-guide-ccm.float32-3x3").c_str()); 20 | 21 | read_data_from_file(_ccm_bias, 3, get_model_path_string("inference-guide-ccm_bias.float32-3").c_str()); 22 | 23 | read_data_from_file(_shifts, 1 * 1 * 3 * 16, get_model_path_string("inference-guide-shifts.float32-1x1x3x16").c_str()); 24 | 25 | read_data_from_file(_slopes, 1 * 1 * 1 * 3 * 16, get_model_path_string("inference-guide-slopes.float32-1x1x1x3x16").c_str()); 26 | 27 | read_data_from_file(_channel_mix_weight, 1 * 1 * 3 * 1, get_model_path_string("inference-guide-channel_mixing-weights.float32-1x1x3x1").c_str()); 28 | 29 | read_data_from_file(_channel_mix_bias, 1, get_model_path_string("inference-guide-channel_mixing-biases.float32-1").c_str()); 30 | 31 | //buffer 32 | _lowres_img_hwc = new float [256 * 256 * 3]; 33 | _bilateral_grid = new float [16 * 16 * 96]; 34 | 35 | } 36 | 37 | 38 | HdrnetTask::~HdrnetTask() 39 | { 40 | // release buffer 41 | delete [] _ccm; 42 | delete [] _ccm_bias; 43 | delete [] _shifts; 44 | delete [] _slopes; 45 | delete [] _channel_mix_bias; 46 | delete [] _channel_mix_weight; 47 | 48 | } 49 | 50 | 51 | int HdrnetTask::run_task(float * in, float * out, int height, int width) 52 | { 53 | int size = height * width; 54 | float * guide_map = new float [size]; 55 | 56 | resize(in, _lowres_img_hwc, height, width, 256, 256); 57 | 58 | generate_bilateral_grid(_lowres_img_hwc, _bilateral_grid); 59 | 60 | generate_guide_map(in, guide_map, height, width); 61 | 62 | apply_slicing_layer_and_assemble(in, _bilateral_grid, guide_map, out, height, width); 63 | 64 | delete [] guide_map; 65 | 66 | return 0; 67 | } 68 | 69 | 70 | int HdrnetTask::resize(float * src, float * dst, int src_height, int src_width, int dst_height, int dst_width) 71 | { 72 | for (int h = 0; h < dst_height; h++) 73 | { 74 | for (int w = 0; w < dst_width; w++) 75 | { 76 | float crespond_h = (h + 0.5f) * src_height / (1.0f * dst_height) - 0.5f; 77 | float crespond_w = (w + 0.5f) * src_width / (1.0f * dst_width) - 0.5f; 78 | 79 | int floor_h = static_cast(floor(crespond_h)); 80 | int floor_w = static_cast(floor(crespond_w)); 81 | 82 | float value_r = 0.0f; 83 | float value_g = 0.0f; 84 | float value_b = 0.0f; 85 | 86 | for (int hh = floor_h; hh < floor_h + 2; hh++) 87 | { 88 | int h_idx = std::max(std::min(hh, src_height - 1), 0); 89 | float h_ratio = std::max(1.0f - std::abs(crespond_h - hh), 0.0f); 90 | 91 | for (int ww = floor_w; ww < floor_w + 2; ww++) 92 | { 93 | int w_idx = std::max(std::min(ww, src_width - 1), 0); 94 | float w_ratio = std::max(1.0f - std::abs(crespond_w - ww), 0.0f); 95 | 96 | int in_idx = h_idx * src_width + w_idx; 97 | value_r += src[in_idx * 3 + 0] * h_ratio * w_ratio; 98 | value_g += src[in_idx * 3 + 1] * h_ratio * w_ratio; 99 | value_b += src[in_idx * 3 + 2] * h_ratio * w_ratio; 100 | } 101 | } 102 | 103 | int dst_pos = h * dst_width + w; 104 | 105 | dst[dst_pos * 3 + 0] = value_r; 106 | dst[dst_pos * 3 + 1] = value_g; 107 | dst[dst_pos * 3 + 2] = value_b; 108 | } 109 | } 110 | 111 | return 0; 112 | } 113 | 114 | 115 | 116 | int HdrnetTask::generate_bilateral_grid( 117 | float * in, 118 | float * out 119 | ) 120 | { 121 | LOGD("# Run AI ...\n"); 122 | 123 | run_network(in, out); 124 | 125 | return 0; 126 | } 127 | 128 | 129 | int HdrnetTask::generate_guide_map( 130 | float * full_res, //full res HWC 131 | float * guide_out, //full res 132 | int height, 133 | int width 134 | ) 135 | { 136 | for (int h = 0; h < height; h++) 137 | { 138 | for (int w = 0; w < width; w++) 139 | { 140 | float r, g, b; 141 | r = full_res[h * width * 3 + w * 3 + 0]; 142 | g = full_res[h * width * 3 + w * 3 + 1]; 143 | b = full_res[h * width * 3 + w * 3 + 2]; 144 | 145 | /* use ccm, create new r, g, b value 146 | transpose([new_r, new_g, new_b]) = [r,g,b] * ccm + bias 147 | */ 148 | float new_r, new_g, new_b; 149 | 150 | new_r = _ccm[0] * r + _ccm[3] * g + _ccm[6] * b + _ccm_bias[0]; 151 | new_g = _ccm[1] * r + _ccm[4] * g + _ccm[7] * b + _ccm_bias[1]; 152 | new_b = _ccm[2] * r + _ccm[5] * g + _ccm[8] * b + _ccm_bias[2]; 153 | 154 | /* use slope and shifts per channel */ 155 | float guide_r = 0; 156 | float guide_g = 0; 157 | float guide_b = 0; 158 | for (int i = 0; i < 16; i++) 159 | { 160 | guide_r += _slopes[i] * std::max(new_r - _shifts[i], float(0)); 161 | guide_g += _slopes[i + 16] * std::max(new_g - _shifts[i + 16], float(0)); 162 | guide_b += _slopes[i + 32] * std::max(new_b - _shifts[i + 32], float(0)); 163 | } 164 | 165 | /* channel mix */ 166 | float guide_value = 0; 167 | guide_value = _channel_mix_weight[0] * guide_r + 168 | _channel_mix_weight[1] * guide_g + 169 | _channel_mix_weight[2] * guide_b + _channel_mix_bias[0]; 170 | guide_out[h * width + w] = guide_value; 171 | } 172 | } 173 | 174 | return 0; 175 | } 176 | 177 | 178 | int HdrnetTask::apply_slicing_layer_and_assemble( 179 | float * img_in, // full_res, HWC format 180 | float * grid, // coeeff, 16x16x8x3x4 181 | float * guide_map, // guide map 182 | float * img_out, 183 | int height, 184 | int width 185 | ) 186 | { 187 | /* Begin to process. */ 188 | int grid_height = 16; 189 | int grid_width = 16; 190 | int grid_depth = 8; 191 | int chans = 12; 192 | 193 | int h_scale = grid_width * grid_depth * chans; 194 | int w_scale = grid_depth * chans; 195 | int d_scale = chans; 196 | 197 | float * chans_values = new float [chans]; 198 | 199 | for (int h = 0; h < height; h++) 200 | { 201 | for (int w = 0; w < width; w++) 202 | { 203 | for (int i = 0; i < chans; i++) 204 | { 205 | chans_values[i] = 0; 206 | } 207 | 208 | float gh = (h + 0.5f) * grid_height / (1.0f * height) - 0.5f; 209 | float gw = (w + 0.5f) * grid_width / (1.0f * width) - 0.5f; 210 | //gd = (guide_map[h * width + w] + 0.5f) * grid_depth / 1.0f - 0.5f; 211 | float gd = guide_map[h * width + w] * grid_depth - 0.5f;//according to the cuda code 212 | 213 | /* The neighboring position */ 214 | int fh = static_cast(floor(gh)); 215 | int fw = static_cast(floor(gw)); 216 | int fd = static_cast(floor(gd)); 217 | 218 | /* The neighboring 8 values, tri-linear interpolation */ 219 | for (int hh = fh; hh < fh + 2; hh++) 220 | { 221 | int h_idx = std::max(std::min(hh, grid_height - 1), 0); 222 | float h_ratio = std::max(1.0f - std::abs(gh - hh), 0.0f); 223 | 224 | for (int ww = fw; ww < fw + 2; ww++) 225 | { 226 | int w_idx = std::max(std::min(ww, grid_width - 1), 0); 227 | float w_ratio = std::max(1.0f - std::abs(gw - ww), 0.0f); 228 | 229 | for (int dd = fd; dd < fd + 2; dd++) 230 | { 231 | int d_idx = std::max(std::min(dd, grid_depth - 1), 0); 232 | float d_ratio = std::max(1.0f - std::abs(gd - dd), 0.0f); 233 | for (int c = 0; c < chans; c++) 234 | { 235 | int grid_idx = h_idx * h_scale + w_idx * w_scale + d_idx * d_scale + c; 236 | chans_values[c] += grid[grid_idx] * h_ratio * w_ratio * d_ratio; 237 | } 238 | } 239 | } 240 | } 241 | 242 | /* RGB format is HWC */ 243 | float r = img_in[h * width * 3 + w * 3 + 0]; 244 | float g = img_in[h * width * 3 + w * 3 + 1]; 245 | float b = img_in[h * width * 3 + w * 3 + 2]; 246 | 247 | img_out[h * width * 3 + w * 3 + 0] = chans_values[0] * r + chans_values[1] * g + chans_values[2] * b + chans_values[3]; 248 | img_out[h * width * 3 + w * 3 + 1] = chans_values[4] * r + chans_values[5] * g + chans_values[6] * b + chans_values[7]; 249 | img_out[h * width * 3 + w * 3 + 2] = chans_values[8] * r + chans_values[9] * g + chans_values[10] * b + chans_values[11]; 250 | 251 | //return 0; 252 | } 253 | } 254 | 255 | delete [] chans_values; 256 | 257 | return 0; 258 | } 259 | -------------------------------------------------------------------------------- /src/hdrnet/hdrnet_api.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Filename: hdrnet_api.cpp 4 | * Description: cpp file 5 | * 6 | * Version: 1.0 7 | * Created: 2018-10-10 8 | * Author: chencheng 9 | * 10 | * History: initial draft 11 | ******************************************************************************* 12 | */ 13 | #include "hdrnet/hdrnet_api.h" 14 | #include "utils/Utils.h" 15 | #include "hdrnet/HdrnetTask.h" 16 | #include "hdrnet/preprocess.h" 17 | #include 18 | 19 | 20 | 21 | int HDRNET_setup(void ** handle, const char * model_dir) 22 | { 23 | LOGD("# setup_hdrnet\n"); 24 | 25 | (*handle) = new HdrnetTask(model_dir); 26 | 27 | return 0; 28 | } 29 | 30 | int HDRNET_run(void ** handle, UINT8 * src_img, UINT8 * dst_img, int height, int width) 31 | { 32 | LOGD("# run_hdrnet!\n"); 33 | 34 | int ret = 0; 35 | 36 | /* memory allocate */ 37 | int size = height * width * 3; 38 | float * fullres_img_hwc = new float [size]; 39 | 40 | /* normalize */ 41 | normalize_data_to_float(src_img, fullres_img_hwc, size); 42 | 43 | HdrnetTask * hdrnet_task = static_cast(* handle); 44 | 45 | hdrnet_task->run_task(fullres_img_hwc, fullres_img_hwc, height, width); 46 | 47 | convert_float_to_char(fullres_img_hwc, dst_img, size); 48 | 49 | delete [] fullres_img_hwc; 50 | 51 | return ret; 52 | } 53 | 54 | 55 | int HDRNET_clean(void ** handle) 56 | { 57 | LOGD("# clean_hdrnet\n"); 58 | 59 | HdrnetTask * hdrnet_task = static_cast(* handle); 60 | 61 | delete hdrnet_task; 62 | 63 | return 0; 64 | } 65 | 66 | 67 | int HDRNET_read_uchar_data_from_file(UINT8 * data, int size, const char * file_name) 68 | { 69 | return read_data_from_file(data, size, file_name); 70 | } 71 | 72 | int HDRNET_read_float_data_from_file(float * data, int size, const char * file_name) 73 | { 74 | return read_data_from_file(data, size, file_name); 75 | } 76 | 77 | int HDRNET_write_uchar_data_to_file(UINT8 * data, int size, const char * file_name) 78 | { 79 | return write_data_to_file(data, size, file_name); 80 | } 81 | 82 | int HDRNET_write_float_data_to_file(float * data, int size, const char * file_name) 83 | { 84 | return write_data_to_file(data, size, file_name); 85 | } 86 | -------------------------------------------------------------------------------- /src/hdrnet/preprocess.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Filename: preprocess.cpp 4 | * Description: cpp file 5 | * 6 | * Version: 1.0 7 | * Created: 2018-10-10 8 | * Author: chencheng 9 | * 10 | * History: initial draft 11 | ******************************************************************************* 12 | */ 13 | 14 | #include "helper.h" 15 | #include "hdrnet/preprocess.h" 16 | #include 17 | #include 18 | 19 | #define CLIP(x, min, max) ((x < min) ? min : (x > max) ? max : x) 20 | 21 | int normalize_data_to_float(UINT8 * uint8_data, float * float_data, int size) 22 | { 23 | for (int i = 0; i < size; i++) 24 | { 25 | float_data[i] = float(uint8_data[i]) / float(255.0); 26 | } 27 | 28 | return 0; 29 | } 30 | 31 | int convert_float_to_char(float * float_data, UINT8 * uint8_data, int size) 32 | { 33 | for (int i = 0; i < size; i++) 34 | { 35 | uint8_data[i] = CLIP(round(float_data[i] * 255), 0, 255); 36 | } 37 | 38 | return 0; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/utils/Utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Filename: template.cpp 4 | * Description: cpp file 5 | * 6 | * Version: 1.0 7 | * Created: 2018-07-20 8 | * Author: chencheng 9 | * 10 | * History: initial draft 11 | ******************************************************************************* 12 | */ 13 | #include "utils/Utils.h" 14 | #include 15 | #include 16 | 17 | #define LOGE(x...) printf(x) 18 | 19 | #ifdef DEBUG 20 | #define LOGD(x...) printf(x) 21 | #else 22 | #define LOGD(x...) 23 | #endif 24 | 25 | template 26 | int read_data_from_file(Type * data, int size, const char * file_name) 27 | { 28 | printf("%s\n", file_name); 29 | printf("size: %d\n", size); 30 | FILE * fi = fopen(file_name, "rb"); 31 | if (fi == NULL) 32 | { 33 | LOGE("Error: file open error! %s\n", file_name); 34 | return -1; 35 | } 36 | 37 | int rsize = fread(data, sizeof(Type), size, fi); 38 | if (rsize != size) 39 | { 40 | LOGE("Error: fread failed! %s\n", __FUNCTION__); 41 | } 42 | 43 | fclose(fi); 44 | 45 | LOGD("# get_data_from_rgb_file!\n"); 46 | return 0; 47 | } 48 | 49 | template int read_data_from_file(UINT8 * data, int size, const char * file_name); 50 | template int read_data_from_file(float * data, int size, const char * file_name); 51 | 52 | 53 | 54 | int write_data_to_file(UINT8 * data, int size, const char * file_name) 55 | { 56 | FILE * fo = fopen(file_name, "w"); 57 | if (fo == NULL) 58 | { 59 | LOGE("Error: file open error! %s\n", file_name); 60 | return -1; 61 | } 62 | 63 | fwrite(data, sizeof(UINT8), size, fo); 64 | 65 | fclose(fo); 66 | 67 | LOGD("%s saved!\n", file_name); 68 | 69 | return 0; 70 | } 71 | 72 | 73 | int write_data_to_file(float * float_data, int size, const char * file_name) 74 | { 75 | UINT8 * uint8_data = new UINT8 [size]; 76 | 77 | for (int i = 0; i < size; i++) 78 | { 79 | int tmp = round(float_data[i] * float(255)); 80 | uint8_data[i] = (tmp < 0) ? 0 : ((tmp > 255) ? 255 : tmp); 81 | } 82 | 83 | write_data_to_file(uint8_data, size, file_name); 84 | 85 | delete [] uint8_data; 86 | 87 | return 0; 88 | } 89 | --------------------------------------------------------------------------------