%% Top-Hat Filtering to Remove Uneven Background Illumination on NVIDIA Jetson TX2 Developer Kit
% This example shows how to deploy Image Processing Toolbox(TM) algorithms 
% to NVIDIA(R) Jetson TX2 board using the GPU Coder(TM) Support Package for 
% NVIDIA GPUs. The <docid:images_ref#f5-346033 imtophat>  function that performs  
% morphological top-hat filtering on a grayscale image is used as an example  
% to demonstrate this concept. Top-hat filtering computes the morphological  
% opening of the image (using <docid:images_ref#f5-345703 imopen>) and then subtracts  
% the result from the original image. The generated  
% CUDA(R) code uses shared memory to speed up the operations on the GPU. 

% 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).
% * NVIDIA CUDA toolkit installed on the board.
% * OpenCV 3.0 (or higher) library on the target for reading and displaying
% images and 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*
%
% * CUDA enabled NVIDIA GPU with compute capability 3.2 or higher.
% * NVIDIA CUDA toolkit and driver.
% * 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>.
% * Image Processing Toolbox for reading and displaying images.
% * 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>.

%% 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');
%%
% 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
% To verify that the compilers and libraries necessary for running this example
% are set up correctly, use the <docid:gpucoder_ref#mw_0957d820-192f-400a-8045-0bb746a75278 coder.checkGpuInstall>
% function.
% 
%   envCfg = coder.gpuEnvConfig('jetson');
%   envCfg.BasicCodegen = 1;
%   envCfg.Quiet = 1;
%   envCfg.HardwareObject = hwobj;
%   coder.checkGpuInstall(envCfg);

%% The |imtophat| Entry-Point Function
% The |imtophatDemo_gpu.m| calls |imtophat| internally. The |imtophat| 
% function performs morphological opening on the image using the 
% <docid:images_ref#f5-345703 imopen> function. The result of the image is 
% subtracted from the original image. The |imopen| operation is basically 
% <docid:images_ref#f4-343298 imerode> operation followed by
% <docid:images_ref#f4-341525 imdilate>.
%
% This example is shown on an input grayscale image.
original = imread('rice.png');
imshow(original),title('Input to Top-Hat Filtering');
%%
% Create a disc-shaped structuring element with a radius of 12. 
% Neighbourhood, |Nhood| of this structuring element is passed as an input
% argument for the imtophat function.
se = strel('disk',12);
Nhood = se.Neighborhood;
type imtophatDemo_gpu

%% Generate and Deploy CUDA Code on the Target
% This example uses |imtophatDemo_gpu.m| as the entry-point function for 
% code generation. To generate a CUDA executable, create a GPU code 
% configuration object.
%
%   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');

%%
% The custom |main.cpp| file is a wrapper that calls the |imtophatDemo_gpu| 
% entry-point function in the generated code. Post processing steps are 
% added in the main file using OpenCV interfaces. Build Flags for OpenCV 
% libraries are included in |imtophatDemo_gpu.m| entry-point function.
%%
%   cfg.CustomSource = fullfile('main.cpp');
%% 
% To generate CUDA code, use the <docid:coder_ref#br46oyi-1 codegen> function 
% and pass the GPU code configuration object along with input arguments.
% In this step, CUDA code is generated on the host, generated files are 
% copied over and built on the target in the workspace directory. The
% workspace directory is available as a property, |workspaceDir|  in the
% hardware object, |hwobj|. 
% 
%   codegen -args {original,coder.Constant(Nhood)} -config cfg imtophatDemo_gpu -report

%% Run the Application on the Target
% This application takes a grayscale image as input. Copy the rice.png file 
% from host to the target device by using the |putFile| command. 
%
%   hwobj.putFile('rice.png',hwobj.workspaceDir);

%%
% Use the |runApplication| method of the hardware object to launch the
% application on the target hardware.
%
%   hwobj.runApplication('imtophatDemo_gpu','rice.png');

%% Top-Hat Filtered Image on Jetson TX2
% <<../gpucoderdemo_topHatFilteringOnJetsonTX2_output.png>>

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