В этом примере показано, как обучить семантическую сегментирующую сеть по 3-D организованным данным облака точек лидара.
StartSeg [1] - сверточная нейронная сеть (CNN) для выполнения сквозной семантической сегментации дорожных объектов на основе организованного лидарного точечного облака. Используя такие способы, как пространственное объединение пирамид (ASPP) и блоки сжатия и возбуждения, сеть обеспечивает улучшенные результаты сегментации. Процедура обучения, показанная в этом примере, требует 2-D сферических проекционных изображений в качестве входных данных для сети глубокого обучения.
В этом примере используется набор данных сцены шоссе, собранный с помощью датчика OS1 Ouster. Он содержит организованное сканирование облака точек лидара сцен шоссе и соответствующие метки истинности земли для объектов автомобилей и грузовиков. Размер файла данных составляет приблизительно 760 МБ.
Этот код используется для загрузки набора данных сцены магистрали. Набор данных содержит 1617 точечных облаков, сохраненных как pointCloud объектов в массиве ячеек. Соответствующие данные о истинности земли, которые прилагаются к примеру, содержат информацию об ограничительной рамке легковых и грузовых автомобилей в каждом облаке точек.
url = 'https://www.mathworks.com/supportfiles/lidar/data/WPI_LidarData.tar.gz'; outputFolder = fullfile(tempdir,'WPI'); lidarDataTarFile = fullfile(outputFolder,'WPI_LidarData.tar.gz'); if ~exist(lidarDataTarFile, 'file') mkdir(outputFolder); disp('Downloading WPI Lidar driving data (760 MB)...'); websave(lidarDataTarFile, url); untar(lidarDataTarFile,outputFolder); end % Check if tar.gz file is downloaded, but not uncompressed. if ~exist(fullfile(outputFolder, 'WPI_LidarData.mat'), 'file') untar(lidarDataTarFile,outputFolder); end lidarData = load(fullfile(outputFolder, 'WPI_LidarData.mat')); groundTruthData = load('WPI_LidarGroundTruth.mat');
Примечание: В зависимости от вашего подключения к Интернету процесс загрузки может занять некоторое время. Код приостанавливает выполнение MATLAB ® до завершения процесса загрузки. Кроме того, можно загрузить набор данных на локальный диск с помощью веб-браузера, а затем извлечьWPI_LidarData. Чтобы использовать файл, загруженный из Интернета, измените outputFolder переменная в коде к местоположению загруженного файла.
Загрузите предварительно обученную сеть, чтобы избежать необходимости ждать завершения обучения. Если вы хотите обучить сеть, установите doTraining переменной true.
doTraining = false; if ~doTraining && ~exist('trainedPointSegNet.mat','file') disp('Downloading pretrained network (14 MB)...'); pretrainedURL = 'https://www.mathworks.com/supportfiles/lidar/data/trainedPointSegNet.mat'; websave('trainedPointSegNet.mat', pretrainedURL); end
Downloading pretrained network (14 MB)...
Используйте helperGenerateTrainingData вспомогательная функция, присоединенная к этому примеру, для генерации обучающих данных из облаков точек лидара. Функция использует данные облака точек и ограничивающей рамки для создания пятиканальных входных изображений и изображений меток пикселей. Чтобы создать изображения меток пикселей, функция выбирает точки внутри ограничивающей рамки и помечает их идентификатором класса ограничивающей рамки. Каждый обучающий образ задается как массив 64 на 1024 на 5:
Высота каждого изображения составляет 64 пиксела.
Ширина каждого изображения составляет 1024 пикселя.
Каждое изображение имеет 5 каналов. Пять каналов определяют 3-D координаты облака точек, интенсивность и диапазон: + z2.
Ниже приведено визуальное представление обучающих данных.

