%% Deployment and Classification of Webcam Images on NVIDIA Jetson TX2 Platform
% This example shows how to generate CUDA(R) code from a DAGNetwork object
% and deploy the generated code onto the NVIDIA(R) Jetson TX2 board using 
% the GPU Coder(TM) Support Package for NVIDIA GPUs. This example uses the 
% resnet50 deep learning network to classify images from a USB webcam video stream.

% Copyright 2019 The MathWorks, Inc. 

%% Prerequisites
%
% *Target Board Requirements*
%
% * NVIDIA Jetson Tegra TX2 embedded platform. 
% * Ethernet crossover cable to connect the target board and host PC (if 
% the target board cannot be connected to a local network).
% * USB camera to connect to the TX2.
% * NVIDIA CUDA toolkit installed on the board.
% * NVIDIA cuDNN library (v5 or higher) on the target.
% * OpenCV 3.0 (or higher) library on the target for reading and displaying
% images/video.
% * Environment variables on the target for the compilers and libraries. 
% For information on the supported versions of the compilers and libraries 
% and their setup, see
% <docid:nvidia_ug#mw_3e566086-bbce-4f1a-8f26-367c8b5f5953 Install and Setup Prerequisites>
%  for NVIDIA boards.
%
% *Development Host Requirements*
%
% * NVIDIA CUDA toolkit and driver.
% * Deep Learning Toolbox(TM) to use a DAGNetwork object.
% * 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>.
% * GPU Coder Support Package for NVIDIA GPUs. To install
% this support package, use the <matlab:matlab.addons.supportpackage.internal.explorer.showSupportPackages('NVIDIA','tripwire') Add-On Explorer>.
% * 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>.

%% Verify NVIDIA Support Package Installation on Host
% Use the |checkHardwareSupportPackageInstall| function to verify that the 
% host system is compatible to run this example.
% 
%   checkHardwareSupportPackageInstall();

%% Connect to the NVIDIA Hardware
% The GPU Coder Support Package for NVIDIA GPUs uses an SSH connection over 
% TCP/IP to execute commands while building and running the generated CUDA 
% code on the Jetson platform. You must therefore connect the
% target platform to the same network as the host computer or use an 
% Ethernet crossover cable to connect the board directly to the host
% computer. Refer to the NVIDIA documentation on how to set up and
% configure your board.
%
% To communicate with the NVIDIA hardware, you must create a live hardware
% connection object by using the 
% <docid:nvidia_ref#mw_5a6bd41b-6ed9-47ee-876d-1975bcdcd195 jetson> 
% function. You must know the host name or IP address, username, and 
% password of the target board to create a live hardware connection object.
%
%   hwobj= jetson('host-name','username','password');

%%
% *NOTE:* 
%
% In case of a connection failure, a diagnostics error message is 
% reported on the MATLAB command line. If the connection has failed, the 
% most likely cause is incorrect IP address or hostname.
%
%%
% When there are multiple live connection objects for different targets,
% the code generator performs remote build on the target for which a 
% recent live object was created. To choose a hardware board for performing
% remote build, use the |setupCodegenContext()| method of the respective 
% live hardware object. If only one live connection object was created, it is 
% not necessary to call this method.
%
%   hwobj.setupCodegenContext;
%% Verify GPU Environment on the Target
% 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('jetson');
%   envCfg.DeepLibTarget = 'cudnn';
%   envCfg.DeepCodegen = 1;
%   envCfg.Quiet = 1;
%   envCfg.HardwareObject = hwobj;
%   coder.checkGpuInstall(envCfg);

%% ResNet-50 Entry-Point Function
% The |resnet50_wrapper.m| entry-point function uses a pre-trained 
% ResNet-50 Network to classify images. ResNet-50 is a DAG Network trained 
% on more than a million images from the ImageNet database. The output 
% contains the categorical scores of each class the image belongs to.

type resnet50_wrapper
%% Generate & Deploy CUDA Code on the Target
% To generate a CUDA executable that can be deployed on to an NVIDIA target, 
% create a GPU coder configuration object for generating an executable.
%
%   cfg = coder.gpuConfig('exe');

%% 
% Use the <docid:coder_ref#mw_c0d3d077-d33a-4dca-b85d-76027b3170b7 coder.hardware> 
% function to create a configuration object for the Jetson platform and 
% assign it to the |Hardware| property of the GPU code configuration 
% object |cfg|.
%
%   cfg.Hardware = coder.hardware('NVIDIA Jetson');

%%
% Set Deep Learning Configuration to 'cudnn' or tensorrt'
%
%   cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');

%% 
% In this example, code generation is done using image as an input.
% However, webcam stream is fed a input to the executable after deployment.
%%
% Sample image input for code generation
im=single(imread('peppers.png'));
im=imresize(im,[224,224]);
%%
% The custom main file is coded to take video as input and classifies each frame
% in the video sequence. The custom |main_resnet50.cu|  
% file is a wrapper that calls the predict function in the generated code. 
% Post processing steps such as displaying output on the input frame are 
% added in the main file using OpenCV interfaces. 
% 
%   cfg.CustomSource=fullfile('main_resnet50.h');
%   cfg.CustomSource=fullfile('main_resnet50.cu');
%% 
% To generate CUDA code and deploy it onto target, use the <docid:coder_ref#br46oyi-1 codegen> function 
% and pass the GPU code configuration object. After the code generation takes 
% place on the host, the generated files are copied over and built on the 
% target in the workspace directory. 
% 
%   codegen -config cfg -args {im} resnet50_wrapper -report

%% Run the Application on the Target 
% Copy the synsetWords_resnet50 text file from host computer to the target device
% by using the |putFile| command.
%%
%   hwobj.putFile('synsetWords_resnet50.txt',hwobj.workspaceDir);
%%
% Use the |runApplication| method of the hardware object to launch the
% application on the target hardware. The application will be located in
% the workspace directory.
%
%   hwobj.runApplication('resnet50_wrapper');

%% Resnet Classification output on Jetson TX2
% <<../gpucoderdemo_resnet50_Jetson_TX2_output.png>>

%% Kill the Application
% Use the |killApplication| method of the hardware object to kill the
% running application on the target.
%
%   hwobj.killApplication('resnet50_wrapper');
