exponenta event banner

Обнаружение, классификация и отслеживание транспортных средств с помощью Lidar

В этом примере показано, как обнаруживать, классифицировать и отслеживать транспортные средства с помощью данных облака точек лидара, захваченных датчиком лидара, установленным на эго-транспортном средстве. Лидарные данные, используемые в этом примере, записываются из сценария вождения шоссе. В этом примере данные облака точек сегментируются для определения класса объектов с помощью PointSeg сеть. Для отслеживания обнаруженных транспортных средств используется трекер совместной вероятностной ассоциации данных (JPDA) с интерактивным множественным модельным фильтром.

Обзор

Модуль восприятия играет важную роль в достижении полной автономности транспортных средств с системой ADAS. Лидар и камера являются важными датчиками в процессе восприятия. Лидар хорошо извлекает точную информацию о глубине объектов, в то время как камера создает богатую и подробную информацию об окружающей среде, которая полезна для классификации объектов.

Этот пример включает в себя главным образом следующие части:

  • Сегментация наземной плоскости

  • Семантическая сегментация

  • Ориентированный фитинг ограничивающей рамки

  • Отслеживание ориентированных ограничивающих рамок

На блок-схеме представлен обзор всей системы.

Загрузить данные

Лидарный датчик генерирует данные облака точек либо в организованном формате, либо в неорганизованном формате. Данные, используемые в этом примере, собираются с помощью датчика Ouster OS1 lidar. Этот лидар создает организованное облако точек с 64 горизонтальными линиями сканирования. Данные облака точек состоят из трех каналов, представляющих координаты точек x, y и z. Каждый канал имеет размер 64 на 1024. Использовать функцию помощника helperDownloadData для загрузки данных и их загрузки в рабочую область MATLAB ®.

Примечание: Загрузка может занять несколько минут.

[ptClouds,pretrainedModel] = helperDownloadData;

Сегментация нулевой плоскости

В этом примере используется гибридный подход, который использует segmentGroundFromLidarData (инструментарий компьютерного зрения) и pcfitplane(Панель инструментов компьютерного зрения). Сначала оцените параметры нулевой плоскости с помощью segmentGroundFromLidarData функция. Расчетная плоскость земли разделена на полосы вдоль направления транспортного средства, чтобы подогнать плоскость, используя pcfitplane функция на каждой полосе. Этот гибридный подход надежно подходит к плоскости земли кусочно и обрабатывает изменения в облаке точек.

% Load point cloud
ptCloud = ptClouds{1};
% Define ROI for cropping point cloud
xLimit = [-30,30];
yLimit = [-12,12];
zLimit = [-3,15];

roi = [xLimit,yLimit,zLimit];
% Extract ground plane
[nonGround,ground] = helperExtractGround(ptCloud,roi);
figure;
pcshowpair(nonGround,ground);
legend({'\color{white} Nonground','\color{white} Ground'},'Location','northeastoutside');

Семантическая сегментация

В этом примере используется предварительно обученный PointSeg сетевая модель. PointSeg - сквозная сеть семантической сегментации в реальном времени, обученная для таких классов объектов, как легковые автомобили, грузовики и фон. Вывод из сети представляет собой маскированное изображение с каждым пикселем, помеченным в соответствии с классом. Эта маска используется для фильтрации различных типов объектов в облаке точек. Вход в сеть представляет собой пятиканальное изображение, то есть x, y, z, интенсивность и диапазон. Дополнительные сведения о сети или о том, как обучить сеть, см. в примере семантической сегментации облака точек Lidar с использованием Deep Learning Network (Lidar Toolbox).

Подготовка входных данных

helperPrepareData функция генерирует пятиканальные данные из загруженных данных облака точек.

% Load and visualize a sample frame
frame = helperPrepareData(ptCloud);
figure;
subplot(5,1,1);
imagesc(frame(:,:,1));
title('X channel');

