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

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

Обзор

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

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

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

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

  • Ориентированный ограничивающий прямоугольник подбора кривой

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

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

Загрузка данных

Датчик лидара генерирует данные облака точек либо в организованном формате, либо в неорганизованном формате. Данные, используемые в этом примере, собираются с использованием датчика Ouster OS1 lidar. Этот лидар создает организованное облако точек с 64 горизонтальными линиями скана. Данные облака точек состоят из трех каналов, представляющих координаты x, y и z точек. Каждый канал имеет размер 64 на 1024. Используйте функцию helper 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 Используя PointSeg Нейронной сети для глубокого обучения пример.

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

The 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 функция. Эти кластеры транспортных средств напоминают форму буквы 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");

Способы визуализации Setup

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

  1. Lidar Range Image: изображение облака точек в 2-D как изображение области значений

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

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

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

display = helperLidarObjectDetectionDisplay;

Цикл через данные

The 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,ϕ,l,w,h]. Для получения дополнительной информации о том, как отслеживать ограничительные рамки в данных лидара, смотрите пример Track Vehicles Using Lidar: From Point Cloud to Track List (Sensor Fusion and Tracking Toolbox). В этом примере информация о классе предоставляется с помощью ObjectAttributes свойство objectDetection object. При создании новых треков функция инициализации фильтра ,задается с помощью функции helper 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] Xiao Zhang, Wenda Xu, Chiyu Dong и John M. Dolan, «Effective L-Shape Fitting for Vehicle Detection Using Laser Scanners», IEEE Intelligent Vehicles Symposium, июнь 2017

[2] Y. Wang, T. Shi, P. Yun, L. Tai, and M. Liu, «Pointseg: Real-time semantic segmentation based on 3d lidar облако точек», arXiv preprint arXiv:1807.06288, 2018.