Обнаружение и распознавание дорожных знаков

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

В этом примере обнаружения и распознавания дорожных знаков вы выполняете три шага - обнаружение, Non-Maximal Suppression (NMS) и распознавание. Во-первых, пример обнаруживает дорожные знаки на вход изображении с помощью сети обнаружения объектов, которая является вариантом сети You Only Look Once (YOLO). Затем перекрывающиеся обнаружения подавляются при помощи алгоритма NMS. Наконец, сеть распознавания классифицирует обнаруженные дорожные знаки.

Необходимые условия для третьих лиц

Необходимый

Этот пример генерирует CUDA MEX и имеет следующие требования к третьим лицам.

  • Графический процессор NVIDIA с поддержкой CUDA ® и совместимый драйвер.

Дополнительный

Для сборок, не являющихся MEX, таких как статические, динамические библиотеки или исполняемые файлы, этот пример имеет следующие дополнительные требования.

Проверьте окружение GPU

Используйте coder.checkGpuInstall (GPU Coder) для проверки правильности настройки компиляторов и библиотек, необходимых для выполнения этого примера.

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

Сети обнаружения и распознавания

Сеть обнаружения обучается в среде Darknet и импортируется в MATLAB ® для вывода. Поскольку размер дорожного знака относительно невелик относительно размера изображения, а количество обучающих выборок на класс меньше в обучающих данных, все дорожные знаки рассматриваются как один класс для настройки сети обнаружения.

Сеть обнаружения разделяет вход изображение на сетку 7 на 7. Каждая сетевая камера обнаруживает дорожный знак, если центр дорожного знака попадает в сетевую камеру. Каждая камера предсказывает два ограничивающих прямоугольника и оценки достоверности для этих ограничивающих прямоугольников. Оценками достоверности указать, содержит ли поле объект или нет. Каждая камера предсказывает вероятность нахождения знака трафика в сетевую камеру. Итоговый счет является продуктом предыдущих счетов. Вы применяете порог 0,2 для этого итогового счета, чтобы выбрать обнаружения.

Сеть распознавания обучается на тех же изображениях при помощи MATLAB.

Вспомогательный скрипт trainRecognitionnet.m показывает обучение сети распознавания.

Получите предварительно обученную сеть SeriesNetwork

Загрузите сети обнаружения и распознавания.

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

The tsdr_predict Функция точки входа

Функция точки входа tsdr_predict.m принимает изображение и обнаруживает дорожные знаки в изображении при помощи сети обнаружения. Функция подавляет перекрывающиеся обнаружения (NMS) при помощи selectStrongestBbox и распознает знак трафика при помощи сети распознавания. Функция загружает сетевые объекты из yolo_tsr.mat в постоянную переменную детектионнет и 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

Сгенерируйте MEX CUDA для tsdr_predict Функция

Создайте объект строения GPU для цели MEX и установите целевой язык на C++. Используйте coder.DeepLearningConfig (GPU Coder) функция для создания CuDNN объект строения глубокого обучения и присвоение его DeepLearningConfig свойство объекта строения кода GPU. Чтобы сгенерировать 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'.

Запуск сгенерированного MEX

Загрузите вход изображение.

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;

Похожие темы

Для просмотра документации необходимо авторизоваться на сайте