subplot(5,1,2);
imagesc(frame(:,:,2));
title('Y channel');

subplot(5,1,3);
imagesc(frame(:,:,3));
title('Z channel');

subplot(5,1,4);
imagesc(frame(:,:,4));
title('Intensity channel');

subplot(5,1,5);
imagesc(frame(:,:,5));
title('Range channel');

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

if ~exist('net','var')
    net = pretrainedModel.net;
end

% Define classes
classes = ["background","car","truck"];

% Define color map
lidarColorMap = [
            0.98  0.98   0.00  % unknown
            0.01  0.98   0.01  % green color for car
            0.01  0.01   0.98  % blue color for motorcycle
            ];

% Run forward pass
pxdsResults = semanticseg(frame,net);

% Overlay intensity image with segmented output
segmentedImage = labeloverlay(uint8(frame(:,:,4)),pxdsResults,'Colormap',lidarColorMap,'Transparency',0.5);

% Display results
figure;
imshow(segmentedImage);
helperPixelLabelColorbar(lidarColorMap,classes);

Созданная семантическая маска используется для фильтрации облаков точек, содержащих грузовики. Аналогично, фильтровать облака точек для других классов.

truckIndices = pxdsResults == 'truck';
truckPointCloud = select(nonGround,truckIndices,'OutputSize','full');

% Crop point cloud for better display
croppedPtCloud = select(ptCloud,findPointsInROI(ptCloud,roi));
croppedTruckPtCloud = select(truckPointCloud,findPointsInROI(truckPointCloud,roi));

% Display ground and nonground points
figure;
pcshowpair(croppedPtCloud,croppedTruckPtCloud);
legend({'\color{white} Nonvehicle','\color{white} Vehicle'},'Location','northeastoutside');

Кластеризация и фитинг ограничивающей рамки

После извлечения облаков точек различных классов объектов объекты группируются с помощью евклидовой кластеризации с использованием pcsegdist (Панель инструментов компьютерного зрения). Чтобы сгруппировать все точки, принадлежащие одному кластеру, облако точек, полученное как кластер, используется в качестве начальных точек для выращивания области в некруглых точках. Используйте findNearestNeighbors(Панель инструментов компьютерного зрения) функция, чтобы закольцевать все точки для роста региона. Извлеченный кластер устанавливается в L-образную ограничивающую рамку с использованием pcfitcuboid(Панель инструментов Lidar). Эти скопления транспортных средств напоминают форму буквы L, если смотреть сверху вниз. Эта функция помогает оценить ориентацию транспортного средства. Ориентированная аппроксимация ограничительной рамки помогает оценить угол наклона объектов, что полезно в таких приложениях, как планирование путей и управление трафиком.

Кубовидные границы кластеров также можно вычислить, найдя минимальную и максимальную пространственные границы в каждом направлении. Однако этот способ не позволяет оценить ориентацию обнаруженных транспортных средств. Разница между этими двумя методами показана на рисунке.

[labels,numClusters] = pcsegdist(croppedTruckPtCloud,1);

% Define cuboid parameters
params = zeros(0,9);

for clusterIndex = 1:numClusters
    ptsInCluster = labels == clusterIndex;
        
    pc = select(croppedTruckPtCloud,ptsInCluster);
    location = pc.Location;
    
    xl = (max(location(:,1)) - min(location(:,1)));
    yl = (max(location(:,2)) - min(location(:,2)));
    zl = (max(location(:,3)) - min(location(:,3)));
    
    % Filter small bounding boxes
    if size(location,1)*size(location,2) > 20 && any(any(pc.Location)) && xl > 1 && yl > 1
        indices = zeros(0,1);
        objectPtCloud = pointCloud(location);        
        for i = 1:size(location,1)
            seedPoint = location(i,:);
            indices(end+1) = findNearestNeighbors(nonGround,seedPoint,1);
        end
        
        % Remove overlapping indices        
        indices = unique(indices);
        
        % Fit oriented bounding box
        model = pcfitcuboid(select(nonGround,indices));
        params(end+1,:) = model.Parameters;
    end
