%% Logo Recognition Network
%  
% This example shows code generation for a logo classification application 
% that uses deep learning. It uses the |codegen| command to generate a MEX 
% function that performs prediction on a |SeriesNetwork| object
% called LogoNet.
%
%    Copyright 2017-2019 The MathWorks, Inc.

%% Third-Party Prerequisites
% *Required*
%
% This example generates CUDA MEX and has the following third-party 
% requirements.
%
% * CUDA(R) enabled NVIDIA(R) GPU and compatible driver.
%
% *Optional*
%
% For non-MEX builds such as static, dynamic libraries or executables,
% this example has the following additional requirements.
%
% * NVIDIA toolkit.
% * NVIDIA cuDNN library.
% * Environment variables for the compilers and libraries. For more
% information, see
% <docid:gpucoder_gs#mw_aa8b0a39-45ea-4295-b244-52d6e6907bff Third-party
% Products> and <docid:gpucoder_gs#mw_453fbbd7-fd08-44a8-9113-a132ed383275
% Environment Variables>.

%% 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);

%% The Logo Recognition Network
% Logos assist users in brand identification and recognition. Many 
% companies incorporate their logos in advertising, documentation 
% materials, and promotions. The logo recognition network (logonet) was 
% developed in MATLAB(R) and can recognize 32 logos under various 
% lighting conditions and camera motions. Because this network focuses 
% only on recognition, you can use it in applications where localization is 
% not required. 
%
%% Training the Network
% The network is trained in MATLAB by using training data that contains 
% around 200 images for each logo. Because the number of images for 
% training the network is small, data augmentation increases the number of 
% training samples. Four types of data augmentation are used: 
% contrast normalization, Gaussian blur, random flipping, and shearing. This
% data augmentation helps in recognizing logos in images captured by
% different lighting conditions and camera motions. The input size for 
% logonet is [227 227 3]. Standard SGDM trains by using a learning rate of 
% 0.0001 for 40 epochs with a mini-batch size of 45.
% The <matlab:edit(fullfile(matlabroot,'examples','deeplearning_shared','main','trainLogonet.m')) trainLogonet.m>
% helper script demonstrates the data augmentation on a sample image,
% architecture of the logonet, and training options.
%
%% Get Pretrained SeriesNetwork
%
% Download the logonet network and save it to |LogoNet.mat|.
getLogonet();
%%
%
% The saved network contains 22 layers including convolution, fully connected, and the
% classification output layers.
load('LogoNet.mat');
convnet.Layers
%% The |logonet_predict| Entry-Point Function
% 
% The <matlab:edit(fullfile(matlabroot,'examples','deeplearning_shared','main','logonet_predict.m')) logonet_predict.m>
% entry-point function takes an image input and performs prediction on the 
% image using the deep learning network saved in the |LogoNet.mat| file.
% The function loads the network object from |LogoNet.mat| into a persistent
% variable _logonet_ and reuses the persistent variable on subsequent 
% prediction calls.  
%
type('logonet_predict.m')
%% Generate CUDA MEX for the |logonet_predict| Function 
%
% Create a GPU 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. To generate CUDA MEX, use the |codegen| command 
% and specify the input to be of size [227,227,3]. This value corresponds 
% to the input layer size of the logonet network.
cfg = coder.gpuConfig('mex');
cfg.TargetLang = 'C++';
cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
codegen -config cfg logonet_predict -args {ones(227,227,3,'uint8')} -report

%% Run Generated MEX 
% Load an input image. Call |logonet_predict_mex| on the input image.
im = imread('test.png');
imshow(im);
im = imresize(im, [227,227]);
predict_scores = logonet_predict_mex(im);
%% 
% Map the top five prediction scores to words in the Wordnet dictionary 
% synset (logos).
synsetOut = {'adidas', 'aldi', 'apple', 'becks', 'bmw', 'carlsberg', ...
    'chimay', 'cocacola', 'corona', 'dhl', 'erdinger', 'esso', 'fedex',...
    'ferrari', 'ford', 'fosters', 'google', 'guinness', 'heineken', 'hp',...
    'milka', 'nvidia', 'paulaner', 'pepsi', 'rittersport', 'shell', 'singha', 'starbucks', 'stellaartois', 'texaco', 'tsingtao', 'ups'};

[val,indx] = sort(predict_scores, 'descend');
scores = val(1:5)*100;
top5labels = synsetOut(indx(1:5)); 
%%
% Display the top five classification labels.
outputImage = zeros(227,400,3, 'uint8');
for k = 1:3
    outputImage(:,174:end,k) = im(:,:,k);
end

scol = 1;
srow = 20;

for k = 1:5
    outputImage = insertText(outputImage, [scol, srow], [top5labels{k},' ',num2str(scores(k), '%2.2f'),'%'], 'TextColor', 'w','FontSize',15, 'BoxColor', 'black');
    srow = srow + 20;
end

 imshow(outputImage);
%% 
%
% Clear the static network object that was loaded in memory.
clear mex;

