В этом примере показано, как оценить жесткое преобразование между 3-D лидаром и камерой. В конце этого примера можно использовать жесткую матрицу преобразования для предохранения данных лидара и камеры.
На этой диаграмме описывается процесс калибровки лидара и камеры (LCC).

Датчики Lidar и камеры являются наиболее распространенными датчиками зрения в приложениях автономного вождения. Камеры предоставляют богатую цветовую информацию и другие возможности, которые можно использовать для извлечения различных характеристик обнаруженных объектов. С другой стороны, датчики Lidar обеспечивают точное 3-D расположение и структуру объектов. Чтобы улучшить конвейер обнаружения и классификации объектов, данные этих двух датчиков могут быть слиты вместе для получения более подробной и точной информации об объектах.
Матрица преобразования в виде ориентации и относительных положений между двумя датчиками является предшественником данных сплавления от этих двух датчиков. Калибровка камеры лидара помогает в оценке матрицы преобразования между 3D лидаром и камерой, установленной на автономном транспортном средстве. В этом примере используются данные двух разных лидарных датчиков, HDL64 и VLP16. HDL64 данные собираются из среды Gazebo, как показано на этом рисунке.

Данные регистрируются в виде набора изображений PNG и соответствующих облаков точек PCD. В этом примере предполагается, что внутренние параметры камеры известны. Дополнительные сведения о извлечении внутренних параметров камеры см. в разделе Калибровка одной камеры.
Загрузите данные датчика Velodyne HDL-64 из беседки.
imagePath = fullfile(toolboxdir('lidar'), 'lidardata', 'lcc', 'HDL64', 'images'); ptCloudPath = fullfile(toolboxdir('lidar'), 'lidardata', 'lcc', 'HDL64', 'pointCloud'); cameraParamsPath = fullfile(imagePath, 'calibration.mat'); intrinsic = load(cameraParamsPath); % Load camera intrinsics imds = imageDatastore(imagePath); % Load images using imageDatastore pcds = fileDatastore(ptCloudPath, 'ReadFcn', @pcread); % Load point cloud files imageFileNames = imds.Files; ptCloudFileNames = pcds.Files; squareSize = 200; % Square size of the checkerboard % Set random seed to generate reproducible results. rng('default');
В этом примере в качестве функции сравнения используется шахматный шаблон. Края шашки оцениваются с помощью датчиков лидара и камеры. Использовать estimateCheckerboardCorners3d для вычисления координат углов шашки и размера фактической шашки в мм. Углы оцениваются в 3-D относительно системы координат камеры. Дополнительные сведения о системах координат камеры см. в разделе Системы координат на панели инструментов Lidar
[imageCorners3d, checkerboardDimension, dataUsed] = ... estimateCheckerboardCorners3d(imageFileNames, intrinsic.cameraParams, squareSize); imageFileNames = imageFileNames(dataUsed); % Remove image files that are not used
Результаты можно визуализировать с помощью функции помощника helperShowImageCorners.
% Display Checkerboard corners
helperShowImageCorners(imageCorners3d, imageFileNames, intrinsic.cameraParams);
Аналогично, использовать detectRectangularPlanePoints функция обнаружения шахматной доски в данных лидара. Функция обнаруживает прямоугольные объекты в облаке точек на основе входных размеров. В этом случае он обнаруживает шахматную доску, используя размеры доски, рассчитанные в предыдущем разделе.
% Extract ROI from the detected image corners roi = helperComputeROI(imageCorners3d, 5); % Filter point cloud files corresponding to the detected images ptCloudFileNames = ptCloudFileNames(dataUsed); [lidarCheckerboardPlanes, framesUsed, indices] = ... detectRectangularPlanePoints(ptCloudFileNames, checkerboardDimension, 'ROI', roi); % Remove ptCloud files that are not used ptCloudFileNames = ptCloudFileNames(framesUsed); % Remove image files imageFileNames = imageFileNames(framesUsed); % Remove 3D corners from images imageCorners3d = imageCorners3d(:, :, framesUsed);
Для визуализации обнаруженной шахматной доски используйте helperShowCheckerboardPlanes функция.
helperShowCheckerboardPlanes(ptCloudFileNames, indices);