end

% Display point cloud and detected bounding box
figure;
pcshow(croppedPtCloud.Location,croppedPtCloud.Location(:,3));
showShape('cuboid',params,"Color","red","Label","Truck");

Настройка визуализации

Используйте helperLidarObjectDetectionDisplay для визуализации полного рабочего процесса в одном окне. Макет окна визуализации разделен на следующие разделы:

  1. Изображение диапазона Lidar: изображение облака точек в 2-D как изображение диапазона

  2. Сегментированное изображение: Обнаруженные метки, созданные из семантической сети сегментации, наложенные на изображение интенсивности или четвертый канал данных

  3. Обнаружение ориентированной ограничивающей рамки: 3-D облака точек с ориентированными ограничивающими рамками

  4. Вид сверху: вид сверху облака точек с ориентированными ограничивающими прямоугольниками

display = helperLidarObjectDetectionDisplay;

Закольцовывание данных

helperLidarObjectDetection класс является оболочкой, инкапсулирующей все шаги сегментации, кластеризации и подгонки ограничивающей рамки, упомянутые в вышеприведенных разделах. Используйте findDetections для извлечения обнаруженных объектов.

% Initialize lidar object detector
lidarDetector = helperLidarObjecDetector('Model',net,'XLimits',xLimit,...
    'YLimit',yLimit,'ZLimit',zLimit);

% Prepare 5-D lidar data
inputData = helperPrepareData(ptClouds);

% Set random number generator for reproducible results.
S = rng(2018);

% Initialize the display
initializeDisplay(display);

numFrames = numel(inputData);
for count = 1:numFrames
    
    % Get current data
    input = inputData{count};
    
    rangeImage = input(:,:,5);
    
    % Extact bounding boxes from lidar data
    [boundingBox,coloredPtCloud,pointLabels] = detectBbox(lidarDetector,input);
            
    % Update display with colored point cloud
    updatePointCloud(display,coloredPtCloud);
    
    % Update bounding boxes
    updateBoundingBox(display,boundingBox);
    
    % Update segmented image 
    updateSegmentedImage(display,pointLabels,rangeImage);
    
    drawnow('limitrate');
end

Отслеживание ориентированных ограничивающих рамок

В этом примере используется трекер совместной вероятностной связи данных (JPDA). Временной шаг dt устанавливается в 0,1 секунды, так как набор данных захватывается при частоте 10 Гц. Модель пространства состояний, используемая в трекере, основана на кубовидной модели с параметрами, [x, y, z, start, l, w, h]. Дополнительные сведения о том, как отслеживать ограничивающие прямоугольники в данных лидара, см. в примере «Отслеживание транспортных средств с использованием лидара: из облака точек в список дорожек». В этом примере информация о классе предоставляется с помощью ObjectAttributes имущества objectDetection object. При создании новых дорожек функция инициализации фильтра, определяется с помощью функции помощника helperMultiClassInitIMMFilter использует класс обнаружения для настройки начальных размеров объекта. Это помогает трекеру отрегулировать модель измерения ограничивающей рамки с соответствующими размерами дорожки.

Настройте объект JPDA-трекера с этими параметрами.

assignmentGate = [10 100]; % Assignment threshold;
confThreshold = [7 10];    % Confirmation threshold for history logi
delThreshold = [2 3];     % Deletion threshold for history logic
Kc = 1e-5;                 % False-alarm rate per unit volume

% IMM filter initialization function
filterInitFcn = @helperMultiClassInitIMMFilter;

% A joint probabilistic data association tracker with IMM filter
tracker = trackerJPDA('FilterInitializationFcn',filterInitFcn,...
    'TrackLogic','History',...
    'AssignmentThreshold',assignmentGate,...
    'ClutterDensity',Kc,...
    'ConfirmationThreshold',confThreshold,...
    'DeletionThreshold',delThreshold,'InitializationThreshold',0);

