%% Code Generation for Denoising Deep Neural Network
% This example shows how to generate CUDA(R) MEX from MATLAB(R) code and
% denoise grayscale images by using the denoising convolutional neural
% network (DnCNN [1]). You can use the denoising network to estimate noise in 
% a noisy image, and then remove it to obtain a denoised image.
%
% Copyright 2018-2019 The MathWorks, Inc.

%% Prerequisites
% * CUDA enabled NVIDIA(R) GPU with compute capability 3.2 or higher.
% * NVIDIA CUDA toolkit and driver.
% * NVIDIA cuDNN library.
% * Environment variables for the compilers and libraries. For information 
% on the supported versions of the compilers and libraries, see 
% <matlab:web(fullfile(docroot,'gpucoder/gs/install-prerequisites.html'))
% Third-party Products>. For setting up the environment variables, see 
% <matlab:web(fullfile(docroot,'gpucoder/gs/setting-up-the-toolchain.html'))
% Environment Variables>.
% * GPU Coder Interface for Deep Learning Libraries support package. To install
% this support package, use the <matlab:matlab.addons.supportpackage.internal.explorer.showSupportPackages('GPU_DEEPLEARNING_LIB','tripwire') Add-On Explorer>.

%% Verify GPU Environment
% Use the <docid:gpucoder_ref#mw_0957d820-192f-400a-8045-0bb746a75278 coder.checkGpuInstall> function
% to verify that the compilers and libraries necessary for running this example
% are set up correctly.
envCfg = coder.gpuEnvConfig('host');
envCfg.DeepLibTarget = 'cudnn';
envCfg.DeepCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);

%% Load Noisy Image
% Load a noisy grayscale image into the workspace and display the image. 

noisyI = imread('noisy_cameraman.png');
figure
imshow(noisyI);
title('Noisy Image');

%% Get Pretrained Denoising Network
%
% Call the <matlab:edit(fullfile(matlabroot,'examples','deeplearning_shared','main','getDenoisingNetwork.m')) getDenoisingNetwork>
% helper function to get a pretrained image denoising deep neural network.
net = getDenoisingNetwork;
%%
% The |getDenoisingNetwork| function returns a pretrained DnCNN [1] that
% you can use to detect additive white Gaussian noise (AWGN) that has 
% unknown levels. The network is a feed-forward denoising convolutional 
% network that implements a residual learning technique to predict a 
% residual image. In other words, DnCNN [1] computes the difference 
% between a noisy image and the latent clean image.
%%
%
% The network contains 59 layers including convolution, batch
% normalization, and regression output layers. To display an interactive visualization of the 
% deep learning network architecture, use the 
% <docid:nnet_ref#mw_8d52b67d-b6b3-4c62-b573-56fdf4dce6a0 analyzeNetwork> 
% function.
%
%   analyzeNetwork(net);

%% The |denoisenet_predict| Function
% The <matlab:edit(fullfile(matlabroot,'examples','deeplearning_shared','main','denoisenet_predict.m')) denoisenet_predict>
% entry-point function takes a noisy image input and returns a denoised 
% image by using a pretrained denoising network.
%
% The function loads the network object returned by 
% <matlab:edit(fullfile(matlabroot,'examples','deeplearning_shared','main','getDenoisingNetwork.m')) getDenoisingNetwork> 
% into a persistent variable _mynet_ and reuses the persistent object on 
% subsequent prediction calls.  

type denoisenet_predict

%%
% Here, the |activations| method is called with the layer numeric index as
% 59 to extract the activations from the final layer of the network.
% The |'OutputAs'|  |'channels'| name-value pair argument computes
% activations on images larger than the |imageInputLayer.InputSize| of the 
% network.
%
% The |activations| method returns an estimate of the noise in the input
% image by using the pretrained denoising image. 
%
% Once the noise is estimated, subtract the noise from the original
% image to obtain a denoised image.

%% Run MEX Code Generation
% To generate CUDA code for the 
% <matlab:edit(fullfile(matlabroot,'examples','deeplearning_shared','main','denoisenet_predict.m'))
% denoisenet_predict.m> entry-point function, create a GPU code 
% configuration object for a MEX target and set the target language to C++. 
% Use the 
% <docid:gpucoder_ref#mw_e8e85f8e-8dde-45b6-9ec5-f121a79dc48f coder.DeepLearningConfig>
% function to create a |CuDNN| deep learning configuration object and
% assign it to the |DeepLearningConfig| property of the GPU code
% configuration object. Run the |codegen| command specifying an input size
% of [256,256]. This value corresponds to the size of the noisy image that you 
% intend to denoise.
cfg = coder.gpuConfig('mex');
cfg.TargetLang = 'C++';
cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
codegen -config cfg denoisenet_predict -args {ones(256,256,'single')} -report

%% Run Generated MEX 
% 
% The DnCNN [1] is trained on input images having an input range [0,1].
% Call the <matlab:doc('im2single') im2single> function on |noisyI| to rescale the 
% values from [0,255] to [0,1].
%
% Call |denoisenet_predict_predict| on the rescaled input image.
denoisedI = denoisenet_predict_mex(im2single(noisyI));
%% View Denoised Image

figure
imshowpair(noisyI,denoisedI,'montage');
title('Noisy Image (left) and Denoised Image (right)');

%% References
% [1] Zhang, K., W. Zuo, Y. Chen, D. Meng, and L. Zhang. "Beyond a
% Gaussian Denoiser: Residual Learning of Deep CNN for Image Denoising." 
% IEEE Transactions on Image Processing. Vol. 26, Number 7, Feb. 2017, pp. 3142-3155.