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

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

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

Сторонние необходимые условия

Необходимый

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

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

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

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

Проверьте среду графического процессора

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

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

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

Сеть обнаружения обучена в среде даркнета и импортирована в 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

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

tsdr_predict.m функция точки входа берет вход изображений и обнаруживает дорожные знаки в изображении при помощи сети обнаружения. Функция подавляет перекрывающиеся обнаружения (NMS) при помощи selectStrongestBbox и распознает дорожный знак при помощи сети распознавания. Функция загружает сетевые объекты от yolo_tsr.mat в персистентную переменную detectionnet и RecognitionNet.mat в персистентную переменную recognitionnet. Функциональные повторные использования постоянные объекты на последующих вызовах.

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 Функция

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

Похожие темы