allTracks = struct([]);
time = 0;
dt = 0.1;

% Define Measurement Noise
measNoise = blkdiag(0.25*eye(3),25,eye(3));

numTracks = zeros(numFrames,2);

Обнаруженные объекты собираются как массив ячеек objectDetection (Automated Driving Toolbox) объекты с использованием helperAssembleDetections функция.

display = helperLidarObjectDetectionDisplay;
initializeDisplay(display);

for count = 1:numFrames
    time = time + dt;
    % Get current data
    input = inputData{count};
    
    rangeImage = input(:,:,5);
    
    % Extact bounding boxes from lidar data
    [boundingBox,coloredPtCloud,pointLabels] = detectBbox(lidarDetector,input);
    
    % Assemble bounding boxes into objectDetections
    detections = helperAssembleDetections(boundingBox,measNoise,time);
    
    % Pass detections to tracker
    if ~isempty(detections)
        % Update the tracker
         [confirmedTracks,tentativeTracks,allTracks,info] = tracker(detections,time);
         numTracks(count,1) = numel(confirmedTracks);
    end
    
    % Update display with colored point cloud
    updatePointCloud(display,coloredPtCloud);
            
    % Update segmented image 
    updateSegmentedImage(display,pointLabels,rangeImage);
    
    % Update the display if the tracks are not empty
     if ~isempty(confirmedTracks)
        updateTracks(display,confirmedTracks);
     end
     
    drawnow('limitrate');
end

Резюме

В этом примере показано, как обнаруживать и классифицировать транспортные средства, оснащенные ориентированной ограничивающей рамкой, на основе данных лидара. Также вы научились использовать фильтр IMM для отслеживания объектов с информацией о нескольких классах. Результаты семантической сегментации могут быть дополнительно улучшены путем добавления дополнительных данных обучения.

Вспомогательные функции

helperPrepareData

function multiChannelData = helperPrepareData(input)
% Create 5-channel data as x, y, z, intensity and range
% of size 64-by-1024-by-5 from pointCloud.

if isa(input, 'cell')
    numFrames = numel(input);
    multiChannelData = cell(1, numFrames);
    for i = 1:numFrames
        inputData = input{i};
        
        x = inputData.Location(:,:,1);
        y = inputData.Location(:,:,2);
        z = inputData.Location(:,:,3);
        
        intensity = inputData.Intensity;
        range = sqrt(x.^2 + y.^2 + z.^2);
        
        multiChannelData{i} = cat(3, x, y, z, intensity, range);
    end
else
    x = input.Location(:,:,1);
    y = input.Location(:,:,2);
    z = input.Location(:,:,3);
    
    intensity = input.Intensity;
    range = sqrt(x.^2 + y.^2 + z.^2);
    
    multiChannelData = cat(3, x, y, z, intensity, range);
end
end

pixelLabelColorbar

function helperPixelLabelColorbar(cmap, classNames)
% Add a colorbar to the current axis. The colorbar is formatted
% to display the class names with the color.

colormap(gca,cmap)

% Add colorbar to current figure.
c = colorbar('peer', gca);

% Use class names for tick marks.
c.TickLabels = classNames;
numClasses = size(cmap,1);

% Center tick labels.
c.Ticks = 1/(numClasses*2):1/numClasses:1;

% Remove tick mark.
c.TickLength = 0;
end

helperExtractGround

function [ptCloudNonGround,ptCloudGround] = helperExtractGround(ptCloudIn,roi)
% Crop the point cloud

idx = findPointsInROI(ptCloudIn,roi);
pc = select(ptCloudIn,idx,'OutputSize','full');

% Get the ground plane the indices using piecewise plane fitting
[ptCloudGround,idx] = piecewisePlaneFitting(pc,roi);

