PointPillars 深層学習を使用した LiDAR の 3 次元オブジェクト検出
この例では、PointPillars 深層学習ネットワーク [1] を使用して LiDAR でのオブジェクトを検出する方法を示します。この例では、次を行います。
PointPillars オブジェクト検出ネットワークの学習用とテスト用のデータセットを構成する。学習データセットに対するデータ拡張も実行し、ネットワーク効率を向上させる。
学習データからアンカー ボックスを計算して、PointPillars オブジェクト検出ネットワークに学習させる。
関数
pointPillarsObjectDetector
を使用して PointPillars オブジェクト検出器を作成し、関数trainPointPillarsObjectDetector
を使用して検出器に学習させる。
この例では、点群内のオブジェクトの検出に使用する事前学習済みの PointPillars オブジェクト検出器も提供します。事前学習済みのモデルは、Pandaset データセットで学習させています。pointpillars オブジェクト検出ネットワークの詳細については、PointPillars 入門を参照してください。
LiDAR データ セットのダウンロード
PandaSet データ セット [2] からセンサー データのサブセットを含む ZIP ファイル (サイズは約 5.2 GB) をダウンロードします。ダウンロードした後、ファイルを解凍します。このファイルには、Lidar
と Cuboids
という 2 つのメイン フォルダーが含まれており、これには次のデータが含まれています。
PointCloud フォルダーには、前処理された 2560 個のオーガナイズド点群が PCD 形式で格納されています。この点群は、エゴ ビークルが正の y 軸に沿って移動するように配置されています。点群がこの向きから外れている場合は、
pctransform
関数を利用して必要な変換を適用できます。Cuboid
フォルダーには、対応するグラウンド トゥルース データがテーブル形式で格納されています。このデータはPandasetLidarGroundTruth.mat
ファイルに保存されています。このファイルは、3 つのカテゴリ (自動車、トラック、歩行者) の 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® の実行を一時停止します。または、Web ブラウザーを使用してデータ セットをローカル ディスクにダウンロードし、ファイルを抽出することもできます。その場合は、コード内の変数 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
トリミングされた点群とグラウンド トゥルース ボックス ラベルを表示します。
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);
データストア オブジェクトの作成
データ セットを学習セットとテスト セットに分割します。データの 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));
boxLabelDatastore
を使用して、3 次元境界ボックス ラベルを読み込むためのボックス ラベル データストアを作成します。
bds = boxLabelDatastore(trainLabels);
関数combine
を使用して、学習用に点群と 3 次元境界ボックス ラベルを単一のデータストアに統合します。
cds = combine(lds,bds);
データ拡張の実行
この例では、グラウンド トゥルース データ拡張と他のいくつかのグローバル データ拡張手法を使用して、学習データと対応するボックスにさらに多様性を付加します。LIDAR データによる 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
を使用して、グラウンド トゥルース データとカスタム データの拡張を学習データに適用します。
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
補助関数を使用して、拡張された点群と拡張されたグラウンド トゥルース ボックスを表示します。
augData = preview(cdsAugmented); [ptCld,bboxes,labels] = deal(augData{1},augData{2},augData{3}); helperShowPointCloudWith3DBoxes(ptCld,bboxes,labels,classNames,colors)
PointPillars オブジェクト検出器の作成
関数pointPillarsObjectDetector
を使用して、PointPillars オブジェクト検出ネットワークを作成します。PointPillars ネットワークの詳細については、PointPillars 入門を参照してください。
図は、PointPillars オブジェクト検出器のネットワーク アーキテクチャを示しています。PointPillars ネットワークはディープ ネットワーク デザイナー (Deep Learning Toolbox)アプリを使用して作成できます。
この例にサポート ファイルとして添付されている補助関数 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
は、Pandar 64 センサーによって取得された点群データで学習させます。エゴ ビークルの方向は正の y 軸に沿うようにします。
カスタム データセットでこの事前学習済みネットワークを使用して正確な検出を生成するには、次のようにします。
エゴ ビークルが正の 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) | LiDAR ラベラー | LiDAR ビューアー