主要内容

基于PointNet++深度学习的航空激光雷达语义分割

这个例子展示了如何训练一个PointNet++深度学习网络对航空激光雷达数据进行语义分割。

机载激光扫描系统获取的激光雷达数据用于地形测绘、城市建模、生物量测量和灾害管理等应用。从这些数据中提取有意义的信息需要语义分割,在这个过程中,点云中的每个点都被分配一个唯一的类标签。

在本例中,您使用Dayton Annotated Lidar Earth Scan (DALES)数据集训练PointNet++网络执行语义分割[1].数据集包含密集的场景,标记航空激光雷达数据来自城市,郊区,农村和商业设置。该数据集提供了8类的语义分割标签,如建筑、汽车、卡车、电线杆、电线、围栏、地面和植被。

山谷数据加载

DALES数据集包含40个场景的航空激光雷达数据。在40个场景中,29个场景用于训练,其余11个场景用于测试。数据中的每个像素都有一个类标签。按照上面的说明去做山谷将数据集下载到指定的文件夹dataFolder变量。创建文件夹来存储培训和测试数据。

dataFolder = fullfile (tempdir,“山谷”);trainDataFolder = fullfile (dataFolder,“dales_las”“火车”);testDataFolder = fullfile (dataFolder,“dales_las”“测试”);

从训练数据预览点云。

lasReader = lasFileReader (fullfile (trainDataFolder5080 _54435.las));[pc, attr] = readPointCloud (lasReader“属性”“分类”);标签= attr.Classification;%只选择有标记的数据。电脑=选择(pc、标签~ = 0);标签=标签(标签~ = 0);一会= [“地面”“植物”“汽车”“卡车”“电线”“篱笆”“两极”“建筑”];图;ax = pcshow (pc.Location、标签);helperLabelColorbar (ax,类名);标题(“带有叠加语义标签的点云”);

数据进行预处理

DALES数据集中的每一个点云覆盖面积为500 × 500米,比地面旋转激光雷达点云覆盖的典型面积要大得多。为了高效的内存处理,将点云划分为小的、不重叠的网格。

使用helperCropPointCloudsAndMergeLabels函数,作为支持文件附加到本示例中:金宝app

  • 将点云裁剪成大小为50 × 50米的不重叠网格。

  • 将点云采样到固定大小。

  • 将点云归一化到范围[0 1]。

  • 将裁剪好的网格和语义标签分别保存为PCD和PNG文件。

定义网格维度并为每个网格设置固定的点数,以实现更快的训练。

gridSize = (50,50);numPoints = 8192;

如果训练数据已经被划分为网格,则集合writefile.请注意,培训数据必须是由金宝apppcread函数。

writefile = true;numClasses =元素个数(类名);(pcCropTrainPath labelsCropTrainPath,权重)= helperCropPointCloudsAndMergeLabels (...gridSize、trainDataFolder numPoints, writefile numClasses);

注意:处理过程可能需要一些时间。代码暂停MATLAB®执行,直到处理完成。

在训练数据集中所有类的点分布被捕获权重.规范化的权重使用maxWeight

[maxWeight, maxLabel] = max(重量);重量=√maxWeight. /重量);

创建培训数据存储对象

创建一个fileDatastore对象来加载PCD文件pcread函数。

ldsTrain = fileDatastore (pcCropTrainPath,“ReadFcn”@ (x) pcread (x));

使用一个pixelLabelDatastore对象来存储像素标签图像中的像素级标签。对象将每个像素标签映射到一个类名,并为每个类分配一个唯一的标签ID。

%指定从1到类数的标签id。labelIDs = 1: numClasses;一会,pxdsTrain = pixelLabelDatastore (labelsCropTrainPath labelIDs);

加载并显示点云。

