В этом примере показано, как создать код CUDA ® MEX для приложения обнаружения и распознавания дорожных знаков, использующего глубокое обучение. Обнаружение и распознавание дорожных знаков является важным приложением для систем помощи водителю, помогая и предоставляя информацию водителю о дорожных знаках.

В этом примере обнаружения и распознавания знаков трафика выполняются три шага - обнаружение, Non-Maximal Suppression (NMS) и распознавание. Во-первых, пример обнаруживает знаки трафика на входном изображении с помощью сети обнаружения объектов, которая является вариантом сети YOLO. Затем перекрывающиеся обнаружения подавляются с помощью алгоритма NMS. Наконец, сеть распознавания классифицирует обнаруженные знаки трафика.
Необходимый
В этом примере создается CUDA MEX со следующими требованиями сторонних производителей.
Графический процессор NVIDIA ® с поддержкой CUDA ® и совместимый драйвер.
Дополнительный
Для построений, отличных от MEX, таких как статические, динамические библиотеки или исполняемые файлы, этот пример имеет следующие дополнительные требования.
Инструментарий NVIDIA.
Библиотека NVIDIA cuDNN.
Переменные среды для компиляторов и библиотек. Дополнительные сведения см. в разделах Аппаратное обеспечение сторонних производителей и Настройка необходимых продуктов.
Используйте coder.checkGpuInstall для проверки правильности настройки компиляторов и библиотек, необходимых для выполнения этого примера.
envCfg = coder.gpuEnvConfig('host'); envCfg.DeepLibTarget = 'cudnn'; envCfg.DeepCodegen = 1; envCfg.Quiet = 1; coder.checkGpuInstall(envCfg);
Сеть обнаружения обучается в рамках Darknet и импортируется в MATLAB ® для вывода. Поскольку размер знака трафика относительно мал по сравнению с размером изображения и количество обучающих образцов на класс меньше в обучающих данных, все дорожные знаки рассматриваются как единый класс для обучения сети обнаружения.
Сеть обнаружения делит входное изображение на сетку 7 на 7. Каждая ячейка сетки обнаруживает знак трафика, если центр знака трафика находится внутри ячейки сетки. Каждая ячейка предсказывает две ограничивающие рамки и оценки достоверности для этих ограничивающих рамок. Оценки достоверности указывают, содержит ли поле объект или нет. Каждая ячейка предсказывает вероятность нахождения знака трафика в ячейке сетки. Окончательный балл является результатом предыдущих баллов. Для выбора обнаружений применяется пороговое значение 0,2.
Сеть распознавания обучается на тех же изображениях с помощью MATLAB.
В сценарии помощника Trainconnet.m показано обучение сети распознавания.
Загрузите сети обнаружения и распознавания.
getTsdr();
Сеть обнаружения содержит 58 уровней, включая сверточный, протекающий ReLU и полностью соединенные слои.
load('yolo_tsr.mat');
yolo.Layers
ans =
58×1 Layer array with layers:
1 'input' Image Input 448×448×3 images
2 'conv1' Convolution 64 7×7×3 convolutions with stride [2 2] and padding [3 3 3 3]
3 'relu1' Leaky ReLU Leaky ReLU with scale 0.1
4 'pool1' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0]
5 'conv2' Convolution 192 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1]
6 'relu2' Leaky ReLU Leaky ReLU with scale 0.1
7 'pool2' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0]
8 'conv3' Convolution 128 1×1×192 convolutions with stride [1 1] and padding [0 0 0 0]
9 'relu3' Leaky ReLU Leaky ReLU with scale 0.1
10 'conv4' Convolution 256 3×3×128 convolutions with stride [1 1] and padding [1 1 1 1]
11 'relu4' Leaky ReLU Leaky ReLU with scale 0.1
12 'conv5' Convolution 256 1×1×256 convolutions with stride [1 1] and padding [0 0 0 0]
13 'relu5' Leaky ReLU Leaky ReLU with scale 0.1
14 'conv6' Convolution 512 3×3×256 convolutions with stride [1 1] and padding [1 1 1 1]
15 'relu6' Leaky ReLU Leaky ReLU with scale 0.1
16 'pool6' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0]
17 'conv7' Convolution 256 1×1×512 convolutions with stride [1 1] and padding [0 0 0 0]
18 'relu7' Leaky ReLU Leaky ReLU with scale 0.1
19 'conv8' Convolution 512 3×3×256 convolutions with stride [1 1] and padding [1 1 1 1]
20 'relu8' Leaky ReLU Leaky ReLU with scale 0.1
21 'conv9' Convolution 256 1×1×512 convolutions with stride [1 1] and padding [0 0 0 0]
22 'relu9' Leaky ReLU Leaky ReLU with scale 0.1
23 'conv10' Convolution 512 3×3×256 convolutions with stride [1 1] and padding [1 1 1 1]
24 'relu10' Leaky ReLU Leaky ReLU with scale 0.1
25 'conv11' Convolution 256 1×1×512 convolutions with stride [1 1] and padding [0 0 0 0]
26 'relu11' Leaky ReLU Leaky ReLU with scale 0.1
27 'conv12' Convolution 512 3×3×256 convolutions with stride [1 1] and padding [1 1 1 1]
28 'relu12' Leaky ReLU Leaky ReLU with scale 0.1
29 'conv13' Convolution 256 1×1×512 convolutions with stride [1 1] and padding [0 0 0 0]
30 'relu13' Leaky ReLU Leaky ReLU with scale 0.1
31 'conv14' Convolution 512 3×3×256 convolutions with stride [1 1] and padding [1 1 1 1]
32 'relu14' Leaky ReLU Leaky ReLU with scale 0.1
33 'conv15' Convolution 512 1×1×512 convolutions with stride [1 1] and padding [0 0 0 0]
34 'relu15' Leaky ReLU Leaky ReLU with scale 0.1
35 'conv16' Convolution 1024 3×3×512 convolutions with stride [1 1] and padding [1 1 1 1]
36 'relu16' Leaky ReLU Leaky ReLU with scale 0.1
37 'pool16' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0]
38 'conv17' Convolution 512 1×1×1024 convolutions with stride [1 1] and padding [0 0 0 0]
39 'relu17' Leaky ReLU Leaky ReLU with scale 0.1
40 'conv18' Convolution 1024 3×3×512 convolutions with stride [1 1] and padding [1 1 1 1]
41 'relu18' Leaky ReLU Leaky ReLU with scale 0.1
42 'conv19' Convolution 512 1×1×1024 convolutions with stride [1 1] and padding [0 0 0 0]
43 'relu19' Leaky ReLU Leaky ReLU with scale 0.1
44 'conv20' Convolution 1024 3×3×512 convolutions with stride [1 1] and padding [1 1 1 1]
45 'relu20' Leaky ReLU Leaky ReLU with scale 0.1
46 'conv21' Convolution 1024 3×3×1024 convolutions with stride [1 1] and padding [1 1 1 1]
47 'relu21' Leaky ReLU Leaky ReLU with scale 0.1
48 'conv22' Convolution 1024 3×3×1024 convolutions with stride [2 2] and padding [1 1 1 1]
49 'relu22' Leaky ReLU Leaky ReLU with scale 0.1
50 'conv23' Convolution 1024 3×3×1024 convolutions with stride [1 1] and padding [1 1 1 1]
51 'relu23' Leaky ReLU Leaky ReLU with scale 0.1
52 'conv24' Convolution 1024 3×3×1024 convolutions with stride [1 1] and padding [1 1 1 1]
53 'relu24' Leaky ReLU Leaky ReLU with scale 0.1
54 'fc25' Fully Connected 4096 fully connected layer
55 'relu25' Leaky ReLU Leaky ReLU with scale 0.1
56 'fc26' Fully Connected 539 fully connected layer
57 'softmax' Softmax softmax
58 'classoutput' Classification Output crossentropyex with '1' and 538 other classes
Сеть распознавания содержит 14 слоев, включая сверточные, полностью соединенные и классификационные выходные слои.
load('RecognitionNet.mat');
convnet.Layers
ans =
14×1 Layer array with layers:
1 'imageinput' Image Input 48×48×3 images with 'zerocenter' normalization and 'randfliplr' augmentations
2 'conv_1' Convolution 100 7×7×3 convolutions with stride [1 1] and padding [0 0 0 0]
3 'relu_1' ReLU ReLU
4 'maxpool_1' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0]
5 'conv_2' Convolution 150 4×4×100 convolutions with stride [1 1] and padding [0 0 0 0]
6 'relu_2' ReLU ReLU
7 'maxpool_2' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0]
8 'conv_3' Convolution 250 4×4×150 convolutions with stride [1 1] and padding [0 0 0 0]
9 'maxpool_3' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0]
10 'fc_1' Fully Connected 300 fully connected layer
11 'dropout' Dropout 90% dropout
12 'fc_2' Fully Connected 35 fully connected layer
13 'softmax' Softmax softmax
14 'classoutput' Classification Output crossentropyex with '0' and 34 other classes
tsdr_predict Функция точки входаФункция tsdr_predict.m точки входа принимает входной сигнал изображения и обнаруживает знаки трафика в изображении с помощью сети обнаружения. Функция подавляет перекрывающиеся обнаружения (NMS) с помощью selectStrongestBbox и распознает знак трафика с помощью сети распознавания. Функция загружает сетевые объекты из yolo_tsr.mat в постоянную переменную detectionnet и RecognitionNet.mat в постоянное распознавание переменных. Функция повторно использует постоянные объекты при последующих вызовах.
type('tsdr_predict.m')
function [selectedBbox,idx] = tsdr_predict(img)
%#codegen
% This function detects the traffic signs in the image using Detection Network
% (modified version of Yolo) and recognizes(classifies) using Recognition Network
%
% Inputs :
%
% im : Input test image
%
% Outputs :
%
% selectedBbox : Detected bounding boxes
% idx : Corresponding classes
% Copyright 2017-2019 The MathWorks, Inc.
coder.gpu.kernelfun;
% resize the image
img_rz = imresize(img,[448,448]);
% Converting into BGR format
img_rz = img_rz(:,:,3:-1:1);
img_rz = im2single(img_rz);
%% TSD
persistent detectionnet;
if isempty(detectionnet)
detectionnet = coder.loadDeepLearningNetwork('yolo_tsr.mat','Detection');
end
predictions = detectionnet.activations(img_rz,56,'OutputAs','channels');
%% Convert predictions to bounding box attributes
classes = 1;
num = 2;
side = 7;
thresh = 0.2;
[h,w,~] = size(img);
boxes = single(zeros(0,4));
probs = single(zeros(0,1));
for i = 0:(side*side)-1
for n = 0:num-1
p_index = side*side*classes + i*num + n + 1;
scale = predictions(p_index);
prob = zeros(1,classes+1);
for j = 0:classes
class_index = i*classes + 1;
tempProb = scale*predictions(class_index+j);
if tempProb > thresh
row = floor(i / side);
col = mod(i,side);
box_index = side*side*(classes + num) + (i*num + n)*4 + 1;
bxX = (predictions(box_index + 0) + col) / side;
bxY = (predictions(box_index + 1) + row) / side;
bxW = (predictions(box_index + 2)^2);
bxH = (predictions(box_index + 3)^2);
prob(j+1) = tempProb;
probs = [probs;tempProb];
boxX = (bxX-bxW/2)*w+1;
boxY = (bxY-bxH/2)*h+1;
boxW = bxW*w;
boxH = bxH*h;
boxes = [boxes; boxX,boxY,boxW,boxH];
end
end
end
end
%% Run Non-Maximal Suppression on the detected bounding boxess
coder.varsize('selectedBbox',[98, 4],[1 0]);
[selectedBbox,~] = selectStrongestBbox(round(boxes),probs);
%% Recognition
persistent recognitionnet;
if isempty(recognitionnet)
recognitionnet = coder.loadDeepLearningNetwork('RecognitionNet.mat','Recognition');
end
idx = zeros(size(selectedBbox,1),1);
inpImg = coder.nullcopy(zeros(48,48,3,size(selectedBbox,1)));
for i = 1:size(selectedBbox,1)
ymin = selectedBbox(i,2);
ymax = ymin+selectedBbox(i,4);
xmin = selectedBbox(i,1);
xmax = xmin+selectedBbox(i,3);
% Resize Image
inpImg(:,:,:,i) = imresize(img(ymin:ymax,xmin:xmax,:),[48,48]);
end
for i = 1:size(selectedBbox,1)
output = recognitionnet.predict(inpImg(:,:,:,i));
[~,idx(i)]=max(output);
end
tsdr_predict ФункцияСоздайте объект конфигурации графического процессора для цели MEX и установите для целевого языка значение C++. Используйте coder.DeepLearningConfig для создания функции CuDNN глубокий объект конфигурации обучения и назначить его DeepLearningConfig свойства объекта конфигурации кода графического процессора. Для создания CUDA MEX используйте codegen и укажите входные данные, которые должны иметь размер [480 704 3]. Это значение соответствует размеру входного изображения tsdr_predict функция.
cfg = coder.gpuConfig('mex'); cfg.TargetLang = 'C++'; cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn'); codegen -config cfg tsdr_predict -args {ones(480,704,3,'uint8')} -report
Code generation successful: To view the report, open('codegen/mex/tsdr_predict/html/report.mldatx').
Чтобы создать код с помощью TensorRT, передайте coder.DeepLearningConfig('tensorrt') как опция для объекта конфигурации кодера вместо 'cudnn'.
Загрузите входное изображение.
im = imread('stop.jpg');
imshow(im);