Создание пятиканальных обучающих изображений и изображений меток пикселей.
imagesFolder = fullfile(outputFolder, 'images'); labelsFolder = fullfile(outputFolder, 'labels'); helperGenerateTrainingData(lidarData, groundTruthData, imagesFolder, labelsFolder);
Preprocessing data 100.00% complete
Пятиканальные изображения сохраняются в виде файлов MAT. Пиксельные метки сохраняются как PNG-файлы.
Примечание.Обработка может занять некоторое время. Код приостанавливает выполнение MATLAB ® до завершения обработки .
mageDatastore и PixelLabelDatastoreИспользуйте imageDatastore объект для извлечения и хранения пяти каналов 2-D сферических изображений с помощью helperImageMatReader поддерживающая функция, которая является пользовательским средством чтения файлов MAT. Эта функция присоединена к этому примеру как вспомогательный файл.
imds = imageDatastore(imagesFolder, ... 'FileExtensions', '.mat', ... 'ReadFcn', @helperImageMatReader);
Используйте pixelLabelDatastore объект для хранения пиксельных меток из изображений меток. Объект сопоставляет каждую пиксельную метку с именем класса. В этом примере легковые и грузовые автомобили являются единственными объектами, представляющими интерес; все остальные пикселы являются фоном. Укажите эти классы (автомобиль, грузовик и фон) и присвойте каждому классу уникальный идентификатор метки.
classNames = [
"background"
"car"
"truck"
];
numClasses = numel(classNames);
% Specify label IDs from 1 to the number of classes.
labelIDs = 1 : numClasses;
pxds = pixelLabelDatastore(labelsFolder, classNames, labelIDs);Загрузите и отобразите одно из помеченных изображений, наложив его на соответствующее изображение интенсивности с помощью helperDisplayLidarOverlayImage , определенной в разделе «Вспомогательные функции» данного примера.
imageNumber = 225; % Point cloud (channels 1, 2, and 3 are for location, channel 4 is for intensity). I = readimage(imds, imageNumber); labelMap = readimage(pxds, imageNumber); figure; helperDisplayLidarOverlayImage(I, labelMap, classNames); title('Ground Truth');

Используйте helperPartitionLidarData вспомогательная функция, присоединенная к этому примеру, для разделения данных на обучающие, валидационные и тестовые наборы, которые содержат 970, 216 и 431 изображения соответственно.
[imdsTrain, imdsVal, imdsTest, pxdsTrain, pxdsVal, pxdsTest] = ...
helperPartitionLidarData(imds, pxds);Используйте combine функция для объединения хранилищ данных пикселей и изображений для наборов данных обучения и проверки.
trainingData = combine(imdsTrain, pxdsTrain); validationData = combine(imdsVal, pxdsVal);
Увеличение данных используется для повышения точности сети путем случайного преобразования исходных данных во время обучения. С помощью увеличения данных можно добавить большее разнообразие к обучающим данным без фактического увеличения количества маркированных обучающих образцов.
Увеличение данных обучения с помощью transform с пользовательскими операциями предварительной обработки, указанными augmentData , определенной в разделе «Вспомогательные функции» данного примера. Эта функция случайным образом разворачивает сферическое 2-D изображение и связанные с ним метки в горизонтальном направлении. Применение увеличения данных только к набору данных обучения.
augmentedTrainingData = transform(trainingData, @(x) augmentData(x));
Для просмотра распределения меток классов в наборе данных используйте countEachLabel функция.
tbl = countEachLabel(pxds);
tbl(:,{'Name','PixelCount','ImagePixelCount'})ans=3×3 table
Name PixelCount ImagePixelCount
______________ __________ _______________
{'background'} 1.0473e+08 1.0597e+08
{'car' } 9.7839e+05 8.4738e+07
{'truck' } 2.6017e+05 1.9726e+07
Классы в этом наборе данных несбалансированы, что является обычной проблемой в автомобильных наборах данных, содержащих уличные сцены. Фоновый класс охватывает больше площади, чем классы легковых и грузовых автомобилей. В случае неправильной обработки этот дисбаланс может нанести ущерб процессу обучения, поскольку обучение смещено в пользу доминирующих классов.
Используйте эти веса для исправления дисбаланса классов. Использовать количество меток пикселей из tbl.PixelCount и вычислить медианные веса частотного класса.
imageFreq = tbl.PixelCount ./ tbl.ImagePixelCount; classWeights = median(imageFreq) ./ imageFreq
classWeights = 3×1
0.0133
1.1423
1.0000
Создайте сеть, используя createPointSeg вспомогательная функция, которая присоединена к примеру. Код возвращает график слоев, используемый для обучения сети.
inputSize = [64 1024 5]; lgraph = createPointSeg(inputSize, classNames, classWeights);
Используйте analyzeNetwork Функция (Deep Learning Toolbox) для отображения интерактивной визуализации сетевой архитектуры.
analyzeNetwork(lgraph)
Используйте rmsprop алгоритм оптимизации для обучения сети. Укажите гиперпараметры для алгоритма с помощью trainingOptions функция.
maxEpochs = 30; initialLearningRate= 5e-4; miniBatchSize = 8; l2reg = 2e-4; options = trainingOptions('rmsprop', ... 'InitialLearnRate', initialLearningRate, ... 'L2Regularization', l2reg, ... 'MaxEpochs', maxEpochs, ... 'MiniBatchSize', miniBatchSize, ... 'LearnRateSchedule', 'piecewise', ... 'LearnRateDropFactor', 0.1, ... 'LearnRateDropPeriod', 10, ... 'ValidationData', validationData, ... 'Plots', 'training-progress', ... 'VerboseFrequency', 20);
Примечание: Уменьшить miniBatchSize для управления использованием памяти при обучении.
Используйте trainNetwork Функция (Deep Learning Toolbox), позволяющая обучать сеть, если doTraining является true. В противном случае загрузите предварительно подготовленную сеть.
При обучении сети можно использовать ЦП или графический процессор. Для использования графического процессора требуются параллельные вычислительные Toolbox™ и графический процессор NVIDIA ® с поддержкой CUDA ®. Дополнительные сведения см. в разделе Поддержка графического процессора по выпуску (Панель инструментов параллельных вычислений).
if doTraining [net, info] = trainNetwork(trainingData, lgraph, options); else pretrainedNetwork = load('trainedPointSegNet.mat'); net = pretrainedNetwork.net; end
Используйте обученную сеть для прогнозирования результатов в облаке контрольных точек и отображения результатов сегментации.
Сначала прочтите PCD-файл и преобразуйте облако точек в пятиканальное входное изображение. Спрогнозировать метки с помощью обученной сети. Отображение фигуры с сегментацией в виде наложения.
ptCloud = pcread('ousterLidarDrivingData.pcd'); I = helperPointCloudToImage(ptCloud); predictedResult = semanticseg(I, net); figure; helperDisplayLidarOverlayImage(I, predictedResult, classNames); title('Semantic Segmentation Result');

