%% Code Generation For Object Detection Using YOLO v3 Deep Learning
% This example shows how to generate CUDA® MEX for a you only look once (YOLO) v3 object detector with custom layers. YOLO v3 improves upon YOLO v2 by adding detection at multiple scales to help detect smaller objects. Moreover, the loss function used for training is separated into mean squared error for bounding box regression and binary cross-entropy for object classification to help improve detection accuracy. The YOLO v3 network used in this example was trained from the Object Detection Using YOLO v3 Deep Learning example in the Computer Vision Toolbox (TM). For more information, see Object Detection Using YOLO v3 Deep Learning.
%
% Table of Contents
% Third-Party Prerequisites
%     Required
%     Optional
% Verify GPU Environment
% YOLO v3 Network
% Pretrained YOLO v3 Network
% The yolov3Detect Entry-Point Function
% Evaluate the Entry-Point Function for Object Detection
% Generate CUDA MEX
% Run the Generated MEX
% Utility Functions
% References
%
%% Third-Party Prerequisites
%% Required
% CUDA enabled NVIDIA® GPU and compatible driver.
%% Optional
% For non-MEX builds such as static, dynamic libraries or executables, this example has the following additional requirements.
% NVIDIA CUDA toolkit.
% NVIDIA cuDNN library.
% Environment variables for the compilers and libraries. For more information, see Third-party Products and Setting Up the Prerequisite Products.
%
%% Verify GPU Environment
% To verify that the compilers and libraries for running this example are set up correctly, use the coder.checkGpuInstall function.

envCfg = coder.gpuEnvConfig('host');
envCfg.DeepLibTarget = 'cudnn';
envCfg.DeepCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);

%
%% YOLO v3 Network
% The YOLO v3 network in this example is based on SqueezeNet, and uses the feature extraction network in SqueezeNet with the addition of two detection heads at the end. The second detection head is twice the size of the first detection head, so it is better able to detect small objects. Note that any number of detection heads of different sizes can be specified based on the size of the objects to be detected. The YOLO v3 network uses anchor boxes estimated using training data to have better initial priors corresponding to the type of data set and to help the network learn to predict the boxes accurately. For information about anchor boxes, see Anchor Boxes for Object Detection.
% The YOLO v3 network in this example is illustrated in the following diagram.
%
% Each detection head predicts the bounding box coordinates (x, y, width, height), object confidence, and class probabilities for the respective anchor box masks. Therefore, for each detection head, the number of output filters in the last convolution layer is the number of anchor box mask times the number of prediction elements per anchor box. The detection heads comprise the output layer of the network.
%
%% Pretrained YOLO v3 Network
% This example uses the yolov3SqueezeNetVehicleExample_21a.zip file containing the pretrained YOLO v3 network. This file is approximately 9MB in size. Download the file from the MathWorks website, then unzip the file.

fileName = matlab.internal.examples.downloadSupportFile('vision/data/','yolov3SqueezeNetVehicleExample_21a.zip');
unzip(fileName);

% The YOLO v3 network used in this example was trained using the steps described in Object Detection Using YOLO v3 Deep Learning.

matFile = 'yolov3SqueezeNetVehicleExample_21a.mat';
pretrained = load(matFile);
net = pretrained.net;

% YOLO v3 network uses a resize2dLayer to resize the 2-D input image by replicating the neighboring pixel values by a scaling factor of 2. The resize2DLayer is implemented as a custom layer supported for code generation. For more information, see Define Custom Deep Learning Layer for Code Generation.
% Note: You can also use the pretrained detector network availabe through the Computer Vision Toolbox™ Model for YOLO v3 Object Detection support package.
% To use this pretrained network, you must first install the Computer Vision Toolbox Model for YOLO v3 Object Detection from the Add-On Explorer. For more information about installing add-ons, see Get and Manage Add-Ons.
% Then, save the network from the yolov3ObjectDetector object to a MAT-file and proceed. For example,
% detector = yolov3ObjectDetector('darknet53-coco');
% net = detector.Network;
% matFile = 'pretrainedYOLOv3Detector.mat';
% save(matFile,'net');
%
%
%% The yolov3Detect Entry-Point Function
% The yolov3Detect entry-point function takes an input image and passes it to a trained network for prediction through the yolov3Predict function. The yolov3Predict function loads the network object from the MAT-file into a persistent variable and reuses the persistent object for subsequent prediction calls. Specifically, the function uses the dlnetwork representation of the network trained in the Object Detection Using YOLO v3 Deep Learning example. The predictions from the YOLO v3 grid cell coordinates obtained from the yolov3Predict calls are then converted to bounding box coordinates by using the supporting functions generateTiledAnchors and applyAnchorBoxOffsets.

