语义分割与深度学习
分析训练数据的语义分割
训练一个语义分割网络需要一组图片和相应的像素标记图像的集合。一个像素标记图像是一个图像每个像素值表示像素的分类标签。
下面的代码加载一组小的图片和相应的像素标记图片:
dataDir = fullfile (toolboxdir (“愿景”),“visiondata”);imDir = fullfile (dataDir,“建筑”);pxDir = fullfile (dataDir,“buildingPixelLabels”);
加载图像数据使用imageDatastore
。图像数据存储可以有效地代表了大量的图片,因为图片是只在需要的时候读取到内存中。
imd = imageDatastore (imDir);
读取和显示第一个形象。
I = readimage (imd, 1);图imshow(我)
加载图像像素标签使用pixelLabelDatastore
定义标签id之间的映射和分类名称。在这里使用的数据集,标签是“天空”、“草”、“建筑”,“人行道”。这些类的标签id 1, 2, 3, 4,分别。
定义类名。
一会= [“天空”“草”“建筑”“人行道”];
定义标签ID为每一个类名。
pixelLabelID = (1 2 3 4);
创建一个pixelLabelDatastore
。
一会,pxds = pixelLabelDatastore (pxDir pixelLabelID);
阅读第一个像素标签图像。
C = readimage (pxds, 1);
输出C
是一个分类矩阵在哪里C (i, j)
是像素的分类标签吗我(I, j)
。
C (5,5)
ans =分类天空
覆盖的像素标签图像的不同部分如何图像标记。
B = labeloverlay (C);图imshow (B)
定输出格式可以简化任务,需要通过类名做事。例如,您可以创建一个二进制的面具只是建筑:
buildingMask = C = =“建筑”;图imshowpair (buildingMask,我“蒙太奇”)
创建一个语义分割网络
创建一个简单的语义分割网络,了解常见的层中发现许多语义分割网络。一种常见模式语义分割网络需要将采样图像卷积和ReLU层之间,然后upsample输出与输入的大小。这个操作类似于标准的尺度空间分析使用图像金字塔。然而,在这个过程中使用非线性滤波器优化网络执行操作的一组特定的类你想段。
创建一个图像输入层
语义分割网络从一开始imageInputLayer
,它定义了最小的图像大小网络可以处理。大多数语义分割网络完全卷积,这意味着他们可以处理大于输入指定大小的图像。在这里,一个图像的大小[32 32 3]用于网络处理64 x64 RGB图像。
inputSize = [32 32 3];imgLayer = imageInputLayer (inputSize)
imgLayer = ImageInputLayer属性:名称:“InputSize: [32 32 3] Hyperparameters DataAugmentation:“没有”正常化:“zerocenter”
创建将采样网络
从卷积和ReLU层开始。卷积层填充选择这样的输出大小卷积层输入大小是一样的。这使得它更容易建立一个网络,因为大多数层之间的输入和输出大小保持不变你进步通过网络。
filterSize = 3;numFilters = 32;conv = convolution2dLayer (filterSize numFilters,“填充”1);relu = reluLayer ();
执行将采样使用max池层。创建一个马克斯池层downsample输入2倍通过设置”步
2的参数。
poolSize = 2;maxPoolDownsample2x = maxPooling2dLayer (poolSize,“步”2);
堆栈卷积、ReLU和马克斯池层创建一个网络downsamples其输入的4倍。
downsamplingLayers = [conv relu maxPoolDownsample2x conv relu maxPoolDownsample2x]
downsamplingLayers x1 = 6层阵列层:1“卷积32 3 x3的隆起与步幅[1]和填充1 1 1 1 2”ReLU ReLU 3”麦克斯池2 x2马克斯池步(2 - 2)和填充(0 0 0 0)4”卷积32 3 x3的隆起与步幅[1]和填充[1 1 1 1]5”ReLU ReLU 6”马克斯池2 x2马克斯池步(2 - 2)和填充[0 0 0 0]
创建Upsampling网络
upsampling使用进行转置卷积层(通常也称为“deconv”或“反褶积层)。用于upsampling转置卷积时,它在同一时间执行upsampling和过滤。
创建一个转置卷积upsample 2层。
filterSize = 4;numFilters transposedConvUpsample2x = transposedConv2dLayer(4日,“步”2,“种植”1);
“裁剪”参数设置为1,使输出大小等于输入规模的两倍。
栈转置卷积和relu层。一个输入组层upsampled除以4。
upsamplingLayers = [transposedConvUpsample2x relu transposedConvUpsample2x relu]
upsamplingLayers = 4 x1层与层:数组1“转置卷积32 4 x4转置运算与步幅[2 2]和输出裁剪[1]2”ReLU ReLU 3“转置卷积32 4 x4转置运算与步幅[2 2]和输出裁剪[1]4”ReLU ReLU
创建一个像素分类层
最后一组层负责使像素分类。这最后一层过程的输入,具有相同的空间维度(高度和宽度)作为输入图像。然而,通道的数量(三维)是更大的和等于数量的过滤器在过去转置卷积层。这个第三维度需要挤到类的数量我们希望段。这可以通过使用一个卷积1×1层的过滤器类的数量相等的数量,如3所示。
创建一个卷积层结合的输入特性的三维地图类的数量。
numClasses = 3;conv1x1 = convolution2dLayer (1、numClasses);
以下这个卷积1×1层将softmax和像素分类层。这两层结合预测每个图像像素的分类标签。
pixelClassificationLayer finalLayers = [conv1x1 softmaxLayer () ())
finalLayers = 3 x1层与层:数组1“卷积3 1 x1旋转步[1]和填充[0 0 0 0]2”Softmax Softmax 3”像素分类层叉损失
栈的所有层
栈的所有层完成语义分割网络。
网= [imgLayer downsamplingLayers upsamplingLayers finalLayers]
净= 14 x1层与层:数组1”的形象输入32 x32x3图像zerocenter正常化2”卷积32 3 x3的隆起与步幅[1]和填充[1 1 1 1]3”ReLU ReLU 4”马克斯池2 x2马克斯池步(2 - 2)和填充[0 0 0 0]5“卷积32 3 x3的隆起与步幅[1]和填充1 1 1 1 6”ReLU ReLU 7”麦克斯池2 x2马克斯池步(2 - 2)和填充[0 0 0 0]8”转置卷积32 4 x4转置运算与步幅[2 2]和输出裁剪[1]9”ReLU ReLU 10”转置卷积32 4 x4转置运算与步幅[2 2]和输出裁剪[1]11“ReLU ReLU 12“卷积3 1 x1旋转步[1]和填充[0 0 0 0]13“Softmax Softmax 14“像素分类层叉损失
这个网络已经准备好被训练使用trainNetwork
从深度学习工具箱™。
火车一个语义分割网络
加载训练数据。
dataSetDir = fullfile (toolboxdir (“愿景”),“visiondata”,“triangleImages”);imageDir = fullfile (dataSetDir,“trainingImages”);labelDir = fullfile (dataSetDir,“trainingLabels”);
创建一个图像的图像数据存储。
imd = imageDatastore (imageDir);
创建一个pixelLabelDatastore
地面真理像素标签。
一会= [“三角形”,“背景”];labelIDs = (255 0);一会,pxds = pixelLabelDatastore (labelDir labelIDs);
想象训练图像和地面实况像素标签。
我=读(imd);C =阅读(pxds);I = imresize (5);L = imresize (uint8 (C {1}), 5);imshowpair (L,我“蒙太奇”)
创建一个语义分割网络。这个网络使用一个简单的语义分割网络基于一个将采样和upsampling设计。
numFilters = 64;filterSize = 3;numClasses = 2;32 32层= [imageInputLayer ([1]) convolution2dLayer (filterSize numFilters,“填充”(1)reluLayer) maxPooling2dLayer (2,“步”(2)convolution2dLayer filterSize numFilters,“填充”(1)reluLayer) transposedConv2dLayer (4 numFilters“步”2,“种植”1);numClasses convolution2dLayer(1日);pixelClassificationLayer softmaxLayer () ()];
设置培训选项。
选择= trainingOptions (“个”,…“InitialLearnRate”1 e - 3,…“MaxEpochs”,100,…“MiniBatchSize”,64);
结合图像和像素标签数据存储进行训练。
pxds trainingData =结合(imd);
培训网络。
网= trainNetwork (trainingData层,选择);
培训在单CPU。初始化输入数据规范化。| = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = | | | |时代迭代时间| Mini-batch | Mini-batch |基地学习| | | | (hh: mm: ss) | | |损失精度率| | = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = | | 1 | 1 |就是58.11% | | 1.3458 | 0.0010 | | 17 | 50 | 00:00:12 | 97.30% | 0.0924 | 0.0010 | | 100 | | 00:00:24 | 98.09% | 0.0575 | 0.0010 | | 150 | | 00:00:37 | 98.56% | 0.0424 | 0.0010 | 67 | 200 | | 00:00:49 | 98.48% | 0.0435 | 0.0010 | 84 | 250 | | 00:01:02 | 98.66% | 0.0363 | 0.0010 | 100 | 300 | | 00:01:14 | 98.90% | 0.0310 | 0.0010 | | = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = |培训完成:达到最终的迭代。
读取和显示测试图像。
testImage = imread (“triangleTest.jpg”);imshow (testImage)
段测试图像和显示结果。
C = semanticseg (testImage,净);B = labeloverlay (testImage C);imshow (B)
评估和检查语义分割的结果
导入测试数据集运行pretrained语义分割网络,并评估和检查语义分割质量指标预测结果。
导入一个数据集
的triangleImages
数据集与地面实况100个测试图像标签。定义数据集的位置。
dataSetDir = fullfile (toolboxdir (“愿景”),“visiondata”,“triangleImages”);
定义测试图像的位置。
testImagesDir = fullfile (dataSetDir,“testImages”);
创建一个imageDatastore
对象的测试图像。
imd = imageDatastore (testImagesDir);
定义地面实况标签的位置。
testLabelsDir = fullfile (dataSetDir,“testLabels”);
定义类名和它们相关的标签id。标签图像文件中使用的id是像素值来表示每个类。
一会= [“三角形”“背景”];labelIDs = (255 0);
创建一个pixelLabelDatastore
对象持有的地面实况像素标签测试图像。
一会,pxdsTruth = pixelLabelDatastore (testLabelsDir labelIDs);
运行一个语义分割分类器
加载一个语义分割网络训练的训练图像triangleImages
。
网=负载(“triangleSegmentationNetwork.mat”);网= net.net;
运行网络测试图像。预测标签在一个临时目录中写入磁盘和作为一个返回pixelLabelDatastore
对象。
pxdsResults = semanticseg (imd,净,“WriteLocation”,tempdir);
运行的语义分割网络- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 100张图片处理。
评估预测的质量
预测的标签比地面实况标签。而语义细分指标计算,进步是打印到命令窗口。
指标= evaluateSemanticSegmentation (pxdsResults pxdsTruth);
评估语义分割结果- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *选定指标:全球准确性、类准确性,借据,加权借据,BF的分数。* 100(加工)图像。*完成……完成了。*数据集指标:GlobalAccuracy MeanAccuracy MeanIoU WeightedIoU _______ MeanBFScore * * *…………0.90624 0.95085 - 0.61588 0.87529 - 0.40652
检查类指标
显示分类精度,在联盟(借据)十字路口,边界f - 1得分为每个类数据集。
metrics.ClassMetrics
ans =2×3表准确性借据MeanBFScore ________ _________ ___________三角形1 0.33005 0.028664 0.9017 0.9017 0.78438背景
显示混淆矩阵
显示混合矩阵。
metrics.ConfusionMatrix
ans =2×2表三角形背景________ __________三角形背景9601 88069 4730 0
可视化规范化混淆矩阵作为一个混乱图在图窗口。
厘米= confusionchart (metrics.ConfusionMatrix.Variables,…一会,正常化=“row-normalized”);厘米。Title =“规范化混淆矩阵(%)”;
检查图像度量
可视化每张图象的直方图交叉在联盟(借据)。
imageIoU = metrics.ImageMetrics.MeanIoU;图直方图(imageIoU)标题(图片的意思是借据的)
找到最低的测试图像借据。
[minIoU, worstImageIndex] = min (imageIoU);minIoU = minIoU (1);worstImageIndex = worstImageIndex (1);
阅读测试图像与最坏的借据,地面真值标签,和预测标签进行比较。
worstImageIndex worstTestImage = readimage (imd);worstTrueLabels = readimage (pxdsTruth worstImageIndex);worstPredictedLabels = readimage (pxdsResults worstImageIndex);
标签图像转换为图像,可以在图中显示窗口。
worstTrueLabelImage = im2uint8 ((1) worstTrueLabels = =类名);worstPredictedLabelImage = im2uint8 ((1) worstPredictedLabels = =类名);
显示最糟糕的测试图像,地面实况,预测。
worstMontage =猫(4 worstTestImage worstTrueLabelImage worstPredictedLabelImage);worstMontage = imresize (worstMontage 4“最近的”);图蒙太奇(worstMontage,“大小”3[1])标题([“测试图像与真理与预测。借据= 'num2str (minIoU)))
同样,找到最高的测试图像借据。
[maxIoU, bestImageIndex] = max (imageIoU);maxIoU = maxIoU (1);bestImageIndex = bestImageIndex (1);
重复前面的步骤以读取、转换和显示测试图像与最好的借据地面实况和预测标签。
bestImageIndex bestTestImage = readimage (imd);bestTrueLabels = readimage (pxdsTruth bestImageIndex);bestPredictedLabels = readimage (pxdsResults bestImageIndex);bestTrueLabelImage = im2uint8 ((1) bestTrueLabels = =类名);bestPredictedLabelImage = im2uint8 ((1) bestPredictedLabels = =类名);bestMontage =猫(4 bestTestImage bestTrueLabelImage bestPredictedLabelImage);bestMontage = imresize (bestMontage 4“最近的”);图蒙太奇(bestMontage,“大小”3[1])标题([“测试图像与真理与预测。借据= 'num2str (maxIoU)))
指定指标来评估
可选地,列出指标(s)你想评估使用“指标”
参数。
定义度量来计算。
evaluationMetrics = [“准确性”“借据”];
计算这些指标triangleImages
测试数据集。
指标= evaluateSemanticSegmentation (pxdsResults pxdsTruth,“指标”,evaluationMetrics);
评估语义分割结果- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *选定指标:类准确性,借据。* 100(加工)图像。*完成……完成了。*数据集指标:MeanAccuracy MeanIoU _______ 0.95085 - 0.61588
显示所选的指标为每一个类。
metrics.ClassMetrics
ans =2×2表准确性借据________三角形1 0.33005背景0.9017 - 0.9017
进口像素标记数据集语义分割
这个例子向您展示了如何导入一个像素标记为语义分割网络数据集。
一个像素标记数据集是一组图片和相应的地面真理像素标签语义分割用于训练网络。有许多公共数据集提供注释图像逐像素标签。为了说明的步骤导入这些类型的数据集,本例使用CamVid数据集来自剑桥大学的[1]。
CamVid数据集是一组包含开车时街面视图获得的图像。数据集提供了进行像素级标签32语义类包括汽车、行人、道路。所示的步骤导入CamVid可以用来导入其他像素标记数据集。
下载CamVid数据集
从以下网址下载CamVid图像数据:
imageURL =“http://web4.cs.ucl.ac.uk/staff/g.brostow/MotionSegRecData/files/701_StillsRaw_full.zip”;labelURL =“http://web4.cs.ucl.ac.uk/staff/g.brostow/MotionSegRecData/data/LabeledApproved_full.zip”;outputFolder = fullfile (tempdir,“CamVid”);imageDir = fullfile (outputFolder,“图片”);labelDir = fullfile (outputFolder,“标签”);如果~存在(outputFolder“dir”)disp (“下载557 MB CamVid数据集…”);解压缩(imageURL imageDir);解压缩(labelURL labelDir);结束
注意:下载数据的时间取决于您的网络连接。上面使用的命令将阻止MATLAB®直到下载完成。或者,您可以使用web浏览器来第一个数据下载到您的本地磁盘。用你从网上下载的文件,更改outputFolder
变量上面下载的文件的位置。
CamVid像素标签
CamVid数据编码的像素标签设置为RGB图像,其中每个类是由RGB颜色。以下是数据集的类定义以及它们的RGB编码。
一会= […“动物”,…“拱门”,…“自行车”,…“桥”,…“建筑”,…“汽车”,…“CartLuggagePram”,…“子”,…“Column_Pole”,…“篱笆”,…“LaneMkgsDriv”,…“LaneMkgsNonDriv”,…“Misc_Text”,…“MotorcycleScooter”,…“OtherMoving”,…“ParkingBlock”,…“行人”,…“路”,…“RoadShoulder”,…“人行道”,…“SignSymbol”,…“天空”,…“SUVPickupTruck”,…“TrafficCone”,…“TrafficLight”,…“训练”,…“树”,…“Truck_Bus”,…“隧道”,…“VegetationMisc”,…“墙”];
定义标签等指数和类名之间的映射类名(k)
对应于labelIDs (k,:)
。
labelIDs = […064 128 064;…%的“动物”192 000 128;…%的“拱门”000 128 192;…%“自行车”000 128 064;…%“桥”128 000 000;…%“建设”064 000 128;…%的“汽车”064 000 192;…%”CartLuggagePram”192 128 064;…%的“孩子”192 192 128;…%”Column_Pole”064 064 128;…%“栅栏”128 000 192;…%”LaneMkgsDriv”192 000 064;…%”LaneMkgsNonDriv”128 128 064;…%”Misc_Text”192 000 192;…%”MotorcycleScooter”128 064 064;…%”OtherMoving”064 192 128;…%”ParkingBlock”064 064 000;…%“行人”128 064 128;…%的“路”128 128 192;…%”RoadShoulder”000 000 192;…%“人行道”192 128 128;…%”SignSymbol”128 128 128;…%的“天空”064 128 192;…%”SUVPickupTruck”000 000 064;…%”TrafficCone”000 064 064;…%”TrafficLight”192 064 128;…%“训练”128 128 000;…%的“树”192 128 192;…%”Truck_Bus”064 000 064;…%的“隧道”192 192 000;…%”VegetationMisc”064 192 000];%的“墙”
注意,其他数据集有不同的编码格式的数据。例如,帕斯卡VOC[2]数据集使用数字标签id 0到21之间编码它们的类标签。
可视化CamVid图像的像素标签。
标签= imread (fullfile (labelDir,0001 tp_006690_l.png));图imshow(标签)%添加colorbar展示类颜色映射。N =元素个数(类名);蜱虫= 1 / (N * 2): 1 / N: 1;colorbar (“TickLabels”cellstr(类名),“滴答”蜱虫,“TickLength”0,“TickLabelInterpreter”,“没有”);colormap (labelIDs. / 255)
CamVid数据加载
一个像素标记数据集可以加载使用imageDatastore
和一个pixelLabelDatastore
。
创建一个imageDatastore
加载CamVid图像。
imd = imageDatastore (fullfile (imageDir701 _stillsraw_full));
创建一个pixelLabelDatastore
加载CamVid像素标签。
一会,pxds = pixelLabelDatastore (labelDir labelIDs);
读第十图像和相应的像素标签图像。
I = readimage (imd, 10);C = readimage (pxds 10);
像素标签图像作为分类数组,返回C (i, j)
是分配给像素的分类标签我(I, j)
。显示图像的图像像素标签。
我= labeloverlay (C“Colormap”,labelIDs. / 255);图imshow (B)%添加colorbar。N =元素个数(类名);蜱虫= 1 / (N * 2): 1 / N: 1;colorbar (“TickLabels”cellstr(类名),“滴答”蜱虫,“TickLength”0,“TickLabelInterpreter”,“没有”);colormap (labelIDs. / 255)
未定义或空白标签
是常见的像素标记数据集包括“定义”或“无效”的标签。这些都是用来指定像素没有标记。CamVid,例如标签ID(0 0 0)是用于指定“空白”类。训练算法和评价算法不将这些标签包含在任何计算。
“空白”类不需要显式指定的使用时pixelLabelDatastore
。任何标签ID不映射到一个类名自动标记为“定义”,是被排除在计算。看到未定义像素,使用isundefined
创建一个面具,然后显示它的形象。
undefinedPixels = isundefined (C);B = labeloverlay(我undefinedPixels);图imshow (B)标题(“未定义像素标签”)
结合类
使用公共数据集时,您可能需要将一些类来更好地满足您的应用程序。例如,您可能想训练的语义分割网络场景分成4类:路,天空,车辆,行人,和背景。为此CamVid数据集,上面定义的标签id以适应新课程。首先,定义新类的名称。
newClassNames = [“路”,“天空”,“汽车”,“行人”,“背景”];
接下来,使用细胞组标签id数组M-by-3矩阵。
groupedLabelIDs = {%的道路(128 064 128;…%的“路”128 000 192;…%”LaneMkgsDriv”192 000 064;…%”LaneMkgsNonDriv”000 000 192;…%“人行道”064 192 128;…%”ParkingBlock”128 128 192;…%”RoadShoulder”]%的“天空”(128 128 128;…%的“天空”]%“车辆”(064 000 128;…%的“汽车”064 128 192;…%”SUVPickupTruck”192 128 192;…%”Truck_Bus”192 064 128;…%“训练”000 128 192;…%“自行车”192 000 192;…%”MotorcycleScooter”128 064 064;…%”OtherMoving”]%“行人”(064 064 000;…%“行人”192 128 064;…%的“孩子”064 000 192;…%”CartLuggagePram”064 128 064;…%的“动物”]%的“背景”(128 128 000;…%的“树”192 192 000;…%”VegetationMisc”192 128 128;…%”SignSymbol”128 128 064;…%”Misc_Text”000 064 064;…%”TrafficLight”064 064 128;…%“栅栏”192 192 128;…%”Column_Pole”000 000 064;…%”TrafficCone”000 128 064;…%“桥”128 000 000;…%“建设”064 192 000;…%的“墙”064 000 064;…%的“隧道”192 000 128;…%的“拱门”]};
创建一个pixelLabelDatastore
使用新的类和标签id。
pxds = pixelLabelDatastore (labelDir newClassNames groupedLabelIDs);
读10像素标签图像并显示它的形象。
C = readimage (pxds 10);提出=喷气(元素个数(newClassNames));我= labeloverlay (C“Colormap”,提出);图imshow (B)%添加colorbarN =元素个数(newClassNames);蜱虫= 1 / (N * 2): 1 / N: 1;colorbar (“TickLabels”cellstr (newClassNames),“滴答”蜱虫,“TickLength”0,“TickLabelInterpreter”,“没有”);colormap城市规划机构(cmap)
的pixelLabelDatastore
新类名现在可以用于训练网络的4类,而无需修改原始CamVid像素标签。
引用
加布里埃尔·[1]Brostow J。,Julien Fauqueur, and Roberto Cipolla. "Semantic object classes in video: A high-definition ground truth database."模式识别的字母30.2 (2009):88 - 97。
[2]Everingham, M。,等。2012年“帕斯卡视觉对象类的挑战的结果。”见http://www。pascal-network。org/challenges/VOC/voc2012/workshop/index。html。卷。5。2012年。