主要内容

基于深度学习的多光谱图像语义分割

此示例演示如何使用U-Net对具有七个通道的多光谱图像执行语义分割。

语义分割包括用类标记图像中的每个像素。语义分割的一个应用是跟踪森林砍伐,即森林覆盖随时间的变化。环境机构跟踪森林砍伐,以评估和量化一个地区的环境和生态健康。

基于深度学习的语义分割可以从高分辨率航空照片中获得精确的植被覆盖测量值。一个挑战是区分具有相似视觉特征的类别,例如试图将绿色像素划分为草、灌木或树。为了提高分类精度,一些数据集包含多光谱图像,提供关于每个像素的额外信息。例如,哈姆林海滩州立公园的数据集用三个近红外通道补充了彩色图像,提供了更清晰的分类。

这个例子展示了如何使用基于深度学习的语义分割技术从一组多光谱图像中计算一个区域的植被覆盖百分比。

下载数据

本例使用高分辨率多光谱数据集来训练网络[1].这组图像是由一架无人机在纽约哈姆林海滩州立公园上空拍摄的。该数据包含带有18个对象类标签的标记训练、验证和测试集。数据文件大小为~3.0 GB。

下载数据集的MAT-file版本downloadHamlinBeachMSIData助手函数。此函数作为支持文件附加到示例中。万博1manbetx

imageDir = tempdir;url =“http://www.cis.rit.edu/ ~ rmk6217 / rit18_data.mat”;downloadHamlinBeachMSIData (url, imageDir);

检查训练数据

将数据集加载到工作区中。

负载(fullfile (imageDir“rit18_data”“rit18_data.mat”));

检查数据的结构。

train_dataval_data测试数据
名称大小字节类属性测试数据7x12446x7654 1333663576 uint16列数据7x9393x5642 741934284 uint16 val_数据7x8833x6918 855493716 uint16

多光谱图像数据按如下方式排列:数字通道-借-宽度-借-身高数组。而在MATLAB®中,多通道图像排列为宽度-借-身高-借-数字通道数组。要重塑数据以使通道处于第三维,请使用助手函数,切换通道至第三车道.这个函数作为支持文件附加到示例中。万博1manbetx

train_data = switchChannelsToThirdPlane (train_data);val_data = switchChannelsToThirdPlane (val_data);test_data = switchChannelsToThirdPlane (test_data);

确认数据具有正确的结构。

train_dataval_data测试数据
名称大小字节类属性测试数据12446x7654x7 1333663576 uint16列数据9393x5642x7 741934284 uint16 val数据8833x6918x7 855493716 uint16

RGB颜色通道是第3、2和1个图像通道。以蒙太奇的形式显示训练、验证和测试图像的颜色组件。要使图像在屏幕上显得更亮,可以使用histeq函数。

