PointPillars 딥러닝을 사용한 라이다 3차원 객체 검출
이 예제에서는 PointPillars 딥러닝 신경망을 사용하여 라이다에서 객체를 검출하는 방법을 보여줍니다[1]. 이 예제에서는 다음을 수행합니다.
PointPillars 객체 검출 신경망의 훈련과 테스트를 위한 데이터셋을 구성합니다. 또한 신경망 효율성을 향상하기 위해 훈련 데이터셋에 대한 데이터 증강을 수행합니다.
PointPillars 객체 검출 신경망을 훈련하기 위해 앵커 상자를 훈련 데이터로부터 계산합니다.
pointPillarsObjectDetector
함수를 사용하여 PointPillars 객체 검출기를 만들고trainPointPillarsObjectDetector
함수를 사용하여 검출기를 훈련시킵니다.
이 예제에서는 포인트 클라우드에서 객체를 검출하는 데 사용할 사전 훈련된 PointPillars 객체 검출기도 제공됩니다. 사전 훈련된 모델은 Pandaset 데이터 세트로 훈련된 상태입니다. PointPillars 객체 검출 신경망에 대한 자세한 내용은 Get Started with PointPillars 항목을 참조하십시오.
라이다 데이터 세트 다운로드하기
PandaSet 데이터 세트에서 센서 데이터의 일부가 포함된 ZIP 파일(약 5.2GB 크기)을 다운로드합니다[2]. 다운로드한 후 파일의 압축을 풉니다. 이 파일에는 두 개의 메인 폴더인 Lidar
와 Cuboids
가 있으며, 여기에는 다음의 데이터가 포함되어 있습니다.
PointCloud 폴더에는 에고 차량이 양의 y축을 따라 움직이도록 배열된 PCD 형식의 전처리된 정렬 포인트 클라우드 2560개가 포함되어 있습니다. 포인트 클라우드가 이 방향에서 벗어나는 경우
pctransform
함수를 활용하여 필요한 변환을 적용할 수 있습니다.Cuboid
폴더에는 대응하는 ground truth 데이터가 테이블 형식으로 포함되어 있습니다. 이는PandasetLidarGroundTruth.mat
파일에 저장되어 있습니다. 이 파일은 자동차, 트럭, 보행자라는 세 가지 범주에 대한 3차원 경계 상자 정보를 제공합니다. 포인트 클라우드에 적용된 모든 변환은bboxwarp
함수를 사용하여 경계 상자에 적용해야 합니다.
이 예제의 끝부분에 정의된 helperDownloadPandasetData
헬퍼 함수를 사용하여, 주어진 URL에서 Pandaset 데이터셋을 다운로드합니다.
outputFolder = fullfile(tempdir,'Pandaset'); lidarURL = ['https://ssd.mathworks.com/supportfiles/lidar/data/' ... 'Pandaset_LidarData.tar.gz']; helperDownloadPandasetData(outputFolder,lidarURL);
인터넷 연결에 따라 다운로드가 완료되기까지 얼마간의 시간이 걸릴 수 있습니다. 다운로드 처리가 완료될 때까지 코드는 MATLAB® 실행을 일시 중단합니다. 또는 웹 브라우저를 사용하여 로컬 디스크에 데이터 세트를 다운로드하고 파일을 추출할 수도 있습니다. 이렇게 하려면 코드에서 outputFolder
변수를 다운로드한 파일의 위치로 변경하십시오.
데이터 세트 불러오기
pcread
함수를 사용하여 지정된 경로로부터 PCD 파일을 불러올 파일 데이터저장소를 만듭니다.
path = fullfile(outputFolder,'Lidar'); lidarData = fileDatastore(path,'ReadFcn',@(x) pcread(x));
자동차 객체와 트럭 객체의 3차원 경계 상자 레이블을 불러옵니다.
gtPath = fullfile(outputFolder,'Cuboids','PandaSetLidarGroundTruth.mat'); data = load(gtPath,'lidarGtLabels'); Labels = timetable2table(data.lidarGtLabels); boxLabels = Labels(:,2:3);
전체 뷰 포인트 클라우드를 표시합니다.
figure ptCld = preview(lidarData); ax = pcshow(ptCld.Location); set(ax,'XLim',[-50 50],'YLim',[-40 40]); zoom(ax,2.5); axis off;
데이터 전처리하기
PandaSet 데이터는 전체 뷰 포인트 클라우드로 구성됩니다. 이 예제의 경우 표준 파라미터를 사용하여 전체 뷰 포인트 클라우드를 정면 뷰 포인트 클라우드로 자릅니다[1]. 이러한 파라미터는 신경망에 전달되는 입력의 크기를 결정합니다. x축, y축, z축을 따라 더 작은 포인트 클라우드 범위를 선택하여 원점에 더 가까운 객체를 검출합니다. 이렇게 하면 신경망의 전체 훈련 시간도 단축됩니다.
xMin = 0.0; % Minimum value along X-axis. yMin = -39.68; % Minimum value along Y-axis. zMin = -5.0; % Minimum value along Z-axis. xMax = 69.12; % Maximum value along X-axis. yMax = 39.68; % Maximum value along Y-axis. zMax = 5.0; % Maximum value along Z-axis. xStep = 0.16; % Resolution along X-axis. yStep = 0.16; % Resolution along Y-axis. % Define point cloud parameters. pointCloudRange = [xMin xMax yMin yMax zMin zMax]; voxelSize = [xStep yStep];
이 예제에 지원 파일로 첨부된 cropFrontViewFromLidarData
헬퍼 함수를 사용하여 다음을 수행합니다.
입력 전체 뷰 포인트 클라우드에서 정면 뷰를 자릅니다.
gridParams
로 지정된 ROI 내에 있는 상자 레이블을 선택합니다.
[croppedPointCloudObj,processedLabels] = cropFrontViewFromLidarData(...
lidarData,boxLabels,pointCloudRange);
Processing data 100% complete
잘라낸 포인트 클라우드와 ground truth 상자 레이블을 표시합니다.
pc = croppedPointCloudObj{1,1}; bboxes = [processedLabels.Car{1};processedLabels.Truck{1}]; ax = pcshow(pc); showShape('cuboid',bboxes,'Parent',ax,'Opacity',0.1,... 'Color','green','LineWidth',0.5);
reset(lidarData);
Datastore 객체 만들기
데이터 세트를 훈련 세트와 테스트 세트로 나눕니다. 데이터의 70%를 신경망 훈련용으로, 나머지는 평가용으로 선택합니다.
rng(1); shuffledIndices = randperm(size(processedLabels,1)); idx = floor(0.7 * length(shuffledIndices)); trainData = croppedPointCloudObj(shuffledIndices(1:idx),:); testData = croppedPointCloudObj(shuffledIndices(idx+1:end),:); trainLabels = processedLabels(shuffledIndices(1:idx),:); testLabels = processedLabels(shuffledIndices(idx+1:end),:);
데이터저장소에 쉽게 액세스할 수 있도록 이 예제에 지원 파일로 첨부된 saveptCldToPCD
헬퍼 함수를 사용하여 훈련 데이터를 PCD 파일로 저장합니다. 훈련 데이터가 폴더에 저장되어 있고 pcread
함수에서 지원되는 경우 writeFiles
를 "false"
로 설정할 수 있습니다.
writeFiles = true; dataLocation = fullfile(outputFolder,'InputData'); [trainData,trainLabels] = saveptCldToPCD(trainData,trainLabels,... dataLocation,writeFiles);
Processing data 100% complete
fileDatastore
를 사용하여 파일 데이터저장소를 만들고 pcread
함수를 사용하여 PCD 파일을 불러옵니다.
lds = fileDatastore(dataLocation,'ReadFcn',@(x) pcread(x));
3차원 경계 상자 레이블을 불러오기 위해 boxLabelDatastore
를 사용하여 상자 레이블 데이터저장소를 만듭니다.
bds = boxLabelDatastore(trainLabels);
combine
함수를 사용하여 포인트 클라우드와 3차원 경계 상자 레이블을 하나의 훈련용 데이터저장소로 결합합니다.
cds = combine(lds,bds);
데이터 증강 수행하기
이 예제에서는 ground truth 데이터 증강과 다른 전역 데이터 증강 기법을 사용하여 훈련 데이터와 대응하는 상자를 더 다양하게 만듭니다. 라이더 데이터를 사용한 3차원 객체 검출 워크플로에 사용되는 일반적인 데이터 증강 기법에 대한 자세한 내용은 Data Augmentations for Lidar Object Detection Using Deep Learning 항목을 참조하십시오.
이 예제의 끝부분에 정의된 helperShowPointCloudWith3DBoxes
헬퍼 함수를 사용하여 증강 전에 포인트 클라우드를 읽어오고 표시합니다.
augData = preview(cds); [ptCld,bboxes,labels] = deal(augData{1},augData{2},augData{3}); % Define the classes for object detection. classNames = {'Car','Truck'}; % Define colors for each class to plot bounding boxes. colors = {'green','magenta'}; helperShowPointCloudWith3DBoxes(ptCld,bboxes,labels,classNames,colors)
sampleLidarData
함수를 사용하여 훈련 데이터에서 3차원 경계 상자와 해당 대응점을 샘플링합니다.
sampleLocation = fullfile(outputFolder,'GTsamples'); [ldsSampled,bdsSampled] = sampleLidarData(cds,classNames,'MinPoints',20,... 'Verbose',false,'WriteLocation',sampleLocation); cdsSampled = combine(ldsSampled,bdsSampled);
pcBboxOversample
함수를 사용하여 고정된 수의 자동차 클래스 객체와 트럭 클래스 객체를 모든 포인트 클라우드에 무작위로 추가합니다. transform
함수를 사용하여 ground truth와 사용자 지정 데이터 증강을 훈련 데이터에 적용합니다.
numObjects = [10 10]; cdsAugmented = transform(cds,@(x)pcBboxOversample(x,cdsSampled,classNames,numObjects));
이 예제의 끝부분에 정의된 helperAugmentLidarData
헬퍼 함수를 사용하여 다음과 같은 추가 데이터 증강 기법을 모든 포인트 클라우드에 적용합니다.
5% 무작위 스케일링
[-pi/4, pi/4]에서 z축을 따라 무작위 회전
x축, y축, z축을 따라 각각 [0.2, 0.2, 0.1]미터씩 무작위 평행 이동
cdsAugmented = transform(cdsAugmented,@(x)helperAugmentData(x));
이 예제의 끝부분에 정의된 helperShowPointCloudWith3DBoxes
헬퍼 함수를 사용하여 ground truth 증강된 상자와 함께 증강된 포인트 클라우드를 표시합니다.
augData = preview(cdsAugmented); [ptCld,bboxes,labels] = deal(augData{1},augData{2},augData{3}); helperShowPointCloudWith3DBoxes(ptCld,bboxes,labels,classNames,colors)
PointPillars 객체 검출기 만들기
pointPillarsObjectDetector
함수를 사용하여 PointPillars 객체 검출 신경망을 만들 수 있습니다. PointPillars 신경망에 대한 자세한 내용은 Get Started with PointPillars 항목을 참조하십시오.
이 다이어그램은 PointPillars 객체 검출기의 신경망 아키텍처를 보여줍니다. 심층 신경망 디자이너 (Deep Learning Toolbox) 앱을 사용하여 PointPillars 신경망을 만들 수 있습니다.
이 예제에 지원 파일로 첨부된 calculateAnchorsPointPillars
헬퍼 함수를 사용하여 훈련 데이터를 기반으로 앵커 상자를 추정합니다.
anchorBoxes = calculateAnchorsPointPillars(trainLabels);
PointPillars 검출기를 정의합니다.
detector = pointPillarsObjectDetector(pointCloudRange,classNames,anchorBoxes,... 'VoxelSize',voxelSize);
훈련 옵션 지정하기
trainingOptions
(Deep Learning Toolbox) 함수를 사용하여 신경망 훈련 파라미터를 지정합니다. 훈련이 중단된 경우 저장된 검사 지점에서 훈련을 재개할 수 있습니다.
CPU 또는 GPU를 사용하여 검출기를 훈련시킵니다. GPU를 사용하려면 Parallel Computing Toolbox™와 CUDA® 지원 NVIDIA® GPU가 필요합니다. 자세한 내용은 GPU 연산 요구 사항 (Parallel Computing Toolbox) 항목을 참조하십시오. 사용 가능한 GPU가 있는지 자동으로 감지하려면 executionEnvironment
를 "auto"
로 설정합니다. GPU가 없거나 훈련에 GPU를 사용하지 않으려면 executionEnvironment
를 "cpu"
로 설정합니다. GPU를 훈련에 사용하려면 executionEnvironment
를 "gpu"
로 설정합니다.
executionEnvironment = "auto"; options = trainingOptions('adam',... Plots = "training-progress",... MaxEpochs = 60,... MiniBatchSize = 3,... GradientDecayFactor = 0.9,... SquaredGradientDecayFactor = 0.999,... LearnRateSchedule = "piecewise",... InitialLearnRate = 0.0002,... LearnRateDropPeriod = 15,... LearnRateDropFactor = 0.8,... ExecutionEnvironment= executionEnvironment, ... PreprocessingEnvironment = 'parallel',... BatchNormalizationStatistics = 'moving',... ResetInputNormalization = false,... CheckpointFrequency = 10, ... CheckpointFrequencyUnit = 'epoch', ... CheckpointPath = userpath);
PointPillars 객체 검출기 훈련시키기
doTraining
이 "true"인 경우 trainPointPillarsObjectDetector
함수를 사용하여 PointPillars 객체 검출기를 훈련시킵니다. 또는 사전 훈련된 검출기를 불러옵니다.
doTraining = false; if doTraining [detector,info] = trainPointPillarsObjectDetector(cdsAugmented,detector,options); else pretrainedDetector = load('pretrainedPointPillarsDetector.mat','detector'); detector = pretrainedDetector.detector; end
참고: 사전 훈련된 신경망 pretrainedPointPillarsDetector.mat
은 에고 차량 방향이 양의 y축을 따르는 상황에서 Pandar 64 센서에 의해 캡처된 포인트 클라우드 데이터를 기반으로 훈련된 상태입니다.
사용자 지정 데이터셋에 대해 이 사전 훈련된 신경망을 사용하여 정확한 검출을 생성하려면 다음을 수행합니다.
에고 차량이 양의 y축을 따라 이동하도록 포인트 클라우드 데이터를 변환합니다.
pcorganize
함수를 사용하여 Pandar 64 파라미터로 데이터를 재구성합니다.
검출 생성하기
훈련된 신경망을 사용하여 테스트 데이터의 객체를 검출합니다.
테스트 데이터에서 포인트 클라우드를 읽어옵니다.
테스트 포인트 클라우드를 대상으로 검출기를 실행하여 예측된 경계 상자와 신뢰 점수를 구합니다.
이 예제의 끝부분에 정의된
helperDisplay3DBoxesOverlaidPointCloud
헬퍼 함수를 사용하여 경계 상자와 함께 포인트 클라우드를 표시합니다.
ptCloud = testData{1,1}; % Run the detector on the test point cloud. [bboxes,score,labels] = detect(detector,ptCloud); % Display the predictions on the point cloud. helperShowPointCloudWith3DBoxes(ptCloud,bboxes,labels,classNames,colors)
테스트 세트를 사용하여 검출기 평가하기
훈련된 객체 검출기를 대규모 포인트 클라우드 데이터 세트를 대상으로 평가하여 성능을 측정합니다.
numInputs = 50; % Generate rotated rectangles from the cuboid labels. bds = boxLabelDatastore(testLabels(1:numInputs,:)); groundTruthData = transform(bds,@(x)createRotRect(x)); detectionResults = detect(detector,testData(1:numInputs,:),... 'Threshold',0.25); % Convert the bounding boxes to rotated rectangles format and calculate % the evaluation metrics. for i = 1:height(detectionResults) box = detectionResults.Boxes{i}; detectionResults.Boxes{i} = box(:,[1,2,4,5,9]); detectionResults.Labels{i} = detectionResults.Labels{i}'; end % Evaluate the object detector using average orietation similarity metric metrics = evaluateObjectDetection(detectionResults,groundTruthData,"AdditionalMetrics","AOS"); [datasetSummary,classSummary] = summarize(metrics)
datasetSummary=1×5 table
NumObjects mAPOverlapAvg mAP0.5 mAOSOverlapAvg mAOS0.5
__________ _____________ _______ ______________ _______
511 0.70556 0.70556 0.68208 0.68208
classSummary=2×5 table
NumObjects APOverlapAvg AP0.5 AOSOverlapAvg AOS0.5
__________ ____________ _______ _____________ _______
Car 480 0.76271 0.76271 0.74664 0.74664
Truck 31 0.64841 0.64841 0.61751 0.61751
지원 함수
helperDownloadPandasetData
함수는 Pandaset 데이터를 다운로드합니다.
function helperDownloadPandasetData(outputFolder,lidarURL) % Download the data set from the given URL to the output folder. lidarDataTarFile = fullfile(outputFolder,'Pandaset_LidarData.tar.gz'); if ~exist(lidarDataTarFile,'file') mkdir(outputFolder); disp('Downloading PandaSet Lidar driving data (5.2 GB)...'); websave(lidarDataTarFile,lidarURL); untar(lidarDataTarFile,outputFolder); end % Extract the file. if (~exist(fullfile(outputFolder,'Lidar'),'dir'))... &&(~exist(fullfile(outputFolder,'Cuboids'),'dir')) untar(lidarDataTarFile,outputFolder); end end
helperShowPointCloudWith3DBoxes
함수는 포인트 클라우드를 해당되는 경계 상자와 함께 표시하고, 각 클래스에 다른 색상을 사용하여 쉽게 구분할 수 있도록 합니다.
function helperShowPointCloudWith3DBoxes(ptCld,bboxes,labels,classNames,colors) % Validate the length of classNames and colors are the same assert(numel(classNames) == numel(colors), 'ClassNames and Colors must have the same number of elements.'); % Get unique categories from labels uniqueCategories = categories(labels); % Create a mapping from category to color colorMap = containers.Map(uniqueCategories, colors); labelColor = cell(size(labels)); % Populate labelColor based on the mapping for i = 1:length(labels) labelColor{i} = colorMap(char(labels(i))); end figure; ax = pcshow(ptCld); showShape('cuboid', bboxes, 'Parent', ax, 'Opacity', 0.1, ... 'Color', labelColor, 'LineWidth', 0.5); zoom(ax,1.5); end
helperAugmentData
함수는 데이터에 다음과 같은 증강을 적용합니다.
5% 무작위 스케일링.
[-pi/4, pi/4]에서 z축을 따라 무작위 회전.
x, y, z축을 따라 각각 [0.2, 0.2, 0.1]미터씩 무작위 평행 이동.
function data = helperAugmentData(data) % Apply random scaling, rotation and translation. pc = data{1}; minAngle = -45; maxAngle = 45; % Define outputView based on the grid-size and XYZ limits. outView = imref3d([32,32,32],[-100,100],... [-100,100],[-100,100]); theta = minAngle + rand(1,1)*(maxAngle - minAngle); tform = randomAffine3d('Rotation',@() deal([0,0,1],theta),... 'Scale',[0.95,1.05],... 'XTranslation',[0,0.2],... 'YTranslation',[0,0.2],... 'ZTranslation',[0,0.1]); % Apply the transformation to the point cloud. ptCloudTransformed = pctransform(pc,tform); % Apply the same transformation to the boxes. bbox = data{2}; [bbox,indices] = bboxwarp(bbox,tform,outView); if ~isempty(indices) data{1} = ptCloudTransformed; data{2} = bbox; data{3} = data{1,3}(indices,:); end end
참고 문헌
[1] Lang, Alex H., Sourabh Vora, Holger Caesar, Lubing Zhou, Jiong Yang, and Oscar Beijbom. "PointPillars: Fast Encoders for Object Detection From Point Clouds." In 2019 IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR), 12689-12697. Long Beach, CA, USA: IEEE, 2019. https://doi.org/10.1109/CVPR.2019.01298.
[2] Hesai and Scale. PandaSet. https://scale.com/open-datasets/pandaset.
참고 항목
객체
함수
trainPointPillarsObjectDetector
|trainVoxelRCNNObjectDetector
|pcorganize
|sampleLidarData
|pcBboxOversample
앱
- 심층 신경망 디자이너 (Deep Learning Toolbox) | 라이다 레이블 지정기 | 라이다 뷰어
도움말 항목
- Get Started with PointPillars
- PointPillars 딥러닝을 사용하여 라이다 객체 검출을 위한 코드 생성하기
- Data Augmentations for Lidar Object Detection Using Deep Learning
- Lidar Object Detection Using Complex-YOLO v4 Network
- Transfer Learning Using Voxel R-CNN for Lidar 3-D Object Detection
- Point Cloud Classification Using PointNet++ Deep Learning