交通标志检测和识别
此示例说明如何为使用深度学习的交通标志检测和识别应用程序生成 CUDA® MEX 代码。交通标志检测和识别是驾驶辅助系统的重要应用,可辅助并向驾驶员提供有关道路标志的信息。

在此交通标志检测和识别示例中,执行三个步骤 - 检测、非最大值抑制 (NMS) 和识别。首先,该示例使用 You Only Look Once (YOLO) 网络的目标检测网络变体检测输入图像上的交通标志。然后,使用 NMS 算法抑制重叠检测。最后,识别网络对检测到的交通标志进行分类。
第三方前提条件
必需
此示例生成 CUDA MEX,并具有以下第三方要求。
CUDA 支持 NVIDIA® GPU 和兼容驱动。
可选
对于非 MEX 编译,如静态、动态库或可执行文件,此示例有以下附加要求。
NVIDIA 工具包。
NVIDIA cuDNN 库。
编译器和库的环境变量。有关详细信息,请参阅Third-Party Hardware (GPU Coder)和Setting Up the Prerequisite Products (GPU Coder)。
验证 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 辅助脚本显示识别网络训练。
获得预训练检测器和识别网络
此示例使用包含预训练网络的 yolo_tsr 和 RecognitionNet MAT 文件。这两个文件的大小分别约为 6MB 和 992MB。从 MathWorks® 网站下载该文件。
detectorNet = matlab.internal.examples.downloadSupportFile('gpucoder/cnn_models/traffic_sign_detection/v001','yolo_tsr.mat'); recognitionNet = matlab.internal.examples.downloadSupportFile('gpucoder/cnn_models/traffic_sign_detection/v001','RecognitionNet.mat');
检测网络包含 58 个层,包括卷积层、泄漏 ReLU 层和全连接层。
load(detectorNet); yolo
yolo =
SeriesNetwork with properties:
Layers: [58×1 nnet.cnn.layer.Layer]
InputNames: {'input'}
OutputNames: {'classoutput'}
要查看网络架构,请使用 analyzeNetwork 函数。
analyzeNetwork(yolo)
识别网络包含 14 个层,包括卷积层和全连接层。
load(recognitionNet); convnet
convnet =
SeriesNetwork with properties:
Layers: [14×1 nnet.cnn.layer.Layer]
InputNames: {'imageinput'}
OutputNames: {'classoutput'}
将 SeriesNetwork 对象转换为 dlnetwork 对象,并将它们保存到不同 MAT 文件中。
dlyolo = dag2dlnetwork(yolo); dlconvnet = dag2dlnetwork(convnet); detectorNet = 'detectorNet.mat'; recognitionNet = 'recognitionNet.mat'; save(detectorNet, 'dlyolo'); save(recognitionNet, 'dlconvnet');
tsdr_predict 入口函数
tsdr_predict.m 入口函数以图像作为输入,并使用检测网络检测图像中的交通标志。该函数使用 selectStrongestBbox 抑制重叠检测 (NMS),并使用识别网络识别交通标志。该函数将 dlyolo_tsr.mat 中的网络对象加载到持久变量 detectionnet 中,并将 dlRecognitionNet.mat 中的网络对象加载到持久变量 recognitionnet 中。该函数在后续调用中将重用这些持久性对象。
type('tsdr_predict.m')function [selectedBbox,idx] = tsdr_predict(img,detectorMATFile,recogMATFile)
%#codegen
% Copyright 2017-2024 The MathWorks, Inc.
% 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);
% create a formatted dlarray with 'SSC' format
dlimg_rz = dlarray(img_rz, 'SSC');
%% Traffic Signal Detection
persistent detectionnet;
if isempty(detectionnet)
detectionnet = coder.loadDeepLearningNetwork(detectorMATFile,'Detection');
end
dlpredictions = predict(detectionnet, dlimg_rz, Outputs = 'fc26');
% Extract numeric array from dlarray
predictions = extractdata(dlpredictions);
%% 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(recogMATFile,'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
% Create a formatted dlarray with 'SSCB' format
dlinpImg = dlarray(single(inpImg), 'SSCB');
for i = 1:size(selectedBbox,1)
output = predict(recognitionnet, dlinpImg(:,:,:,i));
[~,idx(i)]=max(extractdata(output));
end
为 tsdr_predict 函数生成 CUDA MEX
为 MEX 目标创建一个 GPU 配置对象,并将目标语言设置为 C++。使用 coder.DeepLearningConfig (GPU Coder) 函数创建一个 CuDNN 深度学习配置对象,并将其赋给 GPU 代码配置对象的 DeepLearningConfig 属性。要生成 CUDA MEX,请使用 codegen 命令并指定输入大小为 [480,704,3]。该值对应于 tsdr_predict 函数的输入图像大小。
cfg = coder.gpuConfig('mex'); cfg.TargetLang = 'C++'; cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn'); inputArgs = {ones(480,704,3,'uint8'),coder.Constant(detectorNet),... coder.Constant(recognitionNet)}; codegen -config cfg tsdr_predict -args inputArgs -report
Code generation successful: View report
要使用 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,detectorNet,recognitionNet);
将类编号映射到类字典中的交通标志名称。
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 从测试视频中抓取帧,执行交通标志检测和识别,并绘制测试视频的每个帧的结果。
type tsdr_testVideofunction tsdr_testVideo
% Copyright 2017-2024 The MathWorks, Inc.
% Input video
v = VideoReader('stop.avi');
detectorNet = 'detectorNet.mat';
recognitionNet = 'recognitionNet.mat';
fps = 0;
while hasFrame(v)
% Take a frame
picture = readFrame(v);
picture = imresize(picture,[480,704]);
% Call MEX function for Traffic Sign Detection and Recognition
tic;
[bboxes,clases] = tsdr_predict_mex(picture,detectorNet,recognitionNet);
newt = toc;
% fps
fps = .9*fps + .1*(1/newt);
% display
displayDetections(picture,bboxes,clases,fps);
end
end
function displayDetections(im,boundingBoxes,classIndices,fps)
% Function for inserting the detected bounding boxes and recognized classes
% and displaying the result
%
% Inputs :
%
% im : Input test image
% boundingBoxes : Detected bounding boxes
% classIndices : Corresponding classes
%
% Traffic Signs (35)
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'};
outputImage = insertShape(im,'Rectangle',boundingBoxes,'LineWidth',3);
for i = 1:size(boundingBoxes,1)
ymin = boundingBoxes(i,2);
xmin = boundingBoxes(i,1);
xmax = xmin+boundingBoxes(i,3);
% inserting class as text at YOLO detection
classRec = classNames{classIndices(i)};
outputImage = insertText(outputImage,[xmax ymin-20],classRec,...
'FontSize',20,'TextColor','red');
end
outputImage = insertText(outputImage,...
round(([size(outputImage,1) 40]/2)-20),...
['Frame Rate: ',num2str(fps)],'FontSize',20,'TextColor','red');
imshow(outputImage);
end