%% Lane Detection Optimized with GPU Coder
%
% This example shows how to generate CUDA(R) code from a deep learning
% network, represented by a |SeriesNetwork| object. In this example, the 
% series network is a convolutional neural network that can detect and 
% output lane marker boundaries from an image.
%
%   Copyright 2017-2018 The MathWorks, Inc.
%% Prerequisites
% * CUDA enabled NVIDIA(R) GPU with compute capability 3.2 or higher.
% * NVIDIA CUDA toolkit and driver.
% * NVIDIA cuDNN library.
% * OpenCV libraries for video read and image display operations.
% * Environment variables for the compilers and libraries. For information
% on the supported versions of the compilers and libraries, see
% <docid:gpucoder_gs#mw_aa8b0a39-45ea-4295-b244-52d6e6907bff
% Third-party Products>. For setting up the environment variables, see
% <docid:gpucoder_gs#mw_453fbbd7-fd08-44a8-9113-a132ed383275
% 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);

%% Get Pretrained SeriesNetwork
[laneNet, coeffMeans, coeffStds] = getLaneDetectionNetwork();

%%
% This network takes an image as an input and outputs two lane boundaries that
% correspond to the left and right lanes of the ego vehicle.
% Each lane boundary is represented by the parabolic equation:
% $y = ax^2+bx+c$,
% where y is the lateral offset and x is the longitudinal distance from the vehicle.
% The network outputs the three parameters a, b, and c per lane.
% The network architecture is similar to AlexNet except that the last few
% layers are replaced by a smaller fully connected layer and regression 
% output layer.
laneNet.Layers

%% Examine Main Entry-Point Function
type detect_lane.m

%% Generate Code for Network and Post-Processing Code
%
% The network computes parameters a, b, and c that describe the parabolic equation
% for the left and right lane boundaries.
%
% From these parameters, compute the x and y coordinates corresponding
% to the lane positions. The coordinates must be mapped to
% image coordinates. The function |detect_lane.m| performs all these computations.
% Generate CUDA code for this function by creating a GPU code configuration 
% object for a |'lib'| 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.
%
cfg = coder.gpuConfig('lib');
cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
cfg.GenerateReport = true;
cfg.TargetLang = 'C++';
codegen -args {ones(227,227,3,'single'),ones(1,6,'double'),ones(1,6,'double')} -config cfg detect_lane

%% Generated Code Description
% The series network is generated as a C++ class containing an array of 23 layer
% classes.
%
%   class c_lanenet
%   {
%    public:
%     int32_T batchSize;
%     int32_T numLayers;
%     real32_T *inputData;
%     real32_T *outputData;
%     MWCNNLayer *layers[23];
%    public:
%     c_lanenet(void);
%     void setup(void);
%     void predict(void);
%     void cleanup(void);
%     real32_T *getInputDataPointer();
%     real32_T *getOutputDataPointer();
%     ~c_lanenet(void);
%   };
%
% The |setup()| method of the class sets up handles and allocates memory for
% each layer object. The |predict()| method invokes prediction for each of 
% the 23 layers in the network.
%
% The cnn_lanenet_conv*_w and cnn_lanenet_conv*_b files are the
% binary weights and bias file for convolution layer in the network.
% The cnn_lanenet_fc*_w and cnn_lanenet_fc*_b files are the
% binary weights and bias file for fully connected layer in the network.
%
codegendir = fullfile('codegen', 'lib', 'detect_lane');
dir(codegendir)

%% Generate Additional Files for Post-Processing the Output
% Export mean and std values from the trained network for use during
% execution.
codegendir = fullfile(pwd, 'codegen', 'lib','detect_lane');
fid = fopen(fullfile(codegendir,'mean.bin'), 'w');
A = [coeffMeans coeffStds];
fwrite(fid, A, 'double');
fclose(fid);

%% Main File
% Compile the network code by using a main file. The main file uses the 
% OpenCV |VideoCapture| method to read frames from the input video. Each 
% frame is processed and classified until no more frames are read.
% Before displaying the output for each frame, the outputs are
% post-processed by using the |detect_lane| function generated in
% |detect_lane.cpp|.

type main_lanenet.cpp

%% Download Example Video
%
if ~exist('./caltech_cordova1.avi', 'file')
    url = 'https://www.mathworks.com/supportfiles/gpucoder/media/caltech_cordova1.avi';
    websave('caltech_cordova1.avi', url);
end

%% Build Executable
%
if ispc
    setenv('MATLAB_ROOT', matlabroot);
    vcvarsall = mex.getCompilerConfigurations('C++').Details.CommandLineShell;
    setenv('VCVARSALL', vcvarsall);
    [~,~] = system('make_win_lane_detection.bat');
    cd(codegendir);
    [status,cmdout] = system('lanenet.exe ..\..\..\caltech_cordova1.avi');
else
    setenv('MATLAB_ROOT', matlabroot);
    [~,~] = system('make -f Makefile_lane_detection.mk');
    cd(codegendir);
    [status,cmdout] = system('./lanenet ../../../caltech_cordova1.avi');
end

%% Input Screenshot
%%
%
% <<../lane_detect_input.png>>
%

%% Output Screenshot
%%
%
% <<../lane_detect_output.png>>
%
