%% Code Generation for Object Detection by Using Single Shot Multibox Detector
%
% This example shows how to generate CUDA(R) code for an SSD network 
% (ssdObjectDetector object) and take advantage of the NVIDIA(R) cuDNN and 
% TensorRT libraries. An SSD network is based on a feed-forward 
% convolutional neural network that detect multiple objects within the 
% image in a single shot.  SSD network can be thought of as having two 
% sub-networks. A feature extraction network, followed by a detection 
% network.
%
% This example generates code for the network trained in the 
% _Object Detection Using SSD Deep Learning_ example from Computer Vision
% Toolbox(TM). For more information, see
% <docid:vision_ug#mw_b4e9bae8-8d1a-4983-bc5b-a60bceebe0c9 Object Detection Using SSD Deep Learning>.
% The _Object Detection Using SSD Deep Learning_ example uses ResNet-50 
% for feature extraction. The detection sub-network is a small CNN 
% compared to the feature extraction network and is composed of a few 
% convolutional layers and layers specific to SSD.
%
%   Copyright 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);

%% Get Pretrained DAGNetwork

net = getSSDNW();

%%
% The DAG network contains 180 layers including convolution, ReLU, and 
% batch normalization layers, anchor box, SSD merge, focal loss, and 
% other 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 |ssdObj_detect| Entry-Point Function
% 
% The <matlab:edit(fullfile(matlabroot,'examples','deeplearning_shared','main','ssdObj_detect.m')) ssdObj_detect.m>
% entry-point function takes an image input and runs the detector on the 
% image using the deep learning network saved in the 
% |ssdResNet50VehicleExample_20a.mat| file. The function loads the network 
% object from the |ssdResNet50VehicleExample_20a.mat| file into a persistent 
% variable _ssdObj_ and reuses the persistent object on subsequent detection 
% calls.  
%
type('ssdObj_detect.m')

%% Run MEX Code Generation 
%
% To generate CUDA code for the 
% <matlab:edit(fullfile(matlabroot,'examples','deeplearning_shared','main','ssdObj_detect.m'))
% ssdObj_detect.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 [300,300,3]. This value corresponds to the input layer size of SSD Network.
%
cfg = coder.gpuConfig('mex');
cfg.TargetLang = 'C++';
cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
codegen -config cfg ssdObj_detect -args {ones(300,300,3,'uint8')} -report


%% Run Generated MEX
% Set up the video file reader and read the input video. Create a video
% player to display the video and the output detections.
%
videoFile = 'highway_lanechange.mp4';
videoFreader = vision.VideoFileReader(videoFile,'VideoOutputDataType','uint8');
depVideoPlayer = vision.DeployableVideoPlayer('Size','Custom','CustomSize',[640 480]);
%%
% Read the video input frame-by-frame and detect the vehicles in the video 
% using the detector.
%
cont = ~isDone(videoFreader);
while cont
    I = step(videoFreader);
    in = imresize(I,[300,300]);
    out = ssdObj_detect_mex(in);
    step(depVideoPlayer, out);
    cont = ~isDone(videoFreader) && isOpen(depVideoPlayer); % Exit the loop if the video player figure window is closed
end

%%
%
% <<../gpucoder_ssd_output.png>>
%
%% References
% [1] Liu, Wei, Dragomir Anguelov, Dumitru Erhan, Christian Szegedy, 
% Scott Reed, Cheng Yang Fu, and Alexander C. Berg. "SSD: Single shot 
% multibox detector." In 14th European Conference on Computer Vision, 
% ECCV 2016. Springer Verlag, 2016.

