В этом примере показано, как преобразовать неорганизованные облака точек в организованный формат с помощью сферической проекции.
3-D облако точек лидара обычно представлено как набор Декартовых координат (x, y, z). Облако точек может также содержать дополнительную информацию, такую как интенсивность и значения RGB. В отличие от распределения пикселей изображения, распределение лидара облака точек обычно является разреженным и нерегулярным. Обработка таких разреженных данных неэффективна. Чтобы получить компактное представление, вы проектируете лидар облаков точек на сферу, чтобы создать плотное, основанное на сетке представление, известное как организованное представление [1]. Для получения дополнительной информации о различиях между организованными и неорганизованными облаками точек см. Обзор обработки лидара. Для извлечения наземной плоскости и методов детектора ключевых точек требуются организованные облака точек. Кроме того, необходимо преобразовать облако точек в организованный формат, если необходимо использовать большинство сетей сегментации глубокого обучения, включая SqueezeSegV1, SqueezeSegV2, RangeNet + [2] и SalsaNext [3]. Пример, показывающий, как использовать глубокое обучение с организованным облаком точек, см. в Lidar Point Cloud Семантической Сегментации Использование SqueezeSegV2 Нейронной сети для глубокого обучения примера.
Чтобы преобразовать неорганизованное облако точек в организованный формат с помощью сферической проекции, необходимо задать параметры датчика лидара, используемого для создания облака точек. Определите, какие параметры задать, сославшись на таблицу данных для вашего датчика. Можно задать следующие параметры.
Строение луча - 'uniform
'или' gradient
'. Задайте 'uniform
', если интервалы между балками равны. Задайте 'gradient
'если балки в горизонте плотно упакованы, а балки в направлении к верхней и нижней частям поля зрения датчика более разнесены.
Вертикальное разрешение - Количество каналов в вертикальном направлении, то есть количество лазеров. Типичными значениями являются 32 и 64.
Вертикальные углы балки - Угловое положение каждого вертикального канала. Вы должны задать этот параметр, когда строение балки 'gradient
'.
Вертикальное поле зрения вверх - Поле зрения в вертикальном направлении над горизонтом (в степенях).
Нисходящее вертикальное поле зрения - Поле зрения в вертикальном направлении ниже горизонта (в степенях).
Разрешение по горизонтали - Количество каналов в горизонтальном направлении. Типичными значениями являются 512 и 1024.
Горизонтальное угловое разрешение - угловое разрешение между каждым каналом в горизонтальном направлении. Вы должны задать этот параметр, когда горизонтальное разрешение не упомянуто в таблице данных.
Горизонтальное поле зрения - Поле зрения, пройденное в горизонтальном направлении (в степенях). В большинстве случаев это значение составляет 360 степени.
Чтение облака точек с помощью pcread
функция.
fileName = fullfile(matlabroot,'examples','deeplearning_shared','data','ousterLidarDrivingData.pcd'); ptCloud = pcread(fileName);
Проверьте размер облака точки выборки. Если координаты облака точек в форме, M-by-N-by-3, облако точек является организованным облаком точек.
disp(size(ptCloud.Location))
64 1024 3
Преобразуйте облако точек в неорганизованный формат с помощью removeInvalidPoints
функция. Координаты неорганизованного облака точек имеют вид M-by-3.
ptCloudUnOrg = removeInvalidPoints(ptCloud); disp(size(ptCloudUnOrg.Location))
65536 3
Данные облака точек были собраны с датчика Ouster OS1 Gen1. Задайте следующие параметры, которые задаются таблицей данных устройства [4].
vResolution = 64;
hResolution = 1024;
vFOVUp = 16.6;
vFOVDown = -16.6;
hFOV = 360;
beamConfig = 'Uniform';
Вычислите углы балки в горизонтальном и вертикальном направлениях.
if strcmp(beamConfig,'Uniform') vbeamAngles = linspace(vFOVUp,vFOVDown,vResolution); end hbeamAngles = linspace(0,hFOV,hResolution);
Преобразуйте неорганизованное облако точек в организованный формат с помощью функции convertUnorgToOrg helper, определенной в конце примера.
ptCloudOrg = convertUnorgToOrg(ptCloudUnOrg,vResolution,hResolution,vbeamAngles,hbeamAngles);
Отображение канала интенсивности исходных и восстановленных организованных облаков точек.
figure
montage({uint8(ptCloud.Intensity),uint8(ptCloudOrg.Intensity)});
title("Intensity Channel of Original Point Cloud(Top) vs. Reconstructed Organized Point Cloud(Bottom)")
Отображение как исходного организованного облака точек, так и восстановленного организованного облака точек с помощью helperShowUnorgAndOrgPair
вспомогательная функция, присоединенная к этому примеру как вспомогательный файл.
display1 = helperShowUnorgAndOrgPair(); display1.plotLidarScan(ptCloudUnOrg,ptCloudOrg,3.5);
Чтение облака точек с помощью pcread
функция.
ptCloudUnOrg = pcread('HDL64LidarData.pcd');
Данные облака точек собираются с датчика HDL-64 Velodyne. Укажите следующие параметры, заданные таблицей данных устройства [5].
vResolution = 64;
hResolution = 1024;
vFOVUp = 2;
vFOVDown = -24.9;
hFOV = 360;
beamConfig = 'Uniform';
Вычислите углы балки в горизонтальном и вертикальном направлениях.
if strcmp(beamConfig,'Uniform') vbeamAngles = linspace(vFOVUp,vFOVDown,vResolution); end hbeamAngles = linspace(0,hFOV,hResolution);
Преобразуйте неорганизованное облако точек в организованный формат с помощью функции convertUnorgToOrg helper, определенной в конце примера.
ptCloudOrg = convertUnorgToOrg(ptCloudUnOrg,vResolution,hResolution,vbeamAngles,hbeamAngles);
Отображение канала интенсивности восстановленного организованного облака точек. Замените NaNs нулями и измените размер изображения для лучшей визуализации.
intensityChannel = ptCloudOrg.Intensity;
intensityChannel(isnan(intensityChannel)) = 0;
figure
intensityChannel = imresize(intensityChannel,'Scale',[3 1]);
imshow(intensityChannel);
Отображение как исходного организованного облака точек, так и восстановленного организованного облака точек с помощью helperShowUnorgAndOrgPair
вспомогательная функция, присоединенная к этому примеру как вспомогательный файл.
display2 = helperShowUnorgAndOrgPair(); display2.plotLidarScan(ptCloudUnOrg,ptCloudOrg,2.5);
Чтение облака точек с помощью pcread
функция. Облако точек получено из [6].
ptCloudUnOrg = pcread('Pandar64LidarData.pcd');
Данные облака точек собираются с помощью датчика Pandar-64. Задайте следующие параметры, которые задаются таблицей данных устройства [7].
vResolution = 64;
hAngResolution = 0.2;
hFOV = 360;
beamConfig = 'gradient';
Конфигурация луча 'gradient
', что означает, что интервал между лучами неоднороден. Задайте значения угла балки вдоль вертикального направления, заданные таблицей данных.
vbeamAngles = [15.0000 11.0000 8.0000 5.0000 3.0000 2.0000 1.8333 1.6667 1.5000 1.3333 1.1667 1.0000 0.8333 0.6667 ... 0.5000 0.3333 0.1667 0 -0.1667 -0.3333 -0.5000 -0.6667 -0.8333 -1.0000 -1.1667 -1.3333 -1.5000 -1.6667 ... -1.8333 -2.0000 -2.1667 -2.3333 -2.5000 -2.6667 -2.8333 -3.0000 -3.1667 -3.3333 -3.5000 -3.6667 -3.8333 -4.0000 ... -4.1667 -4.3333 -4.5000 -4.6667 -4.8333 -5.0000 -5.1667 -5.3333 -5.5000 -5.6667 -5.8333 -6.0000 -7.0000 -8.0000 ... -9.0000 -10.0000 -11.0000 -12.0000 -13.0000 -14.0000 -19.0000 -25.0000];
Вычислите углы горизонтальной балки.
hResolution = round(360/hAngResolution); hbeamAngles = linspace(0,hFOV,hResolution);
Преобразуйте неорганизованное облако точек в организованный формат с помощью функции convertUnorgToOrg helper, определенной в конце примера.
ptCloudOrg = convertUnorgToOrg(ptCloudUnOrg,vResolution,hResolution,vbeamAngles,hbeamAngles);
Отображение канала интенсивности восстановленного организованного облака точек. Замените NaNs нулями и измените размер изображения. Использование histeq
для улучшения визуализации.
intensityChannel = ptCloudOrg.Intensity;
intensityChannel(isnan(intensityChannel)) = 0;
figure
intensityChannel = imresize(intensityChannel,'Scale',[3 1]);
histeq(intensityChannel./max(intensityChannel(:)));
Отображение как исходного организованного облака точек, так и восстановленного организованного облака точек с помощью helperShowUnorgAndOrgPair
вспомогательная функция, присоединенная к этому примеру как вспомогательный файл.
display3 = helperShowUnorgAndOrgPair(); display3.plotLidarScan(ptCloudUnOrg,ptCloudOrg,4);
Используйте convertUnorgToOrg
функция для поиска пиксельных координат проекционного изображения для всех (x, y, z) точек. Функция следует этим шагам.
Вычислите угол тангажа и углы рыскания для каждой точки облака точек.
Вычислите индексы строк и столбцов для каждой точки на основе углов балки, тангажа и рыскания.
Создайте организованное облако точек на основе индексов строка и столбец.
function ptCloudOrganized = convertUnorgToOrg(ptCloud,vResolution,hResolution,vbeamAngles,hbeamAngles) locations = ptCloud.Location; if ~isempty(ptCloud.Intensity) intensity = ptCloud.Intensity; else intensity = zeros(size(ptCloud.Location,1),1); end % Calculate the radial distance for every point. r = sqrt(locations(:,1).^2 + locations(:,2).^2); r(r==0) = 1e-6; % Calculate the pitch and yaw angles for each point in the point cloud. pitch = atan2d(locations(:,3),r); yaw = atan2d(locations(:,2),locations(:,1)); % Shift the range of the yaw angle from [-pi,pi] to [0,2*pi]. yaw = 180-yaw; % Calculate the row indices for all points based on the bin in which the pitch angle for each point falls into. [~,~,rowIdx] = histcounts(pitch,flip(vbeamAngles)); rowIdx(rowIdx == 0) = NaN; rowIdx = vResolution - rowIdx; % Calculate the column indices for all points based on the bin in which the yaw angle for each point falls into. [~,~,colIdx] = histcounts(yaw,hbeamAngles); colIdx(colIdx == 0) = NaN; % Create a pseudo image and fill in the values with the corresponding location and intensity values. pseduoImage = NaN(vResolution,hResolution,4); for i = 1:size(locations,1) if ~isnan(rowIdx(i,1)) && ~isnan(colIdx(i,1)) pseduoImage(rowIdx(i,1),colIdx(i,1),1) = locations(i,1); pseduoImage(rowIdx(i,1),colIdx(i,1),2) = locations(i,2); pseduoImage(rowIdx(i,1),colIdx(i,1),3) = locations(i,3); pseduoImage(rowIdx(i,1),colIdx(i,1),4) = intensity(i,1); end end % Create a point cloud object from the locations and intensity. if ~isempty(ptCloud.Intensity) ptCloudOrganized = pointCloud(pseduoImage(:,:,1:3), 'Intensity', pseduoImage(:,:,4)); else ptCloudOrganized = pointCloud(pseduoImage(:,:,1:3)); end end
[1] Wu, Bichen, Alvin Wan, Xiangyu Yue, and Kurt Keutzer. SqueezeSeg: сверточные нейронные сети с повторяющейся CRF для сегментации дорожного объекта в реальном времени из облака точек 3D LiDAR ". В 2018 году IEEE International Conference on Robotics and Automation (ICRA), 1887-93. Брисбен, QLD: IEEE, 2018. https://doi.org/10.1109/ICRA.2018.8462926.
[2] Милиото, Андрес, Игнасио Виццо, Йенс Бехли и Сайрилл Стахнисс. RangeNet++: быстрая и точная семантическая сегментация лИДАР. В 2019 году IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS), 4213-20. Макао, Китай: IEEE, 2019. https://doi.org/10.1109/IROS40897.2019.8967762.
[3] Кортинхал, Тиаго, Джордж Целепис и Эрен Эрдал Аксой. SalsaNext: быстрая семантическая сегментация облаков точек лИДАР для автономного управления автомобилем с учетом неопределенности. ArXiv:2003.03653 [Cs], 9 июля 2020 года. https://arxiv.org/abs/2003.03653.
[4] Ким, Джейден. «UCS - Ouster LiDAR». Доступ к 22 декабря 2020 года. https://data.ouster.io/downloads/datasheets/datasheet-gen1-v1p13-os1.pdf.
[5] Велодин Лидар. HDL-64E Durable Surround Lidar Sensor (неопр.) (недоступная ссылка). Доступ к 22 декабря 2020 года. https://velodynelidar.com/products/hdl-64e/.
[6] «PandaSet Open Datasets - шкала». Доступ к 22 декабря 2020 года. https://scale.com/open-datasets/pandaset.
[7] «Pandar64 руководство пользователя». Доступ к 22 декабря 2020 года. https://hesaiweb2019.blob.core.chinacloudapi.cn/uploads/Pandar64_User's_Manual.pdf.