Звонить tsdr_predict_mex на входном изображении.
im = imresize(im, [480,704]); [bboxes,classes] = tsdr_predict_mex(im);
Сопоставьте номера классов с именами знаков трафика в словаре классов.
classNames = {'addedLane','slow','dip','speedLimit25','speedLimit35','speedLimit40','speedLimit45',...
'speedLimit50','speedLimit55','speedLimit65','speedLimitUrdbl','doNotPass','intersection',...
'keepRight','laneEnds','merge','noLeftTurn','noRightTurn','stop','pedestrianCrossing',...
'stopAhead','rampSpeedAdvisory20','rampSpeedAdvisory45','truckSpeedLimit55',...
'rampSpeedAdvisory50','turnLeft','rampSpeedAdvisoryUrdbl','turnRight','rightLaneMustTurn',...
'yield','yieldAhead','school','schoolSpeedLimit25','zoneAhead45','signalAhead'};
classRec = classNames(classes);
Отображение обнаруженных знаков трафика.
outputImage = insertShape(im,'Rectangle',bboxes,'LineWidth',3); for i = 1:size(bboxes,1) outputImage = insertText(outputImage,[bboxes(i,1)+bboxes(i,3) bboxes(i,2)-20],classRec{i},'FontSize',20,'TextColor','red'); end imshow(outputImage);

Включенный вспомогательный файл tsdr_testVideo.m захватывает кадры из тестового видео, выполняет обнаружение и распознавание дорожных знаков и отображает результаты на каждом кадре тестового видео.
% Input video
v = VideoReader('stop.avi');
fps = 0; while hasFrame(v)
% Take a frame
picture = readFrame(v);
picture = imresize(picture,[920,1632]);
% Call MEX function for Traffic Sign Detection and Recognition
tic;
[bboxes,clases] = tsdr_predict_mex(picture);
newt = toc; % fps
fps = .9*fps + .1*(1/newt);% display
displayDetections(picture,bboxes,clases,fps);
endОчистка статических сетевых объектов, загруженных в память.
clear mex;