nonGroundIdx = true(size(pc.Location,[1,2]));
nonGroundIdx(idx) = false;
ptCloudNonGround = select(pc,nonGroundIdx,'OutputSize','full');
end


function [groundPlane,idx] = piecewisePlaneFitting(ptCloudIn,roi)
groundPtsIdx = ...
    segmentGroundFromLidarData(ptCloudIn, ...
    'ElevationAngleDelta',5,'InitialElevationAngle',15);
groundPC = select(ptCloudIn,groundPtsIdx,'OutputSize','full');

% Divide x-axis in 3 regions
segmentLength = (roi(2) - roi(1))/3;

x1 = [roi(1),roi(1) + segmentLength];
x2 = [x1(2),x1(2) + segmentLength];
x3 = [x2(2),x2(2) + segmentLength];

roi1 = [x1,roi(3:end)];
roi2 = [x2,roi(3:end)];
roi3 = [x3,roi(3:end)];

idxBack = findPointsInROI(groundPC,roi1);
idxCenter = findPointsInROI(groundPC,roi2);
idxForward = findPointsInROI(groundPC,roi3);

% Break the point clouds in front and back
ptBack = select(groundPC,idxBack,'OutputSize','full');

ptForward = select(groundPC,idxForward,'OutputSize','full');

[~,inliersForward] = planeFit(ptForward);
[~,inliersBack] = planeFit(ptBack);
idx = [inliersForward; idxCenter; inliersBack];
groundPlane = select(ptCloudIn, idx,'OutputSize','full');
end

function [plane,inlinersIdx] = planeFit(ptCloudIn)
[~,inlinersIdx, ~] = pcfitplane(ptCloudIn,1,[0, 0, 1]);
plane = select(ptCloudIn,inlinersIdx,'OutputSize','full');
end

helperAssembleDetections

function mydetections = helperAssembleDetections(bboxes,measNoise,timestamp)
% Assemble bounding boxes as cell array of objectDetection

mydetections = cell(size(bboxes,1),1);
for i = 1:size(bboxes,1)
    classid = bboxes(i,end);
    lidarModel = [bboxes(i,1:3), bboxes(i,end-1), bboxes(i,4:6)];
    % To avoid direct confirmation by the tracker, the ClassID is passed as
    % ObjectAttributes.
    mydetections{i} = objectDetection(timestamp, ...
        lidarModel','MeasurementNoise',...
        measNoise,'ObjectAttributes',struct('ClassID',classid));
end
end

helperDownloadData

function [lidarData, pretrainedModel] = helperDownloadData
outputFolder = fullfile(tempdir,'WPI');
url = 'https://ssd.mathworks.com/supportfiles/lidar/data/lidarSegmentationAndTrackingData.tar.gz';
lidarDataTarFile = fullfile(outputFolder,'lidarSegmentationAndTrackingData.tar.gz');
if ~exist(lidarDataTarFile,'file')
    mkdir(outputFolder);
    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
% Load lidar data
data = load(fullfile(outputFolder,'highwayData.mat'));
lidarData = data.ptCloudData;

% Download pretrained model
url = 'https://ssd.mathworks.com/supportfiles/lidar/data/pretrainedPointSegModel.mat';
modelFile = fullfile(outputFolder,'pretrainedPointSegModel.mat');
if ~exist(modelFile,'file')
    websave(modelFile,url);
end
pretrainedModel = load(fullfile(outputFolder,'pretrainedPointSegModel.mat'));
end

Ссылки

[1] Сяо Чжан, Венда Сюй, Чию Дун и Джон М. Долан, «Эффективный L-образный фитинг для обнаружения транспортных средств с помощью лазерных сканеров», IEEE Intelligent Vehicles Symposium, июнь 2017

[2] Я. Ван, Т. Ши, П. Юн, Л. Тай и М. Лю, «Пуантсег: семантическая сегментация в реальном времени на основе облака точек 3d-лидара», arXiv препринт arXiv:1807.06288, 2018.