%% Lane Detection Optimized with GPU Coder
% This example shows how to generate CUDA® 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.
%% Prerequisites
% CUDA enabled NVIDIA® GPU.
% 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 Third-party Products. For setting up the environment variables, see Environment Variables.
%% Verify GPU Environment
% Use the 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] = getLaneDetectionNetworkGPU();

%
% 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. To view the network architecture, use the analyzeNetwork function.

analyzeNetwork(laneNet)

%
%% 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 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++';
inputs = {ones(227,227,3,'single'),ones(1,6,'double'),ones(1,6,'double')};
codegen -args inputs -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); ~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.cu.

type main_lanenet.cu

%
%% 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);
%     system('lanenet.exe ..\..\..\caltech_cordova1.avi');
% else
%     setenv('MATLAB_ROOT', matlabroot);
%     system('make -f Makefile_lane_detection.mk');
%     cd(codegendir);
%     system('./lanenet ../../../caltech_cordova1.avi');
% end
%% Input Screenshot
%
%% Output Screenshot
%
% Copyright 2017-2021 The MathWorks, Inc.