ptcld =预览(ldsTrain);标签=预览(pxdsTrain);图;ax = pcshow (ptcld.Location uint8(标签);helperLabelColorbar (ax,类名);标题(“带有叠加语义标签的裁剪点云”);

使用helperConvertPointCloud函数,用于将点云转换为单元格数组。这个函数还会排列点云的维度,使其与网络的输入层兼容。

ldsTransformed = transform(ldsTrain,@(x) helperConvertPointCloud(x));

使用结合函数将点云和像素标签合并到一个用于训练的数据存储中。

dsTrain =结合(ldsTransformed pxdsTrain);

定义PointNet + +模型

PointNet + + (2]细分模型包括两个主要组成部分:

  • 集抽象模块

  • 功能扩展模块

集合抽象模块通过分层分组点,逐步将感兴趣的点作为子样本,并使用自定义的PointNet体系结构将点编码为特征向量。由于语义分割任务需要所有原始点的点特征,因此采用基于反距离的插值方案,利用一系列特征传播模块对原始点进行分层次的特征插值。

定义PointNet++架构使用pointnetplusLayers函数。

lgraph = pointnetplusLayers (numPoints 3 numClasses);

为了处理DALES数据集上的类不平衡,从pixelClassificationLayer使用函数。如果属于权重较低的类的一个点被错误分类,网络将受到更大的惩罚。

%用pixelClassificationLayer替换FocalLoss层。larray = pixelClassificationLayer (“名字”“SegmentationLayer”“ClassWeights”...重量、“类”类名);lgraph = replaceLayer (lgraph,“FocalLoss”, larray);

指定培训选项

使用一个大坝优化算法训练网络。使用trainingOptions函数指定超参数。

learningRate = 0.0005;l2Regularization = 0.01;numEpochs = 20;miniBatchSize = 6;learnRateDropFactor = 0.1;learnRateDropPeriod = 10;gradientDecayFactor = 0.9;squaredGradientDecayFactor = 0.999;选择= trainingOptions (“亚当”...“InitialLearnRate”learningRate,...“L2Regularization”l2Regularization,...“MaxEpochs”numEpochs,...“MiniBatchSize”miniBatchSize,...“LearnRateSchedule”“分段”...“LearnRateDropFactor”learnRateDropFactor,...“LearnRateDropPeriod”learnRateDropPeriod,...“GradientDecayFactor”gradientDecayFactor,...“SquaredGradientDecayFactor”squaredGradientDecayFactor,...“阴谋”“训练进步”);

注意:减少miniBatchSize在训练时控制内存使用的价值。

火车模型

你可以通过设置doTraining参数真正的.如果你训练网络,你可以使用CPU或GPU。使用GPU需要并行计算工具箱™和支持CUDA®的NVIDIA®GPU。有关更多信息,请参见GPU支金宝app持情况(并行计算工具箱).否则,加载预训练的网络。

doTraining = false;如果doTraining%使用trainNetwork函数在dsTrain数据存储上训练网络。[net, info] = trainNetwork(dsTrain,lgraph,options);其他的%加载预训练的网络。负载(“pointnetplusTrained.mat”“净”);结束

线段天线点云

网络在下采样点云上训练。要对测试点云进行分割,首先对测试点云进行下采样,类似于对训练数据进行下采样。对这个下采样的测试点云执行推理,以计算预测标签。插值预测标签,得到稠密点云上的预测标签。

定义numNearestNeighbors半径为稠密点云中的每个点找到下采样点云中最近的点,并有效地进行插值。

numNearestNeighbors = 20;半径= 0.05;

阅读完整的测试点云。

lasReader = lasFileReader (fullfile (testDataFolder5080 _54470.las));[pc, attr] = readPointCloud (lasReader“属性”“分类”);labelsDenseTarget = attr.Classification;%只选择有标记的数据。电脑=选择(pc, labelsDenseTarget ~ = 0);labelsDenseTarget = labelsDenseTarget (labelsDenseTarget ~ = 0);初始化预测标签labelsDensePred = 0(大小(labelsDenseTarget));

计算非重叠网格的个数gridSizeXLimits,YLimits点云的。

numGridsX =圆(diff (pc.XLimits) / gridSize (1));numGridsY =圆(diff (pc.YLimits) / gridSize (2));[~, edgesX edgesY indx,印第安纳·琼斯)= histcounts2 (pc.Location (: 1), pc.Location (:, 2),...[numGridsX, numGridsY],“XBinLimits”,电脑。XLimits,“YBinLimits”, pc.YLimits);印第安纳州= sub2ind ([numGridsX numGridsY], indx,印第安纳·琼斯);

迭代所有非重叠网格并使用semanticsegf津津有味。

num=1:numGridsX*numGridsY idx = ind==num;ptCloudDense =选择(pc, idx);labelsDense = labelsDenseTarget (idx);%使用helperDownsamplePoints函数,附加到本例中文件金宝app中提取下采样的点云%密集点云。ptCloudSparse = helperDownsamplePoints (ptCloudDense,...labelsDense numPoints);%绘制稠密点云和稀疏点的空间范围%的云一样。限制= [ptCloudDense.XLimits; ptCloudDense.YLimits ptCloudDense.ZLimits];ptCloudSparseLocation = ptCloudSparse.Location;: ptCloudSparseLocation(1:2) =限制(:1:2)';ptCloudSparse = pointCloud (ptCloudSparseLocation,“颜色”, ptCloudSparse。的颜色,...“强度”, ptCloudSparse。强度,...“正常”, ptCloudSparse.Normal);%使用helperNormalizePointCloud函数,附加到本例中%一个支金宝app持文件,使点云在0和1之间标准化。ptCloudSparseNormalized = helperNormalizePointCloud (ptCloudSparse);ptCloudDenseNormalized = helperNormalizePointCloud (ptCloudDense);%使用在本文末尾定义的helperConvertPointCloud函数示例中,将点云转换为单元格数组并对%点云的尺寸,以使其与输入层兼容%的网络。ptCloudSparseForPrediction = helperConvertPointCloud (ptCloudSparseNormalized);%获取输出预测。labelsSparsePred = semanticseg (ptCloudSparseForPrediction {1},...网,“OutputType”“uint8”);使用helperInterpolate函数,附加到这个例子中%支金宝app持文件,计算密集点云的标签,%使用稀疏点云和稀疏点云上预测的标签。interpolatedLabels = helperInterpolate (ptCloudDenseNormalized,...ptCloudSparseNormalized、labelsSparsePred numNearestNeighbors,...半径,maxLabel numClasses);labelsDensePred (idx) = interpolatedLabels;结束
使用“local”配置文件启动并行池(parpool)…连接到并行池(工作人员数量:6)。

为了更好的可视化,从点云数据中选择一个感兴趣的区域。中的限制roi根据点云数据变化。

roi = [edgesX(5) edgesX(8) edgesY(8) edgesY(11) pc.ZLimits];指数= findPointsInROI (pc, roi);图;ax = pcshow(选择(pc,指数)。位置,labelsDensePred(指数));轴;变焦(ax, 1.5);helperLabelColorbar (ax,类名);标题(“被检测语义标签覆盖的点云”);

评估网络

根据测试数据评估网络性能。使用evaluateSemanticSegmentation函数从测试集结果计算语义分割度量。目标和预测的标签是预先计算的,并存储在labelsDensePredlabelsDenseTarget变量分别。

confusionMatrix = segmentationConfusionMatrix (labelsDensePred,...双(labelsDenseTarget),“类”1: numClasses);指标= evaluateSemanticSegmentation ({confusionMatrix},一会,“详细”、假);

您可以使用联合交叉(IoU)度量度量每个类的重叠量。

evaluateSemanticSegmentation函数返回整个数据集、单个类和每个测试映像的度量值。要在数据集级别查看度量标准,请使用指标。DataSetMetrics财产。

指标。DataSetMetrics
ans =1×4表GlobalAccuracy MeanAccuracy MeanIoU WeightedIoU  ______________ ____________ _______ ___________ 0.93191 0.64238 0.52709 0.88198

数据集指标提供了网络性能的高级概述。要查看每个类对整体性能的影响,请使用指标。ClassMetrics财产。

指标。ClassMetrics
ans =8×2表精度IoU ________ _________ ground 0.98874 0.93499 vegetation 0.5948 0.81865 cars 0.61847 0.36659 trucks 0.018676 0.0070006电源线0.7758 0.6904围栏0.3753 0.21718电杆0.5741 0.28528 buildings 0.92843 0.89662

虽然总体网络性能很好,但是类的指标对于一些类来说,比如卡车表示需要更多的训练数据才能获得更好的表现。

金宝app支持功能

helperLabelColorbar函数将颜色条添加到当前轴。颜色栏被格式化为使用颜色显示类名。

函数helperLabelColorbar (ax,类名)% Colormap的原始类。提出= [[0,0255);(0255,0);[255192203];(255255,0);(255、0255);(255165,0);(139、0150);(255, 0, 0)];提出255 = cmap. /;提出=提出(1:元素个数(类名):); colormap(ax,cmap);%添加颜色栏到当前的数字。c = colorbar (ax);c.Color =' w '%居中标记,并使用类名作为标记。numClasses = size(classNames, 1);c.Ticks = 1:1: numClasses;c.TickLabels =一会;%删除勾号。c.TickLength = 0;结束

helperConvertPointCloud函数将点云转换为单元阵列,并对点云的维度进行排列,以使其与网络的输入层兼容。

函数data = helperConvertPointCloud(数据)如果~iscell(data) data = {data};结束numObservations =大小(数据,1);i = 1:numObservations tmp = data{i,1}.Location;数据{1}=排列(tmp[1、3、2]);结束结束

参考文献

[1] Varney Nina Vijayan K. Asari和Quinn Graehling。DALES:用于语义分割的大规模航空激光雷达数据集。ArXiv: 2004.11985 (Cs,统计)2020年4月14日。https://arxiv.org/abs/2004.11985

李毅,苏浩,列奥尼达斯·j·古巴斯。PointNet++:度量空间点集的深度层次特征学习。ArXiv: 1706.02413 (Cs), 2017年6月7日。https://arxiv.org/abs/1706.02413