人物蒙太奇(...{histeq (train_data (:,: [3 2 1])),...histeq(val_数据(:,:,[3 2 1])),...histeq(测试数据(:,:,[3 2 1])),...“BorderSize”,10,“写成BackgroundColor”“白色”)头衔(“训练图像(左)、验证图像(中)和测试图像(右)的RGB组件”

以蒙太奇的形式显示训练数据的最后三个直方图均衡化通道。这些通道对应于近红外波段,并根据它们的热信号突出图像的不同组成部分。例如,靠近第二个通道图像中心的树比其他两个通道中的树显示更多的细节。

人物蒙太奇(...{histeq (train_data (:: 4)),...histeq (train_data (:: 5)),...histeq (train_data (:: 6))},...“BorderSize”,10,“写成BackgroundColor”“白色”)头衔(“训练图像的IR通道1(左)、2(中)和3(右)”

通道7是指示有效分割区域的掩码。显示用于训练、验证和测试图像的掩码。

人物蒙太奇(...{列_数据(:,:,7),...val_数据(:,:,7),...test_data (:: 7)},...“BorderSize”,10,“写成BackgroundColor”“白色”)头衔(“训练图像遮罩(左)、验证图像(中)和测试图像(右)”

标记的图像包含用于分割的地面真实数据,每个像素分配给18个类别中的一个。获取类别列表及其相应ID。

disp(类)
0.其他类别/图像边框1.道路标记2.树木3.建筑物4.车辆(汽车、卡车或公共汽车)5.人员6.救生椅7.野餐桌8.黑色木板9.白色木板10.橙色落地垫11.水浮标12.岩石13.其他植被14.草15.沙16.水(湖)17.水(池)18.沥青(停车场/人行道)

创建类名向量。

一会= [“路标”“树”“建筑”“汽车”“人”...“LifeguardChair”“野餐桌”“黑木板”...“白木板”“OrangeLandingPad”“浮标”“岩石”...“低地植被”“草地”“Sand_Beach”...“水湖”“水塘”“沥青”];

在直方图均衡化的RGB训练图像上叠加标签。给图像添加一个颜色栏。

提出=喷气(元素个数(类名);B = labeloverlay (histeq (train_data (:,: 4:6)), train_labels,“透明”, 0.8,“彩色地图”,cmap);图形标题(“培训”标签) imshow(B) N = numel(classNames);蜱虫= 1 / (N * 2): 1 / N: 1;colorbar (“滴答声标签”cellstr(类名),“滴答声”蜱虫,“滴答声长度”,0,“TickLabelInterpreter”“没有”);彩色地图(cmap)

将培训数据保存为MAT文件,将培训标签保存为PNG文件。

保存(“train_data.mat”“列车数据”);imwrite(列车标签、,“train_labels.png”);

创建用于训练的随机补丁提取数据存储

使用随机补丁提取数据存储将训练数据提供给网络。该数据存储从包含地面真像和像素标签数据的图像数据存储和像素标签数据存储中提取多个相应的随机patch。打补丁是一种常见的技术,可以防止大图像内存耗尽,并有效地增加可用的训练数据量。

从存储训练图像开始“train_data.mat”在一个imageDatastore.因为MAT文件格式是非标准的图像格式,所以必须使用MAT文件阅读器来读取图像数据。你可以使用辅助MAT文件读取器,matReader,它从训练数据中提取前六个通道,并省略包含掩码的最后一个通道。此函数作为支持文件附加到示例中。万博1manbetx

imd = imageDatastore (“train_data.mat”“FileExtensions”“.mat”“ReadFcn”, @matReader);

创建一个pixelLabelDatastore存储包含18个已标记区域的标签补丁。

PixelLabelId=1:18;pxds=pixelLabelDatastore(“train_labels.png”,类名,像素标签);

创建一个随机抽取数据存储从图像数据存储和像素标签数据存储。每个小批量包含16个256 × 256像素的补丁。在历元的每个迭代中提取1000个小批量。

pxds dsTrain = randomPatchExtractionDatastore (imd, [256256],“PatchesPerImage”,16000);

随机补丁提取数据存储dsTrain在epoch的每次迭代中向网络提供小批量的数据。预览数据存储以探索数据。

inputBatch =预览(dsTrain);disp (inputBatch)
InputImage ResponsePixelLabelImage  __________________ _______________________ { 256×256×6 uint16}{256×256分类}{256×256×6 uint16}{256×256分类}{256×256×6 uint16}{256×256分类}{256×256×6 uint16}{256×256分类}{256×256×6 uint16}{256×256分类}{256×256×6 uint16}{256×256分类}{256×256×6 uint16}{256×256 categorical} {256×256×6 uint16} {256×256 categorical}

创建U-Net网络层

本例使用U-Net网络的一种变体。在U-Net中,最初的卷积层序列被最大池化层点缀,依次降低了输入图像的分辨率。这些层之后是一系列交错上采样算子的卷积层,依次提高了输入图像的分辨率[2].U- net这个名字来源于这样一个事实:这个网络可以被画成一个像字母U一样的对称形状。

本例修改了U-Net,使其在卷积中使用零填充,以便卷积的输入和输出具有相同的大小。使用辅助函数,createUnet,创建一个带有几个预选超参数的U形网络。此函数作为支持文件附加到示例中。万博1manbetx

inputFileSize=[256256,6];lgraph=createUnet(inputFileSize);disp(lgraph.Layers)
带层的58x1层阵列:1“ImageInputLayer”图像输入256x256x6图像,带“零中心”规格化2“编码器-Section-1-Conv-1”卷积64 3x6卷积,带跨距[1 1]和填充[1 1 1 1]3“编码器-Section-1-ReLU-1”ReLU-4“编码器-Section-1-Conv-2”卷积64 3x64卷积,带跨距[1]和填充[1 1 1]5'Encoder-Section-1-ReLU-2'ReLU-ReLU-6'Encoder-Section-1-MaxPool'最大池2x2最大池带跨步[2]和填充[0 0 0 0 0]7'Encoder-Section-2-Conv-1'卷积128 3x3x64卷积带跨步[1]和填充[1 1 1 1 1 1]8'编码器-Section-2-ReLU-1'ReLU-ReLU-9'编码器-Section-2-Conv-2'卷积128 3x3x128带跨步[11]和填充[11]10'编码器-Section-2-ReLU-2'ReLU-11'编码器-Section-2-MaxPool'最大池2x2最大池带跨步[22]和填充[0 0]12'编码器段-3-Conv-1'卷积256 3x3x128卷积带跨步[1]和填充[1]13'编码器段-3-ReLU-1'ReLU-14'编码器段-3-Conv-2'卷积256 3x3x256卷积带跨步[1]和填充[1]15'Encoder-Section-3-ReLU-2'ReLU-ReLU-16'Encoder-Section-3-MaxPool'Max Pool 2x2 Max Pool带跨步[2]和填充[0 0 0 0]17'Encoder-Section-4-Conv-1'卷积512 3x3x256卷积带跨步[1]和填充[1 1 1 1]18'编码器-Section-4-ReLU-1'ReLU-ReLU-19'编码器-Section-4-Conv-2'卷积512 3x3x512带跨步[11]和填充[11]20'编码器-Section-4-ReLU-2'ReLU-21'编码器-Section-4-辍学'DropOut 50%辍学22'编码器-Section-4-MaxPool'最大池2x2最大池带跨步[2]和填充[0]23“Mid-Conv-1”卷积1024 3x3x512卷积带跨步[1]和填充[1]24“Mid-ReLU-1”ReLU-25“Mid-Conv-2”卷积1024 3x3x1024卷积带跨步[1]和填充[1]26“中端ReLU-2”ReLU-ReLU 27“中端辍学”辍学50%辍学28“解码器节-1-UpConv”转置卷积512 2x2x1024转置卷积,带跨步[2]和裁剪[0]29“Decoder-Section-1-UpReLU”ReLU-ReLU 30“Decoder-Section-1-DepthConcatenation”深度级联2个输入的深度级联31“Decoder-Section-1-Conv-1”卷积512 3x3x1024带跨步[1]和填充[1]32'解码器-Section-1-ReLU-1'ReLU-ReLU-33'解码器-Section-1-Conv-2'卷积512 3x3x512带跨步[11]和填充[11]34'解码器-Section-1-ReLU-2'ReLU-ReLU-35'解码器-Section-2-UpConv'转置卷积256 2x2x512带跨步[22]和裁剪[0 0]36“Decoder-Section-2-UpReLU”ReLU-ReLU 37“Decoder-Section-2-DepthConcatenation”深度级联2个输入的深度级联38“Decoder-Section-2-Conv-1”卷积256 3x3x512带跨步[1]和填充[1]39'解码器-Section-2-ReLU-1'ReLU-ReLU-40'解码器-Section-2-Conv-2'卷积256 3x3x256带跨步[11]和填充[11]41'解码器-Section-2-ReLU-2'ReLU-42'解码器-Section-3-UpConv'转置卷积128 2x2x256带跨步[22]和剪切[0 0]43“Decoder-Section-3-UpReLU”ReLU-ReLU 44“Decoder-Section-3-DepthConcatenation”深度级联2个输入的深度级联45“Decoder-Section-3-Conv-1”卷积128 3x3x256带跨步[1]和填充[1]46“Decoder-Section-3-ReLU-1”ReLU-ReLU 47“Decoder-Section-3-Conv-2”卷积128 3x3x128带跨步[11]和填充[11]48“Decoder-Section-3-ReLU-2”ReLU-ReLU 49“Decoder-Section-4-UpConv”转置卷积64 2x2x2x128带跨步[22]和裁剪[0 0]50'解码器-Section-4-UpReLU'ReLU-ReLU-51'解码器-Section-4-DepthConcatenation'深度串联深度串联2个输入52'解码器-Section-4-Conv-1'卷积64 3x3x128带跨步[1]和填充[1]53'解码器-Section-4-ReLU-1'ReLU-ReLU-54'解码器-Section-4-Conv-2'卷积64 3x3x64带跨步[1]和填充[1 1]55'解码器-Section-4-ReLU-2'ReLU-ReLU-56'最终卷积层'卷积18 1xx64带跨步[1]和填充[0 0]57'Softmax层'Softmax Softmax 58'分割层'像素分类层交叉熵损失

选择培训选项

使用随机梯度下降动量优化(SGDM)训练网络。使用trainingOptions(深度学习工具箱)函数。

训练一个深度网络是非常耗时的。通过指定高学习率来加速训练。然而,这可能会导致网络的梯度发生爆炸或无法控制地增长,从而阻碍网络的成功训练。要使渐变保持在有意义的范围内,可以通过指定来启用渐变剪辑“GradientThreshold”作为0.05,并指定“梯度阈值法”使用梯度的l2范数。

initialLearningRate = 0.05;maxEpochs = 150;minibatchSize = 16;l2reg = 0.0001;选择= trainingOptions (“sgdm”...“InitialLearnRate”initialLearningRate,...“动量”, 0.9,...“L2规范化”l2reg,...“MaxEpochs”maxEpochs,...“MiniBatchSize”minibatchSize,...“LearnRateSchedule”“分段”...“洗牌”“every-epoch”...“梯度阈值法”“l2norm”...“GradientThreshold”,0.05,...“阴谋”“培训进度”...“VerboseFrequency”, 20);

培训网络

默认情况下,该示例使用downloadTrainedUnet助手函数。此函数作为支持文件附加到示例中。万博1manbetx预先训练过的网络使您能够运行整个示例,而不必等待训练完成。

要训练网络,请设置doTraining变量为真正的.使用trainNetwork(深度学习工具箱)函数。

如果GPU可用,在GPU上训练。使用GPU需要并行计算工具箱™ 以及支持CUDA®的NVIDIA®GPU。有关更多信息,请参阅GPU版万博1manbetx本支持(并行计算工具箱).在NVIDIA Titan X上训练大约需要20个小时。

doTraining = false;如果doTraining[net,info]=列车网络(dsTrain,lgraph,options);modelDateTime=string(datetime)(“现在”“格式”“yyyy MM dd HH MM ss”));保存(strcat)(“多谱线-,modelDateTime,“-纪元—,num2str(maxEpochs),“.mat”),“净”);其他的培训网网址=“//www.tianjin-qmedu.com/万博1manbetxsupportfiles/vision/data/multispectralUnet.mat”;下载trainedUnet(trainedUnet_url,imageDir);加载(完整文件(imageDir,“trainedUnet”“multispectralUnet.mat”));结束

现在可以使用U-Net对多光谱图像进行语义分割。

预测测试数据的结果

要在经过训练的网络上执行前向传递,请使用辅助函数,分段图像,带有验证数据集。此函数作为支持文件附加到示例中。万博1manbetx分段图像的方法对图像块进行分割semanticseg函数。

predictPatchSize = [1024 1024];segmentedImage = segmentImage (val_data,净,predictPatchSize);

为了只提取分割的有效部分,将分割后的图像乘以验证数据的掩模通道。

segmentedImage = uint8(val_data(:,:,7)~=0) .* segmentedImage;图imshow (segmentedImage,[])标题(“分割图像”

语义分割的输出是有噪声的。执行后期图像处理以去除噪声和杂散像素。使用medfilt2函数从分割中去除椒盐噪声。在去除噪声的情况下可视化分割图像。

segmentedImage = medfilt2 (segmentedImage [7]);imshow (segmentedImage []);标题(“去除噪声的分割图像”

将分割后的图像叠加到直方图均衡化的RGB验证图像上。

B=labeloverlay(histeq(val_数据(:,:,[3 2 1])),分段图像,“透明”, 0.8,“彩色地图”,cmap);图imshow(B)标题(“已标记的验证图像”)色条(“滴答声标签”cellstr(类名),“滴答声”蜱虫,“滴答声长度”,0,“TickLabelInterpreter”“没有”);彩色地图(cmap)

将分割后的图像和ground truth标签保存为PNG文件。这些将用于计算精度度量。

imwrite (segmentedImage“results.png”);imwrite (val_labels“gtruth.png”);

量化分割精度

创建一个pixelLabelDatastore用于分割结果和地面真值标签。

pxdsResults = pixelLabelDatastore (“results.png”,类名,PixelLabelId);pxdsTruth=pixelLabelDatastore(“gtruth.png”,类名,像素标签);

用该方法对语义切分的全局精度进行度量evaluateSemanticSegmentation函数。

舰导弹= evaluateSemanticSegmentation (pxdsResults pxdsTruth,“指标”“global-accuracy”);
评估语义分割结果  ---------------------------------------- * 所选指标:全球精度。*处理1幅图像。*完成……完成了。*数据集指标:GlobalAccuracy ______________ 0.90698

总体精度评分表明,只有超过90%的像素被正确分类。

计算植被覆盖范围

本示例的最终目标是计算多光谱图像中植被覆盖的范围。

找到标记植被的像素数。标签id 2(“Trees”)、13(“LowLevelVegetation”)和14(“Grass_Lawn”)是植被类。并通过对掩模图像感兴趣区域内像素的求和得到有效像素的总数。

vegetationClassIds = uint8([2、13、14]);vegetationPixels = ismember (segmentedImage (:), vegetationClassIds);validPixels = (segmentedImage ~ = 0);numVegetationPixels =总和(vegetationPixels (:));numValidPixels =总和(validPixels (:));

用植被像元数除以有效像元数来计算植被覆盖的百分比。

植被覆盖率=(numvegegationpixels/numValidPixels)*100;fprintf(“植被覆盖百分比是%3.2f%%。”, percentVegetationCover);
植被覆盖率为51.72%。

参考文献

R. Kemker, C. Salvaggio和C. Kanan。用于语义分割的高分辨率多光谱数据集。, abs / 1703.01918。2017.

[2] Ronneberger,O.,P.Fischer和T.Brox.《U-Net:生物医学图像分割的卷积网络》,CoRR,abs/1505.04597.2015。

另请参阅

|||||||(深度学习工具箱)|(深度学习工具箱)

相关的话题

外部网站