基于深度学习的多光谱图像语义分割
这个例子展示了如何使用U-Net对一个多光谱图像的七通道进行语义分割。
语义分割涉及到用类对图像中的每个像素进行标记。语义分割的一个应用是跟踪森林砍伐,即随着时间的推移森林覆盖的变化。环境机构通过跟踪森林砍伐来评估和量化一个地区的环境和生态健康状况。
基于深度学习的语义分割可以从高分辨率航拍照片中得到植被覆盖的精确测量。其中一个挑战是区分具有相似视觉特征的类,例如试图将一个绿色像素分类为草、灌木或树。为了提高分类精度,一些数据集包含多光谱图像,这些图像提供了关于每个像素的额外信息。例如,哈姆林海滩州立公园数据集用三个近红外通道补充了彩色图像,提供了更清晰的类别分离。
这个例子首先向你展示了如何使用预训练的U-Net进行语义分割,然后使用分割结果计算植被覆盖的程度。然后,你可以选择在Hamlin Beach State Parck数据集上使用基于补丁的训练方法训练一个U-Net网络。
下载数据集
本例使用高分辨率多光谱数据集来训练网络[1]。这组图像是用无人机在纽约哈姆林海滩州立公园上空拍摄的。数据包含有标记的训练、验证和测试集,有18个对象类标签。数据文件的大小为3.0 GB。
下载mat文件版本的数据集使用downloadHamlinBeachMSIData
helper函数。该函数作为支持文件附加到示例中。指定dataDir
作为数据的期望位置。
dataDir = fullfile (tempdir,“rit18_data”);downloadHamlinBeachMSIData (dataDir);
加载数据集。
负载(fullfile (dataDir“rit18_data.mat”));谁train_dataval_datatest_data
Name Size Bytes Class Attributes test_data 7x12446x7654 1333663576 uint16 train_data 7x9393x5642 741934284 uint16 val_data 7x8833x6918 855493716 uint16
多光谱图像数据排列为numChannels——- - - - - -宽度——- - - - - -高度数组。然而,在MATLAB®中,多通道图像被排列为宽度——- - - - - -高度——- - - - - -numChannels数组。要重塑数据,使通道处于第三维,请使用switchChannelsToThirdPlane
helper函数。该函数作为支持文件附加到示例中。
train_data = switchChannelsToThirdPlane (train_data);val_data = switchChannelsToThirdPlane (val_data);test_data = switchChannelsToThirdPlane (test_data);
确认数据结构正确。
谁train_dataval_datatest_data
名称大小字节类属性test_data 12446x7654x7 1333663576 uint16 train_data 9393x5642x7 741934284 uint16 val_data 8833x6918x7 855493716 uint16
将训练数据保存为MAT文件,将训练标签保存为PNG文件。这样可以方便地使用imageDatastore
和一个pixelLabelDatastore
在培训。
保存(“train_data.mat”,“train_data”);imwrite (train_labels“train_labels.png”);
多光谱数据可视化
在这个数据集中,RGB颜色通道是第三、第二和第一个图像通道。以蒙太奇的形式显示训练、验证和测试图像的颜色成分。要使图像在屏幕上显得更亮,可以使用histeq
函数。
图蒙太奇(…{histeq (train_data (:,: [3 2 1])),…histeq (val_data (:,:, (3 2 1))),…histeq (test_data (:,:, (3 2 1)))},…BorderSize = 10,写成BackgroundColor =“白色”)标题(“RGB Component of Training, Validation, and Test Image(从左到右)”)
以蒙太奇的形式显示训练数据的最后三个直方图均衡化通道。这些通道对应于近红外波段,并根据其热特征突出显示图像的不同成分。例如,第二通道图像中心附近的树比其他两个通道中的树显示出更多的细节。
图蒙太奇(…{histeq (train_data (:: 4)), histeq (train_data (:,:, 5)), histeq (train_data (:,: 6)},…BorderSize = 10,写成BackgroundColor =“白色”)标题(“训练图像IR通道1、2、3(从左到右)”)
Channel 7是表示有效分割区域的掩码。显示训练、验证和测试图像的掩码。
图蒙太奇(…{train_data (:: 7), val_data (:,: 7), test_data (:,: 7)},…BorderSize = 10,写成BackgroundColor =“白色”)标题(“训练、验证和测试图像的面具(从左到右)”)
可视化Ground Truth标签
标记的图像包含分割的地面真相数据,每个像素分配给18个类中的一个。获取一个类的列表,以及它们对应的id。
disp(类)
0.其他类/图像边界1.;路标2。树3。建设4。交通工具(小汽车、卡车或公共汽车)6人。救生员椅7。野餐的好表8。黑色木板9.; White Wood Panel 10. Orange Landing Pad 11. Water Buoy 12. Rocks 13. Other Vegetation 14. Grass 15. Sand 16. Water (Lake) 17. Water (Pond) 18. Asphalt (Parking Lot/Walkway)
创建一个类名向量。
一会= [“路标”,“树”,“建筑”,“汽车”,“人”,…“LifeguardChair”,“PicnicTable”,“BlackWoodPanel”,…“WhiteWoodPanel”,“OrangeLandingPad”,“浮”,“石头”,…“LowLevelVegetation”,“Grass_Lawn”,“Sand_Beach”,…“Water_Lake”,“Water_Pond”,“沥青”];
将标签覆盖在直方图均衡化的RGB训练图像上。在图像上添加一个颜色条。
提出=喷气(元素个数(类名);B = labeloverlay (histeq (train_data (:,: 4:6)), train_labels,透明度= 0.8,Colormap =提出);图imshow (B)标题(“培训”标签) N = numel(classNames);蜱虫= 1 / (N * 2): 1 / N: 1;colorbar (TickLabels = cellstr(类名),蜱虫=蜱虫,TickLength = 0, TickLabelInterpreter =“没有”);colormap城市规划机构(cmap)
执行语义分割
下载一个预先训练的U-Net网络。
trainedUnet_url =“//www.ru-cchi.com/supportfiles/vision/data/multispectralUnet.mat”;downloadTrainedNetwork (trainedUnet_url dataDir);负载(fullfile (dataDir“multispectralUnet.mat”));
要在训练过的网络上执行语义分割,可以使用segmentMultispectralImage
验证数据的助手功能。该函数作为支持文件附加到示例中。的segmentMultispectralImage
函数对图像补丁执行分割semanticseg
函数。处理补丁是必需的,因为图像的大小阻止了一次处理整个图像。
predictPatchSize = [1024 1024];segmentedImage = segmentMultispectralImage (val_data,净,predictPatchSize);
为了只提取分割的有效部分,将分割后的图像乘以验证数据的掩码通道。
segmentedImage = uint8(val_data(:,:,7)~=0) .* segmentedImage;图imshow (segmentedImage,[])标题(“分割图像”)
语义分割的输出是噪声的。进行图像后期处理,去除噪声和杂散像素。使用medfilt2
函数从分割中去除盐和胡椒噪声。可视化去噪后的分割图像。
segmentedImage = medfilt2 (segmentedImage [7]);imshow (segmentedImage []);标题(“去除噪声的分割图像”)
将分割后的图像覆盖在直方图均衡化的RGB验证图像上。
B = labeloverlay(histeq(val_data(:,:,[3 2 1])),segmentedImage,透明度=0.8,Colormap=cmap);图imshow (B)标题(“标记分割图像”) colorbar (TickLabels = cellstr(类名),蜱虫=蜱虫,TickLength = 0, TickLabelInterpreter =“没有”);colormap城市规划机构(cmap)
计算植被覆盖范围
语义分割结果可用于回答相关的生态问题。例如,被植被覆盖的土地面积的百分比是多少?要回答这个问题,找到标记植被的像素数。标签id 2(“Trees”)、13(“LowLevelVegetation”)和14(“Grass_Lawn”)是植被类。还可以通过对掩码图像ROI中的像素相加,找到有效像素的总数。
vegetationClassIds = uint8([2、13、14]);vegetationPixels = ismember (segmentedImage (:), vegetationClassIds);validPixels = (segmentedImage ~ = 0);numVegetationPixels =总和(vegetationPixels (:));numValidPixels =总和(validPixels (:));
用植被像素数除以有效像素数,计算植被覆盖百分比。
percentVegetationCover = (numVegetationPixels / numValidPixels) * 100;流(“植被覆盖率百分比为%3.2f%%。”, percentVegetationCover);
植被覆盖率为51.72%。
剩下的例子向你展示了如何在Hamlin Beach数据集上训练U-Net。
创建随机补丁提取数据存储进行训练
使用随机补丁提取数据存储将训练数据输入到网络中。该数据存储从包含地面真实图像和像素标签数据的图像数据存储和像素标签数据存储中提取多个相应的随机补丁。补丁是一种常见的技术,可以防止大图像的内存耗尽,并有效增加可用的训练数据量。
从“下载训练图像”开始train_data.mat”
在一个imageDatastore
。因为MAT文件格式是非标准图像格式,必须使用MAT文件读取器才能读取图像数据。你可以使用辅助MAT文件读取器,matRead6Channels
,它从训练数据中提取出前六个通道,并省略了最后一个包含掩码的通道。该函数作为支持文件附加到示例中。
imd = imageDatastore (“train_data.mat”FileExtensions =“.mat”ReadFcn = @matRead6Channels);
创建一个pixelLabelDatastore
来存储包含18个标记区域的标签补丁。
pixelLabelIds = 1:18;pxds = pixelLabelDatastore (“train_labels.png”一会,pixelLabelIds);
创建一个randomPatchExtractionDatastore
来自图像数据存储和像素标签数据存储。每个小批包含16个大小为256 × 256像素的补丁。在历元的每次迭代中提取1000个小批次。
pxds dsTrain = randomPatchExtractionDatastore (imd, [256256], PatchesPerImage = 16000);
随机补丁抽取数据存储dsTrain
在the 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分类}{256×256×6 uint16}{256×256分类}
创建U-Net网络层
这个例子使用了U-Net网络的一个变体。在U-Net中,初始的卷积层系列中穿插着最大池化层,依次降低了输入图像的分辨率。在这些层之后,再穿插上采样算子的一系列卷积层,依次增加输入图像的分辨率[2]。U- net的名字来源于这样一个事实:网络可以画出一个像字母U一样的对称形状。
这个例子修改U-Net在卷积中使用零填充,这样卷积的输入和输出具有相同的大小。使用helper函数,createUnet
,创建一个带有一些预选超参数的U-Net。该函数作为支持文件附加到示例中。
inputTileSize = (256256 6);lgraph = createUnet (inputTileSize);disp (lgraph.Layers)
58×1带有图层的图层数组:1“ImageInputLayer”图像输入图像256×256×6”zerocenter正常化2 Encoder-Section-1-Conv-1卷积64 3×3×6旋转步[1]和填充[1 1 1 1]3‘Encoder-Section-1-ReLU-1 ReLU ReLU 4 Encoder-Section-1-Conv-2卷积64 3×3×64旋转步[1]和填充[1 1 1 1]5‘Encoder-Section-1-ReLU-2 ReLU ReLU 6“Encoder-Section-1-MaxPool”马克斯池2×2马克斯池步(2 - 2)和填充[0 0 0 0]7“Encoder-Section-2-Conv-1”卷积128 3×3×64旋转步[1]和填充(1 1 1)8“Encoder-Section-2-ReLU-1”ReLU ReLU 9 Encoder-Section-2-Conv-2卷积128 3×3×128旋转步[1]和填充[1 1 1 1]10 ' Encoder-Section-2-ReLU-2 ReLU ReLU 11“Encoder-Section-2-MaxPool”马克斯池2×2马克斯池步(2 - 2)和填充[0 0 0 0]12 Encoder-Section-3-Conv-1卷积256 3×3×128旋转步[1]和填充[1 1 1 1]13“Encoder-Section-3-ReLU-1”ReLU ReLU 14 Encoder-Section-3-Conv-2卷积256 3×3×256旋转步[1]和填充[1 1 1 1]15 ' Encoder-Section-3-ReLU-2 ReLU ReLU 16“Encoder-Section-3-MaxPool”马克斯池2×2马克斯池步(2 - 2)和填充[0 0 0 0]17 Encoder-Section-4-Conv-1卷积512 3×3×256旋转步[1]和填充[1 1 1 1]18 ' Encoder-Section-4-ReLU-1 ReLU ReLU 19 Encoder-Section-4-Conv-2卷积512 3×3×512旋转步[1]和填充[1 1 1 1] 20 ' Encoder-Section-4-ReLU-2 ReLU ReLU 21“Encoder-Section-4-DropOut”辍学50%辍学22“Encoder-Section-4-MaxPool”马克斯池2×2马克斯池步(2 - 2)和填充[0 0 0 0]23 Mid-Conv-1卷积1024 3×3×512旋转步[1]和填充[1 1 1 1]24的Mid-ReLU-1 ReLU ReLU 25 Mid-Conv-2卷积1024 3×3×1024旋转步[1]和填充[1 1 1 1]26 ' Mid-ReLU-2 ReLU ReLU 27“Mid-DropOut”辍学辍学28 50%Decoder-Section-1-UpConv转置卷积512 2×2×1024转置运算跨2[2]和裁剪[0 0 0 0]29的Decoder-Section-1-UpReLU ReLU ReLU 30的Decoder-Section-1-DepthConcatenation深度连接深度连接2输入31 Decoder-Section-1-Conv-1卷积512 3×3×1024旋转步[1]和填充[1 1 1 1]32的Decoder-Section-1-ReLU-1 ReLU ReLU 33 Decoder-Section-1-Conv-2卷积512 3×3×512旋转步[1]和填充[1 1 1 1]34 ' Decoder-Section-1-ReLU-2 ReLU ReLU 35 Decoder-Section-2-UpConv转置卷积256 2×2×512转置运算跨2[2]和裁剪[0 0 0 0]36的Decoder-Section-2-UpReLU ReLU ReLU 37 Decoder-Section-2-DepthConcatenation的深度连接深度连接2输入38 Decoder-Section-2-Conv-1卷积256 3×3×512旋转步[1]和填充[1 1 1 1]39的Decoder-Section-2-ReLU-1 ReLU ReLU 40“Decoder-Section-2-Conv-2”卷积256 3×3×256旋转步[1]和填充(1 1 1)41 ' Decoder-Section-2-ReLU-2 ReLU ReLU 42 Decoder-Section-3-UpConv转置卷积128 2×2×256转置运算跨2[2]和裁剪[0 0 0 0]43的Decoder-Section-3-UpReLU ReLU ReLU 44的Decoder-Section-3-DepthConcatenation深度连接深度连接2输入45‘Decoder-Section-3-Conv-1卷积128 3×3×256旋转步[1]和填充[1 1 1 1]46‘Decoder-Section-3-ReLU-1 ReLU ReLU 47 Decoder-Section-3-Conv-2卷积128 3×3×128旋转步[1]和填充[1 1 1 1]48 ' Decoder-Section-3-ReLU-2 ReLU ReLU 49 Decoder-Section-4-UpConv转置卷积64 2×2×128转置运算跨2[2]和种植50[0 0 0 0]的Decoder-Section-4-UpReLU ReLU ReLU 51的Decoder-Section-4-DepthConcatenation深度连接深度连接2输入52 Decoder-Section-4-Conv-1卷积64 3×3×128旋转步[1]和填充[1 1 1 1]53的Decoder-Section-4-ReLU-1 ReLU ReLU 54 Decoder-Section-4-Conv-2卷积64 3×3×64旋转步[1]和填充[1 1 1 1]55的Decoder-Section-4-ReLU-2 ReLU ReLU 56 Final-ConvolutionLayer的卷积18 1×1×64旋转步[1]和填充[0 0 0 0]57 ' Softmax-Layer Softmax Softmax 58 Segmentation-Layer的像素分类层叉损失
选择培训选项
使用带有动量(SGDM)优化的随机梯度下降训练网络。的方法指定SGDM的超参数设置trainingOptions
(深度学习工具箱)函数。
训练一个深度网络是耗时的。通过指定较高的学习率来加速训练。然而,这可能导致网络的梯度爆发或不受控制地增长,阻止网络训练成功。要将梯度保持在有意义的范围内,可以通过指定“GradientThreshold”
作为0.05
,并指定“GradientThresholdMethod”
使用梯度的l2范数。
initialLearningRate = 0.05;maxEpochs = 150;minibatchSize = 16;l2reg = 0.0001;选择= trainingOptions (“个”,…InitialLearnRate = initialLearningRate,…动量= 0.9,…L2Regularization = l2reg,…MaxEpochs = MaxEpochs,…MiniBatchSize = MiniBatchSize,…LearnRateSchedule =“分段”,…洗牌=“every-epoch”,…GradientThresholdMethod =“l2norm”,…GradientThreshold = 0.05,…情节=“训练进步”,…VerboseFrequency = 20);
训练网络或下载预训练网络
要训练网络,请设置doTraining
变量在以下代码中真正的
。训练模型使用trainNetwork
(深度学习工具箱)函数。
如果有可用的GPU,可以使用它进行训练。使用GPU需要并行计算工具箱™和CUDA®支持的NVIDIA®GPU。有关更多信息,请参见GPU计算的需求(并行计算工具箱)。在NVIDIA Titan X上训练大约需要20个小时。
doTraining = false;如果doTraining net = trainNetwork(dsTrain,lgraph,options);modelDateTime =字符串(datetime (“现在”格式=“yyyy-MM-dd-HH-mm-ss”));保存(fullfile (dataDir“multispectralUnet——”+ modelDateTime +“.mat”),“净”);结束
评估细分精度
对验证数据进行分段。
segmentedImage = segmentMultispectralImage (val_data,净,predictPatchSize);
将分割后的图像和ground truth标签保存为PNG文件。该示例使用这些文件来计算精度指标。
imwrite (segmentedImage“results.png”);imwrite (val_labels“gtruth.png”);
装载分割结果和地面真相使用pixelLabelDatastore
。
pxdsResults = pixelLabelDatastore (“results.png”一会,pixelLabelIds);pxdsTruth = pixelLabelDatastore (“gtruth.png”一会,pixelLabelIds);
度量语义分割的全局准确性,使用evaluateSemanticSegmentation
函数。
舰导弹= evaluateSemanticSegmentation (pxdsResults pxdsTruth,指标=“global-accuracy”);
评估语义分割结果 ---------------------------------------- * 所选指标:全球精度。*处理1张图像。*完成……完成了。*数据集指标:GlobalAccuracy ______________ 0.90411
全局精度评分表明,刚刚超过90%的像素被正确分类。
参考文献
[1] Kemker, R., C. Salvaggio,和C. Kanan。“用于语义分割的高分辨率多光谱数据集。”, abs / 1703.01918。2017.
[2] Ronneberger, O., P. Fischer,和T. Brox。《U-Net:用于生物医学图像分割的卷积网络》。, abs / 1505.04597。2015.
另请参阅
trainingOptions
(深度学习工具箱)|trainNetwork
(深度学习工具箱)|randomPatchExtractionDatastore
|pixelLabelDatastore
|semanticseg
|evaluateSemanticSegmentation
|imageDatastore
|histeq
|unetLayers
相关的话题
- 使用深度学习的语义分割入门
- 使用深度学习的语义分割
- 深度学习的数据存储(深度学习工具箱)