type('yolov3Detect.m')

%
%% Evaluate the Entry-Point Function for Object Detection
% Follow these steps to evaluate the entry-point function on an image from the test data.
% Specify the confidence threshold as 0.5 to keep only detections with confidence scores above this value.
% Specify the overlap threshold as 0.5 to remove overlapping detections.
% Read an image from the input data.
% Use the entry-point function yolov3Detect to get the predicted bounding boxes, confidence scores, and class labels.
% Display the image with bounding boxes and confidence scores.
% Define the desired thresholds.

confidenceThreshold = 0.5;
overlapThreshold = 0.5;

% Specify the network input size of the trained network and the number of network outputs.

networkInputSize = [227 227 3];
networkOutputs = numel(net.OutputNames);

% Read the example image data obtained from the labeled data set from the Object Detection Using YOLO v3 Deep Learning example. This image contains one instance of an object of type vehicle.

I = imread('vehicleImage.jpg');

% Specify the class names.

classNames = {'vehicle'};

% Invoke the detect method on YOLO v3 network and display the results.

[bboxes,scores,labelsIndex] = yolov3Detect(matFile,I,...
networkInputSize,networkOutputs,confidenceThreshold,overlapThreshold,classNames);
labels = classNames(labelsIndex);

% Display the detections on the image
IAnnotated = insertObjectAnnotation(I,'rectangle',bboxes,strcat(labels,{' - '},num2str(scores)));
figure
imshow(IAnnotated)

%
%% Generate CUDA MEX
% To generate CUDA® code for the yolov3Detect entry-point function, create a GPU code configuration object for a MEX 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.

cfg = coder.gpuConfig('mex');
cfg.TargetLang = 'C++';
cfg.DeepLearningConfig = coder.DeepLearningConfig(TargetLibrary='cudnn');

args = {coder.Constant(matFile),I,coder.Constant(networkInputSize),...
coder.Constant(networkOutputs),confidenceThreshold,...
overlapThreshold,classNames};

codegen -config cfg yolov3Detect -args args -report

% To generate CUDA® code for TensorRT target create and use a TensorRT deep learning configuration object instead of the CuDNN configuration object. Similarly, to generate code for MKLDNN target, create a CPU code configuration object and use MKLDNN deep learning configuration object as its DeepLearningConfig property.
%
%% Run the Generated MEX
% Call the generated CUDA MEX with the same image input I as before and display the results.

[bboxes,scores,labelsIndex] = yolov3Detect_mex(matFile,I,...
networkInputSize,networkOutputs,confidenceThreshold,...
overlapThreshold,classNames);
labels = classNames(labelsIndex);

figure;
IAnnotated = insertObjectAnnotation(I,'rectangle',bboxes,strcat(labels,{' - '},num2str(scores)));
imshow(IAnnotated);

%
%% Utility Functions
% The utillity functions listed below are based on the ones used in Object Detection Using YOLO v3 Deep Learning example and modified to make the utility functions suitable for code generation.

type('applyActivations.m')

%

type('extractPredictions.m')

%

type('generateTiledAnchors.m')

%

type('applyAnchorBoxOffsets.m')

%

type('preprocessData.m')

%
%% References
% 1. Redmon, Joseph, and Ali Farhadi. “YOLOv3: An Incremental Improvement.” Preprint, submitted April 8, 2018. https://arxiv.org/abs/1804.02767.
% Copyright 2020-2021 The MathWorks, Inc.