%% Code Generation for Deep Learning on Raspberry Pi
% This example shows how to generate and deploy code for prediction on a 
% Raspberry Pi(TM) by using |codegen| with the MATLAB Support Package for
% Raspberry Pi Hardware.
%
% When you generate code for prediction using the ARM(R) Compute Library and 
% a hardware support package, |codegen| generates code on the host computer,
% copies the generated files to the target hardware, and builds
% the executable on the target hardware.

% Copyright 2018 The MathWorks, Inc.

%% Prerequisites
% * ARM processor that supports the NEON extension
% * ARM Compute Library (on the target ARM hardware)
% * Open Source Computer Vision Library
% * Environment variables for the compilers and libraries 
% * MATLAB(R) Coder(TM)
% * The support package MATLAB Coder Interface for Deep Learning
% * Deep Learning Toolbox(TM)
% * MATLAB Support Package for Raspberry Pi Hardware
%
% For supported versions of libraries and for information about setting up
% environment variables, see <docid:coder_ug#mw_99a4acec-aced-453c-aadd-a18e83133574>.
% This example is not supported for MATLAB Online.
%
%% The |squeezenet_raspi_predict| Function
% This example uses the DAG network SqueezeNet to show image classification
% with the ARM Compute Library. A pretrained SqueezeNet for MATLAB is available 
% in the Deep Learning Toolbox. The |squeezenet_arm_predict| function loads the
% SqueezeNet network into a persistent network object. On subsequent calls to the
% function, the persistent object is reused.
%
% So that the generated executable program links against the OpenCV
% libraries, the |squeezenet_arm_predict| function specifies linker options by using
% |coder.updateBuildInfo|.
type squeezenet_raspi_predict
%% Set Up a Code Generation Configuration Object 
% Create a code generation configuration object for generation of an executable program. 
% Specify generation of C++ code.
cfg = coder.config('exe');
cfg.TargetLang = 'C++';
%% Set Up a Configuration Object for Deep Learning Code Generation with ARM Compute Library
% Create a |coder.ARMNEONConfig| object. Specify the version of the ARM Compute library 
% that is on the Raspberry Pi. Specify the architecture of the Raspberry Pi.
dlcfg = coder.DeepLearningConfig('arm-compute');
dlcfg.ArmArchitecture = 'armv7';
dlcfg.ArmComputeVersion = '19.05';
%% Attach the Deep Learning Configuration Object to the Code Generation Configuration Object
cfg.DeepLearningConfig = dlcfg;
%% Create a Connection to the Raspberry Pi
% Use the MATLAB Support Package for Raspberry Pi Support Package function,
% |raspi|, to create a connection to the Raspberry Pi. In the following
% code, replace:
%
% * |raspiname| with the name of your Raspberry Pi
% * |username| with your user name
% * |password| with your password
%
%   r = raspi('raspiname','username','password');
%% Configure Code Generation Hardware Parameters for Raspberry Pi
% Create a |coder.Hardware| object for Raspberry Pi and attach it to the
% code generation configuration object.
%
%   hw = coder.hardware('Raspberry Pi');
%   cfg.Hardware = hw;
%%
% Specify the build folder on the Raspberry Pi
%
%   buildDir = '~/remoteBuildDir';
%   cfg.Hardware.BuildDir = buildDir;
%% Provide a C++ Main File 
% The C++ main file reads the input image, runs prediction on the image,
% and displays the classification labels on the image.
%%
% Specify the main file in the code generation configuration object.
cfg.CustomSource = 'main_squeezenet_raspi.cpp';
%% Generate the Executable Program on the Raspberry Pi
% Use |codegen| to generate the C++ code. When you use |codegen| with the 
% MATLAB Support Package for Raspberry PI Hardware, the executable is built
% on the Raspberry Pi.
%
% Make sure that you set the environment variables ARM_COMPUTELIB and LD_LIBRARY_PATH
% on the Raspberry Pi. See
% <docid:coder_ug#mw_99a4acec-aced-453c-aadd-a18e83133574>.
%
%   codegen -config cfg squeezenet_raspi_predict -args {ones(227, 227, 3,'single')} -report
%% Fetch the Generated Executable Directory 
% To test the generated code on the Raspberry Pi, copy the input image to
% the generated code directory. You can find this directory manually or by using 
% the |raspi.utils.getRemoteBuildDirectory| API. This function lists the directories 
% of the binary files that are generated by using |codegen|. Assuming that
% the binary is found in only one directory, enter:
%
%   applicationDirPaths = raspi.utils.getRemoteBuildDirectory('applicationName','squeezenet_raspi_predict');
%   targetDirPath = applicationDirPaths{1}.directory;
%% Copy Example Files to the Raspberry Pi
% To copy files required to run the executable program, use |putFile|, which is available with
% the MATLAB Support Package for Raspberry Pi Hardware.
%
%   r.putFile('synsetWords_squeezenet_raspi.txt', targetDirPath);
%   r.putFile('coffeemug.png',targetDirPath);
%% Run the Executable Program on the Raspberry Pi
% Run the executable program on the Raspberry Pi from MATLAB and direct the output
% back to MATLAB.
%
%   exeName = 'squeezenet_raspi_predict.elf';
%   argsforexe = ' coffeemug.png '; % Provide the input image;
%   command = ['cd ' targetDirPath ';./' exeName argsforexe];
%   output = system(r,command)
%% Get the Prediction Scores
%
%   outputfile = [targetDirPath, '/output.txt'];
%   r.getFile(outputfile);
%% Map the Prediction Scores to Labels
% Map the top five prediction scores to corresponding labels in the trained
% network.
%
%   net = squeezenet;
%   ClassNames = net.Layers(end).ClassNames;
%%
% Read the classification.
%
%   fid = fopen('output.txt') ;
%   S = textscan(fid,'%s');
%   fclose(fid) ;
%   S = S{1} ;
%   predict_scores = cellfun(@(x)str2double(x), S);
%%
% Remove NaN values that were strings.
%
%   predict_scores(isnan(predict_scores))=[];
%   [val,indx] = sort(predict_scores, 'descend');
%   scores = val(1:5)*100;
%   top5labels = ClassNames(indx(1:5));

%%
% Display classification labels on the image.
%
%   im = imread('coffeemug.png');
%   im = imresize(im, [227 227]);
%   outputImage = zeros(227,400,3, 'uint8');
%   for k = 1:3
%       outputImage(:,174:end,k) = im(:,:,k);
%   end
%   scol = 1;
%   srow = 1;
%   outputImage = insertText(outputImage, [scol, srow], 'Classification with Squeezenet', 'TextColor', 'w','FontSize',20, 'BoxColor', 'black');
%   srow = srow + 30;
%   for k = 1:5
%       outputImage = insertText(outputImage, [scol, srow], [top5labels{k},' ',num2str(scores(k), '%2.2f'),'%'], 'TextColor', 'w','FontSize',15, 'BoxColor', 'black');
%       srow = srow + 25;
%   end
%   imshow(outputImage);
%
%%
%
% <<../squeezenet_raspi_coffeemug_output.png>>