Используйте helperDisplayLidarOverlayPointCloud вспомогательная функция, определенная в разделе «Вспомогательные функции» этого примера, для отображения результата сегментации по объекту облака точек 3-D ptCloud .
figure;
helperDisplayLidarOverlayPointCloud(ptCloud, predictedResult, numClasses);
view([95.71 24.14])
title('Semantic Segmentation Result on Point Cloud');
Запустить semanticseg функция на всем тестовом наборе для измерения точности сети. Набор MiniBatchSize до значения 8 для уменьшения использования памяти при сегментировании изображений. Это значение можно увеличить или уменьшить в зависимости от объема памяти графического процессора в системе.
outputLocation = fullfile(tempdir, 'output'); if ~exist(outputLocation,'dir') mkdir(outputLocation); end pxdsResults = semanticseg(imdsTest, net, ... 'MiniBatchSize', 8, ... 'WriteLocation', outputLocation, ... 'Verbose', false);
semanticseg функция возвращает результаты сегментации набора тестовых данных в виде PixelLabelDatastore объект. Функция записывает фактические данные метки пикселя для каждого тестового изображения в imdsTest объект на диск в расположении, указанном 'WriteLocation' аргумент.
Используйте evaluateSemanticSegmentation функция для вычисления метрик семантической сегментации по результатам тестового набора.
metrics = evaluateSemanticSegmentation(pxdsResults, pxdsTest, 'Verbose', false);Величину перекрытия в классе можно измерить с помощью метрики пересечение-объединение (IoU).
evaluateSemanticSegmentation функция возвращает метрики для всего набора данных, для отдельных классов и для каждого тестового образа. Для просмотра метрик на уровне набора данных используйте metrics.DataSetMetrics собственность.
metrics.DataSetMetrics
ans=1×5 table
GlobalAccuracy MeanAccuracy MeanIoU WeightedIoU MeanBFScore
______________ ____________ _______ ___________ ___________
0.99209 0.83752 0.67895 0.98685 0.91654
Метрики набора данных обеспечивают общий обзор производительности сети. Чтобы увидеть влияние каждого класса на общую производительность, проверьте метрики для каждого класса с помощью metrics.ClassMetrics собственность.
metrics.ClassMetrics
ans=3×3 table
Accuracy IoU MeanBFScore
________ _______ ___________
background 0.99466 0.99212 0.98529
car 0.75977 0.50096 0.82682
truck 0.75814 0.54378 0.77119
Хотя общая производительность сети хорошая, метрики классов показывают, что смещенные классы (легковые и грузовые) не сегментированы так же, как классы с обильными данными (фон). Вы можете повысить производительность сети, обучая сеть более маркированным данным, содержащим классы автомобилей и грузовиков.
augmentData функция случайным образом разворачивает 2-D сферическое изображение и связанные с ним метки в горизонтальном направлении.
function out = augmentData(inp) %augmentData Apply random horizontal flipping. out = cell(size(inp)); % Randomly flip the five-channel image and pixel labels horizontally. I = inp{1}; sz = size(I); tform = randomAffine2d('XReflection',true); rout = affineOutputView(sz,tform,'BoundsStyle','centerOutput'); out{1} = imwarp(I,tform,'OutputView',rout); out{2} = imwarp(inp{2},tform,'OutputView',rout); end
helperDisplayLidarOverlayImage функция перекрывает семантическую карту сегментации по каналу интенсивности 2-D сферического изображения. Функция также изменяет размер наложенного изображения для улучшения визуализации.
function helperDisplayLidarOverlayImage(lidarImage, labelMap, classNames) %helperDisplayLidarOverlayImage Overlay labels over the intensity image. % % helperDisplayLidarOverlayImage(lidarImage, labelMap, classNames) % displays the overlaid image. lidarImage is a five-channel lidar input. % labelMap contains pixel labels and classNames is an array of label % names. % Read the intensity channel from the lidar image. intensityChannel = uint8(lidarImage(:,:,4)); % Load the lidar color map. cmap = helperLidarColorMap(); % Overlay the labels over the intensity image. B = labeloverlay(intensityChannel,labelMap,'Colormap',cmap,'Transparency',0.4); % Resize for better visualization. B = imresize(B, 'Scale', [3 1], 'method', 'nearest'); imshow(B); % Display the color bar. helperPixelLabelColorbar(cmap, classNames); end
helperDisplayLidarOverPointCloud функция накладывает результат сегментации на 3-D организованное облако точек.
function helperDisplayLidarOverlayPointCloud(ptCloud, labelMap, numClasses) %helperDisplayLidarOverlayPointCloud Overlay labels over a point cloud object. % % helperDisplayLidarOverlayPointCloud(ptCloud, labelMap, numClasses) % displays the overlaid pointCloud object. ptCloud is the organized % 3-D point cloud input. labelMap contains pixel labels and numClasses % is the number of predicted classes. sz = size(labelMap); % Apply the color red to cars. carClassCar = zeros(sz(1), sz(2), numClasses, 'uint8'); carClassCar(:,:,1) = 255*ones(sz(1), sz(2), 'uint8'); % Apply the color blue to trucks. truckClassColor = zeros(sz(1), sz(2), numClasses, 'uint8'); truckClassColor(:,:,3) = 255*ones(sz(1), sz(2), 'uint8'); % Apply the color gray to the background. backgroundClassColor = 153*ones(sz(1), sz(2), numClasses, 'uint8'); % Extract indices from the labels. carIndices = labelMap == 'car'; truckIndices = labelMap == 'truck'; backgroundIndices = labelMap == 'background'; % Extract a point cloud for each class. carPointCloud = select(ptCloud, carIndices, 'OutputSize','full'); truckPointCloud = select(ptCloud, truckIndices, 'OutputSize','full'); backgroundPointCloud = select(ptCloud, backgroundIndices, 'OutputSize','full'); % Apply colors to different classes. carPointCloud.Color = carClassCar; truckPointCloud.Color = truckClassColor; backgroundPointCloud.Color = backgroundClassColor; % Merge and add all the processed point clouds with class information. coloredCloud = pcmerge(carPointCloud, truckPointCloud, 0.01); coloredCloud = pcmerge(coloredCloud, backgroundPointCloud, 0.01); % Plot the colored point cloud. Set an ROI for better visualization. ax = pcshow(coloredCloud); set(ax,'XLim',[-35.0 35.0],'YLim',[-32.0 32.0],'ZLim',[-3 8], ... 'XColor','none','YColor','none','ZColor','none'); set(get(ax,'parent'), 'units','normalized'); end
helperLidarColorMap функция определяет карту цветов, используемую набором данных лидара.
function cmap = helperLidarColorMap() cmap = [ 0.00 0.00 0.00 % background 0.98 0.00 0.00 % car 0.00 0.00 0.98 % truck ]; end
helperPixelLabelColorbar функция добавляет панель цветов к текущей оси. Панель цветов отформатирована для отображения имен классов с цветом.
function helperPixelLabelColorbar(cmap, classNames) colormap(gca, cmap); % Add a colorbar to the current figure. c = colorbar('peer', gca); % Use class names for tick marks. c.TickLabels = classNames; numClasses = size(classNames, 1); % Center tick labels. c.Ticks = 1/(numClasses * 2):1/numClasses:1; % Remove tick marks. c.TickLength = 0; end
[1] Ван, Юань, Тяньюэ Ши, Пэн Юнь, Лэй Тай и Мин Лю. «PointSeg: семантическая сегментация в реальном времени на основе 3D облака пункта LiDAR». ArXiv:1807.06288 [Cs], 25 сентября 2018 года. http://arxiv.org/abs/1807.06288.