这个例子展示了如何在三维组织的激光雷达点云数据上训练PointSeg语义分割网络。
PointSeg [1]是一种卷积神经网络(CNN),用于基于有组织的激光雷达点云对道路物体进行端到端语义分割。通过使用非均匀空间金字塔池化(ASPP)和挤压激励块等方法,该网络提供了更好的分割结果。本例中显示的训练过程需要2-D球形投影图像作为深度学习网络的输入。
本例使用Ouster OS1传感器收集的高速公路场景数据集。它包含有组织的高速公路场景的激光雷达点云扫描和相应的汽车和卡车物体的地面真相标签。数据文件的大小约为760 MB。
执行此代码下载高速公路场景数据集。数据集包含1617个点云,存储为pointCloud
单元格数组中的对象。对应的地面真相数据,附在示例中,包含每个点云中汽车和卡车的边界框信息。
url =“//www.tatmou.com/金宝appsupportfiles/lidar/data/WPI_LidarData.tar.gz”;outputFolder = fullfile(tempdir,批发价格指数的);lidarDataTarFile = fullfile(输出文件夹,“WPI_LidarData.tar.gz”);如果~存在(lidarDataTarFile“文件”mkdir (outputFolder);disp (“下载WPI激光雷达驾驶数据(760 MB)……”);websave (lidarDataTarFile、url);解压(lidarDataTarFile outputFolder);结束检查tar.gz文件是否已下载,但未解压。如果~ (fullfile (outputFolder,存在“WPI_LidarData.mat”),“文件”)解压(lidarDataTarFile outputFolder);结束lidarData = load(fullfile(outputFolder)“WPI_LidarData.mat”));groundTruthData = load(“WPI_LidarGroundTruth.mat”);
注意:根据您的互联网连接,下载过程可能需要一些时间。该代码暂停MATLAB®执行,直到下载过程完成。或者,您可以使用web浏览器将数据集下载到本地磁盘,然后提取WPI_LidarData
.要使用从web下载的文件,请更改outputFolder
变量中指定下载文件的位置。
下载预训练的网络,以避免等待训练完成。如果要训练网络,请设置doTraining
变量为true。
doTraining = false;如果~doTraining && ~exist(“trainedPointSegNet.mat”,“文件”) disp (“正在下载预训练的网络(14 MB)…”);pretrainedURL =“//www.tatmou.com/金宝appsupportfiles/lidar/data/trainedPointSegNet.mat”;websave (“trainedPointSegNet.mat”, pretrainedURL);结束
下载预训练的网络(14 MB)…
使用helperGenerateTrainingData
金宝app本例附带的支持函数用于从激光雷达点云生成训练数据。该函数使用点云和包围框数据创建五通道输入图像和像素标签图像。为了创建像素标签图像,该函数选择边界框内的点,并用边界框类ID标记它们。每个训练图像被指定为64 × 1024 × 5数组:
每个图像的高度是64像素。
每个图像的宽度为1024像素。
每个图像有5个通道。这五个通道指定了点云的三维坐标,强度,和范围: .
下面是训练数据的可视化表示。
生成五通道训练图像和像素标签图像。
imagesFolder = fullfile(输出文件夹,“图片”);labelsFolder = fullfile(输出文件夹,“标签”);helperGenerateTrainingData(lidarData, groundTruthData, imagesFolder, labelsFolder);
预处理数据完成100.00%
五通道图像被保存为MAT文件。像素标签保存为PNG格式。
注意:处理过程可能需要一些时间。该代码暂停MATLAB®执行,直到处理完成。
mageDatastore
和PixelLabelDatastore
使用imageDatastore
对象来提取和存储二维球面图像的五个通道helperImageMatReader
金宝app支持功能,这是一个自定义的MAT文件阅读器。这个函数作为支持文件附加到这个示例中。金宝app
imds = imageDatastore(imagesFolder,...“FileExtensions”,“.mat”,...“ReadFcn”, @helperImageMatReader);
使用pixelLabelDatastore
对象从标签图像中存储按像素划分的标签。对象将每个像素标签映射到一个类名。在这个例子中,汽车和卡车是唯一感兴趣的对象;所有其他像素都是背景。指定这些类(汽车、卡车和背景),并为每个类分配唯一的标签ID。
classNames = [“背景”“汽车”“卡车”];numClasses = numel(classNames);指定标签id,取值范围从1到类的个数。labelIDs = 1: numClasses;pxds = pixelLabelDatastore(标签文件夹,classNames, labelIDs);
方法将其中一个标记图像叠加在相应的强度图像上,从而加载和显示该标记图像helperDisplayLidarOverlayImage
函数中定义的金宝app支持功能部分的示例。
imageNumber = 225;点云(通道1、2、3表示位置,通道4表示强度)。I = readimage(imds, imageNumber);labelMap = readimage(pxds, imageNumber);图;helperDisplayLidarOverlayImage(I, labelMap, classNames);标题(“地面实况”);
使用helperPartitionLidarData
金宝app本例附带的支持函数将数据分为训练集、验证集和测试集,分别包含970、216和431张图像。
[imdsTrain, imdsVal, imdsTest, pxdsTrain, pxdsVal, pxdsTest] =...pxds helperPartitionLidarData (imd);
使用结合
函数组合用于训练和验证数据集的像素和图像数据存储。
trainingData = combine(imdsTrain, pxdsTrain);validationData = combine(imdsVal, pxdsVal);
数据增强是通过在训练过程中随机转换原始数据来提高网络的准确性。通过使用数据增强,您可以为训练数据添加更多的多样性,而无需实际增加标记训练样本的数量。
增强训练数据使用变换
属性指定的自定义预处理操作augmentData
函数中定义的金宝app支持功能部分的示例。这个函数在水平方向上随机翻转球面2-D图像和相关标签。仅对训练数据集应用数据增强。
augmentedTrainingData = transform(trainingData, @(x) augmentData(x));
要查看类标签在数据集中的分布,请使用countEachLabel
函数。
tbl = countEachLabel(pxds);台(:{“名字”,“PixelCount”,“ImagePixelCount”})
ans =3×3表名字PixelCount ImagePixelCount ______________ __________ _______________ {' 背景”}1.0473 e + 08年1.0597 e + 08年{‘汽车’}9.7839 8.4738 e + e + 05年07{“卡车”}2.6017 e + e + 07年05年1.9726
这个数据集中的类是不平衡的,这是包含街道场景的汽车数据集中的一个常见问题。背景类比汽车和卡车类覆盖更多的区域。如果处理不当,这种不平衡可能不利于学习过程,因为学习倾向于优势阶级。
使用这些权重来纠正类的不平衡。的像素标签计数资源描述。PixelCount
属性并计算中位数频率类权重。
imageFreq = tbl。PixelCount./ tbl.ImagePixelCount; classWeights = median(imageFreq) ./ imageFreq
classWeights =3×10.0133 1.1423 1.0000
创建PointSeg网络createPointSeg
金宝app支持函数,该函数附在示例中。代码返回用于训练网络的层图。
inputSize = [64 1024 5];lgraph = createPointSeg(inputSize, classNames, classWeights);
使用analyzeNetwork
(深度学习工具箱)函数来显示网络体系结构的交互式可视化。
analyzeNetwork (lgraph)
使用rmsprop
训练网络的优化算法。属性指定算法的超参数trainingOptions
函数。
maxEpochs = 30;initialLearningRate = 5的军医;miniBatchSize = 8;L2reg = 2e-4;选项= trainingOptions(“rmsprop”,...“InitialLearnRate”initialLearningRate,...“L2Regularization”l2reg,...“MaxEpochs”maxEpochs,...“MiniBatchSize”miniBatchSize,...“LearnRateSchedule”,“分段”,...“LearnRateDropFactor”, 0.1,...“LearnRateDropPeriod”10...“ValidationData”validationData,...“阴谋”,“训练进步”,...“VerboseFrequency”, 20);
注意:减少miniBatchSize
训练时控制记忆的使用。
使用trainNetwork
(深度学习工具箱)函数来训练PointSeg网络doTraining
是真正的
.否则,加载预训练的网络。
如果你训练网络,你可以使用CPU或GPU。使用GPU需要并行计算工具箱™和支持CUDA®的NVIDIA®GPU。有关更多信息,请参见GPU支金宝app持版本(并行计算工具箱).
如果doTraining [net, info] = trainNetwork(trainingData, lgraph, options);其他的pretrainedNetwork = load(“trainedPointSegNet.mat”);net =预培训网络;结束
使用训练好的网络在测试点云上预测结果,并显示分割结果。
首先,读取PCD文件并将点云转换为五通道输入图像。使用训练过的网络预测标签。将分段显示为叠加图。
ptCloud = pcread(“ousterLidarDrivingData.pcd”);I = helppointcloudtoimage (ptCloud);predictedResult = semanticseg(I, net);图;helperDisplayLidarOverlayImage(I, predictedResult, classNames);标题(“语义分割结果”);
使用helperDisplayLidarOverlayPointCloud
属性中定义的Helper函数金宝app支持功能部分,以显示在三维点云对象上的分割结果ptCloud
.
图;helperDisplayLidarOverlayPointCloud(ptCloud, predictedResult, numClasses);查看([95.71 24.14])“点云的语义分割结果”);
运行semanticseg
函数对整个测试集进行测试,以测量网络的准确性。集MiniBatchSize
值为8以减少分割图像时的内存使用。您可以根据系统上的GPU内存数量增加或减少这个值。
outputLocation = fullfile(tempdir,“输出”);如果~存在(outputLocation“dir”mkdir (outputLocation);结束pxdsResults = semanticseg(imdsTest, net,...“MiniBatchSize”8...“WriteLocation”outputLocation,...“详细”、假);
的semanticseg
函数返回测试数据集上的分割结果PixelLabelDatastore
对象。函数中为每个测试图像写入实际像素标签数据imdsTest
属性指定的位置中的磁盘“WriteLocation”
论点。
使用evaluateSemanticSegmentation
函数从测试集结果计算语义分割度量。
metrics = evaluateSemanticSegmentation(pxdsResults, pxdsTest, pxdsTest)“详细”、假);
您可以使用交集-over-union (IoU)度量来度量每个类的重叠量。
的evaluateSemanticSegmentation
函数返回整个数据集、单个类和每个测试图像的指标。要查看数据集级别的指标,请使用指标。DataSetMetrics
财产。
指标。DataSetMetrics
ans =表1×5GlobalAccuracy MeanAccuracy MeanIoU WeightedIoU MeanBFScore ______________ ____________ _______ ___________ ___________ 0.99209 0.83752 0.67895 0.98685 0.91654
数据集指标提供了网络性能的高级概述。类检查每个类的度量,以查看每个类对总体性能的影响指标。ClassMetrics
财产。
指标。ClassMetrics
ans =3×3表准确性IoU MeanBFScore ________ _______ ___________后台0.99466 0.99212 0.98529汽车0.75977 0.50096 0.82682卡车0.75814 0.54378 0.77119
尽管网络的整体性能很好,但类指标表明,有偏见的类(汽车和卡车)并没有像具有丰富数据的类(背景)那样分割。您可以通过使用包含汽车和卡车类别的更多标记数据来训练网络,从而提高网络性能。
的augmentData
函数在水平方向上随机翻转二维球面图像和相关标签。
函数out = augmentData(inp)应用随机水平翻转。Out = cell(size(inp));%随机翻转五通道图像和像素标签水平。I = inp{1};sz = size(I);tform = randomAffine2d(“XReflection”,真正的);rout = affineOutputView(sz,tform,“BoundsStyle”,“centerOutput”);out{1} = imwarp(I,tform,“OutputView”,溃败);输出{2}= imwarp(inp{2},tform,“OutputView”,溃败);结束
的helperDisplayLidarOverlayImage
函数将语义分割图覆盖在二维球面图像的强度通道上。该函数还可以调整覆盖图像的大小,以便更好地可视化。
函数helperDisplayLidarOverlayImage(lidarImage, labelMap, classNames)在强度图像上叠加标签。%% helperDisplayLidarOverlayImage(lidarImage, labelMap, classNames)%显示覆盖的图像。lidarImage是一个五通道激光雷达输入。% labelMap包含像素标签,classNames是一个标签数组%的名字。从激光雷达图像中读取强度通道。intensityChannel = uint8(lidarImage(:,:,4));加载激光雷达彩色地图。cmap = helperLidarColorMap();将标签覆盖在强度图像上。。B = labeloverlay(intensityChannel,labelMap,“Colormap”提出,“透明”, 0.4);为更好的可视化调整大小。B = imresize(B,“规模”, [3 1],“方法”,“最近的”);imshow (B);显示颜色条。helperPixelLabelColorbar(提出,类名);结束
的helperDisplayLidarOverPointCloud
函数将分割结果覆盖在三维组织的点云上。
函数helperDisplayLidarOverlayPointCloud(ptCloud, labelMap, numClasses)在点云对象上叠加标签。%% helperDisplayLidarOverlayPointCloud(ptCloud, labelMap, numClasses)%显示覆盖的pointCloud对象。ptCloud是有组织的%三维点云输入。labelMap包含像素标签和numClasses%是预测类的数量。sz = size(labelMap);把红色涂在汽车上。carClassCar = 0 (sz(1), sz(2), numClasses,“uint8”);carClassCar(:,:,1) = 255*ones(sz(1), sz(2),“uint8”);在卡车上涂上蓝色。= 0 (sz(1), sz(2), numClasses,“uint8”);truckClassColor(:,:,3) = 255*ones(sz(1), sz(2),“uint8”);将灰色应用于背景。backgroundClassColor = 153*ones(sz(1), sz(2), numClasses,“uint8”);从标签中提取索引。carIndices = labelMap ==“汽车”;truckIndices = labelMap ==“卡车”;backgroundIndices = labelMap ==“背景”;为每个类提取一个点云。carPointCloud = select(ptCloud, carindexes,“OutputSize”,“全部”);truckPointCloud = select(ptCloud, truckIndices,“OutputSize”,“全部”);backgroundPointCloud = select(ptCloud, backgrounddindices,“OutputSize”,“全部”);为不同的类应用颜色。carPointCloud。Color = carClassCar;truckPointCloud。Color = truckClassColor;backgroundPointCloud。Color = backgroundClassColor;合并并添加所有处理过的带类信息的点云。colordcloud = pcmerge(carPointCloud, truckPointCloud, 0.01);coloredCloud = pcmerge(coloredCloud, backgroundPointCloud, 0.01);绘制彩色点云。为更好的可视化设置ROI。ax = pcshow(coloredCloud);集(ax,“XLim”(-35.0 - 35.0),“YLim”(-32.0 - 32.0),“ZLim”, 8 [3],...“XColor”,“没有”,“YColor”,“没有”,“ZColor”,“没有”);集(get (ax,“父”),“单位”,“归一化”);结束
的helperLidarColorMap
函数定义激光雷达数据集使用的颜色映射。
函数cmap = helperLidarColorMap() cmap = [0.00 0.00 0.00%的背景0.98 0.00 0.00%的车0.00 0.00 0.98%的卡车];结束
的helperPixelLabelColorbar
函数将颜色条添加到当前轴。颜色条被格式化以显示带有颜色的类名。
函数helperPixelLabelColorbar(cmap, classNames) colormap(gca, cmap);向当前图形添加颜色条。C = colorbar(“对等”甘氨胆酸,);使用类名作为标记。c.TickLabels = classNames;numClasses = size(classNames, 1);%中心打勾标签。c.Ticks = 1/(numClasses * 2):1/numClasses:1;删除标记。c.TickLength = 0;结束
[1]王、袁、史天岳、云鹏、泰磊、刘明。PointSeg:基于三维激光雷达点云的实时语义分割ArXiv: 1807.06288 (Cs)2018年9月25日。http://arxiv.org/abs/1807.06288。