Использовать estimateLidarCameraTransform to оценить жесткую матрицу преобразования между лидаром и камерой.
[tform, errors] = estimateLidarCameraTransform(lidarCheckerboardPlanes, ... imageCorners3d, 'CameraIntrinsic', intrinsic.cameraParams);
После завершения калибровки можно использовать калибровочную матрицу двумя способами:
Проецировать облако точек Lidar на изображение.
Улучшение облака точек Лидара с помощью цветовой информации из изображения.
Использовать helperFuseLidarCamera function для визуализации лидара и данных изображения, слитых вместе.
helperFuseLidarCamera(imageFileNames, ptCloudFileNames, indices, ...
intrinsic.cameraParams, tform);
Для оценки точности калибровки определены три типа ошибок:
Ошибка перевода: Среднее значение разницы между центроидом шашечных углов в лидаре и проецированными углами в 3-D от изображения.
Ошибка вращения: среднее значение разницы между нормалями шашечной доски в облаке точек и проецированными углами в 3-D от изображения.
Ошибка репроекции: среднее значение разницы между центроидом углов изображения и проецированными углами лидара на изображении.
Постройте график расчетных значений ошибок с помощью helperSunError.
helperShowError(errors)

После калибровки проверьте данные с высокими ошибками калибровки и повторно запустите калибровку.
outlierIdx = errors.RotationError < mean(errors.RotationError); [newTform, newErrors] = estimateLidarCameraTransform(lidarCheckerboardPlanes(outlierIdx), ... imageCorners3d(:, :, outlierIdx), 'CameraIntrinsic', intrinsic.cameraParams); helperShowError(newErrors);

Проверьте технологический процесс LCC на фактических данных о Лидаре VLP-16, чтобы оценить его работу.
clear; imagePath = fullfile(toolboxdir('lidar'), 'lidardata', 'lcc', 'vlp16', 'images'); ptCloudPath = fullfile(toolboxdir('lidar'), 'lidardata', 'lcc', 'vlp16', 'pointCloud'); cameraParamsPath = fullfile(imagePath, 'calibration.mat'); intrinsic = load(cameraParamsPath); % Load camera intrinscs imds = imageDatastore(imagePath); % Load images using imageDatastore pcds = fileDatastore(ptCloudPath, 'ReadFcn', @pcread); % Loadr point cloud files imageFileNames = imds.Files; ptCloudFileNames = pcds.Files; squareSize = 81; % Square size of the checkerboard % Set random seed to generate reproducible results. rng('default'); % Extract Checkerboard corners from the images [imageCorners3d, checkerboardDimension, dataUsed] = ... estimateCheckerboardCorners3d(imageFileNames, intrinsic.cameraParams, squareSize); imageFileNames = imageFileNames(dataUsed); % Remove image files that are not used % Filter point cloud files corresponding to the detected images ptCloudFileNames = ptCloudFileNames(dataUsed); % Extract ROI from the detected image corners roi = helperComputeROI(imageCorners3d, 5); %Extract Checkerboard in lidar data [lidarCheckerboardPlanes, framesUsed, indices] = detectRectangularPlanePoints(... ptCloudFileNames, checkerboardDimension, 'RemoveGround', true, 'ROI', roi); imageCorners3d = imageCorners3d(:, :, framesUsed); % Remove ptCloud files that are not used ptCloudFileNames = ptCloudFileNames(framesUsed); % Remove image files imageFileNames = imageFileNames(framesUsed); [tform, errors] = estimateLidarCameraTransform(lidarCheckerboardPlanes, ... imageCorners3d, 'CameraIntrinsic', intrinsic.cameraParams); helperFuseLidarCamera(imageFileNames, ptCloudFileNames, indices,... intrinsic.cameraParams, tform);

% Plot the estimated error values
helperShowError(errors);
В этом примере представлен обзор начала процесса калибровки лидарной камеры для извлечения жесткого преобразования между двумя датчиками. В этом примере также показано, как использовать жесткую матрицу преобразования для сплавления данных лидара и камеры.
[1] Липу Чжоу и Цимо Ли и Майкл Кэсс, "Автоматическая внешняя калибровка камеры и 3D LiDAR с использованием линейных и плоских соответствий", "IEEE/RSJ Intl. Conf. on Intelligent Robots and Systems, IROS ", Окт, 2018.
[2] К. С. Арун, Т. С. Хуан и С. Д. Blostein, «Установка методом наименьших квадратов двух наборов точек 3-D», IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. PAMI-9, no. 5, pp. 698-700, Sept 1987.