Семантические примеры сегментации

Анализируйте данные тренировки для семантической сегментации

Чтобы обучить семантическую сеть сегментации, вам нужны набор изображений и его соответствующий набор пикселя маркированные изображения. Маркированное изображение пикселя является изображением, где каждое пиксельное значение представляет категориальную метку того пикселя.

Следующий код загружает маленький набор изображений и их соответствующего пикселя маркированные изображения:

dataDir = fullfile(toolboxdir('vision'),'visiondata');
imDir = fullfile(dataDir,'building');
pxDir = fullfile(dataDir,'buildingPixelLabels');

Загрузите данные изображения с помощью imageDatastore. Datastore изображений может эффективно представлять большое количество изображений, потому что изображения только читаются в память при необходимости.

imds = imageDatastore(imDir);

Считайте и отобразите первое изображение.

I = readimage(imds,1);
figure
imshow(I)

Загрузите пиксельные изображения метки с помощью pixelLabelDatastore, чтобы задать отображение между меткой IDs и категориальными именами. В наборе данных, используемом здесь, метки являются "небом", "травой", "созданием" и "тротуаром". Метка IDs для этих классов равняется 1, 2, 3, 4, соответственно.

Задайте имена классов.

classNames = ["sky" "grass" "building" "sidewalk"];

Задайте метку ID для каждого имени класса.

pixelLabelID = [1 2 3 4];

Создайте pixelLabelDatastore.

pxds = pixelLabelDatastore(pxDir,classNames,pixelLabelID);

Считайте первое пиксельное изображение метки.

C = readimage(pxds,1);

Вывод C является категориальной матрицей, где C(i,j) является категориальной меткой пикселя I(i,j).

C(5,5)
ans = categorical
     sky 

Наложите пиксельные метки на изображении, чтобы видеть, как различные части изображения маркированы.

B = labeloverlay(I,C);
figure
imshow(B)

Категориальный выходной формат упрощает задачи, которые требуют выполнения вещей именами классов. Например, можно создать бинарную маску только создания:

buildingMask = C == 'building';

figure
imshowpair(I, buildingMask,'montage')

Создайте семантическую сеть сегментации

Создайте простую семантическую сеть сегментации и узнайте об общих слоях, найденных во многих семантических сетях сегментации. Общий шаблон в семантических сетях сегментации требует субдискретизации изображения между сверточным и слоями ReLU, и затем сверхдискретизируйте вывод, чтобы совпадать с входным размером. Эта операция походит на стандартный анализ пробела шкалы с помощью пирамид изображений. Во время этого процесса однако, сеть выполняет операции с помощью нелинейных фильтров, оптимизированных для определенного набора классов, которые вы хотите сегментировать.

Создайте входной слой изображений

Семантическая сеть сегментации запускается с imageInputLayer, который задает самый маленький размер изображения, который может обработать сеть. Большинство семантических сетей сегментации является полностью сверточным, что означает, что они могут обработать изображения, которые больше, чем заданный входной размер. Здесь, размер изображения [32 32 3] используется для сети к процессу 64x64 изображения RGB.

inputSize = [32 32 3];
imgLayer = imageInputLayer(inputSize)
imgLayer = 
  ImageInputLayer with properties:

                Name: ''
           InputSize: [32 32 3]

   Hyperparameters
    DataAugmentation: 'none'
       Normalization: 'zerocenter'

Создайте сеть субдискретизации

Запустите со слоев ReLU и свертки. Дополнение слоя свертки выбрано таким образом, что выходной размер слоя свертки совпадает с входным размером. Это облегчает создавать сеть, потому что размеры ввода и вывода между большинством слоев остаются то же самое, в то время как вы прогрессируете через сеть.

filterSize = 3;
numFilters = 32;
conv = convolution2dLayer(filterSize,numFilters,'Padding',1);
relu = reluLayer();

Субдискретизация выполняется с помощью макс. слоя объединения. Создайте макс. слой объединения, чтобы субдискретизировать вход фактором 2 путем устанавливания параметра 'Stride' на 2.

poolSize = 2;
maxPoolDownsample2x = maxPooling2dLayer(poolSize,'Stride',2);

Сложите свертку, ReLU и макс. объединение слоев, чтобы создать сеть, которая субдискретизирует ее вход фактором 4.

downsamplingLayers = [
    conv
    relu
    maxPoolDownsample2x
    conv
    relu
    maxPoolDownsample2x
    ]
downsamplingLayers = 
  6x1 Layer array with layers:

     1   ''   Convolution   32 3x3 convolutions with stride [1  1] and padding [1  1  1  1]
     2   ''   ReLU          ReLU
     3   ''   Max Pooling   2x2 max pooling with stride [2  2] and padding [0  0  0  0]
     4   ''   Convolution   32 3x3 convolutions with stride [1  1] and padding [1  1  1  1]
     5   ''   ReLU          ReLU
     6   ''   Max Pooling   2x2 max pooling with stride [2  2] and padding [0  0  0  0]

Создайте сеть повышающей дискретизации

Повышающая дискретизация сделана с помощью транспонированного слоя свертки (также обычно называемый "deconv" или слоя "развертки"). Когда транспонированная свертка используется для повышающей дискретизации, она выполняет повышающую дискретизацию и фильтрацию одновременно.

Создайте транспонированный слой свертки, чтобы сверхдискретизировать 2.

filterSize = 4;
transposedConvUpsample2x = transposedConv2dLayer(4,numFilters,'Stride',2,'Cropping',1);

Параметр 'Обрезки' устанавливается на 1, чтобы заставить выходной размер равняться дважды входному размеру.

Сложите транспонированную свертку и relu слои. Вход к этому набору слоев сверхдискретизирован 4.

upsamplingLayers = [
    transposedConvUpsample2x
    relu
    transposedConvUpsample2x
    relu
    ]
upsamplingLayers = 
  4x1 Layer array with layers:

     1   ''   Transposed Convolution   32 4x4 transposed convolutions with stride [2  2] and output cropping [1  1]
     2   ''   ReLU                     ReLU
     3   ''   Transposed Convolution   32 4x4 transposed convolutions with stride [2  2] and output cropping [1  1]
     4   ''   ReLU                     ReLU

Создайте слой классификации пикселей

Итоговый набор слоев ответственен за то, что сделал классификации пикселей. Эти последние слои обрабатывают вход, который имеет те же пространственные размерности (высота и ширина) как входное изображение. Однако количество каналов (третья размерность) больше и равно количеству, просачивается последний транспонированный слой свертки. Эта третья размерность должна быть сжата вниз к количеству классов, которые мы хотим сегментировать. Это может быть сделано с помощью слоя свертки 1 на 1, количество которого фильтров равняются количеству классов, например, 3.

Создайте слой свертки, чтобы объединить третью размерность входных карт функции вниз к количеству классов.

numClasses = 3;
conv1x1 = convolution2dLayer(1,numClasses);

После этой свертки 1 на 1 слой softmax и слои классификации пикселей. Эти два слоя объединяются, чтобы предсказать категориальную метку для каждого пикселя изображения.

finalLayers = [
    conv1x1
    softmaxLayer()
    pixelClassificationLayer()
    ]
finalLayers = 
  3x1 Layer array with layers:

     1   ''   Convolution                  3 1x1 convolutions with stride [1  1] and padding [0  0  0  0]
     2   ''   Softmax                      softmax
     3   ''   Pixel Classification Layer   Cross-entropy loss 

Сложите все слои

Сложите все слои, чтобы завершить семантическую сеть сегментации.

net = [
    imgLayer    
    downsamplingLayers
    upsamplingLayers
    finalLayers
    ]
net = 
  14x1 Layer array with layers:

     1   ''   Image Input                  32x32x3 images with 'zerocenter' normalization
     2   ''   Convolution                  32 3x3 convolutions with stride [1  1] and padding [1  1  1  1]
     3   ''   ReLU                         ReLU
     4   ''   Max Pooling                  2x2 max pooling with stride [2  2] and padding [0  0  0  0]
     5   ''   Convolution                  32 3x3 convolutions with stride [1  1] and padding [1  1  1  1]
     6   ''   ReLU                         ReLU
     7   ''   Max Pooling                  2x2 max pooling with stride [2  2] and padding [0  0  0  0]
     8   ''   Transposed Convolution       32 4x4 transposed convolutions with stride [2  2] and output cropping [1  1]
     9   ''   ReLU                         ReLU
    10   ''   Transposed Convolution       32 4x4 transposed convolutions with stride [2  2] and output cropping [1  1]
    11   ''   ReLU                         ReLU
    12   ''   Convolution                  3 1x1 convolutions with stride [1  1] and padding [0  0  0  0]
    13   ''   Softmax                      softmax
    14   ''   Pixel Classification Layer   Cross-entropy loss 

Эта сеть готова быть обученной с помощью trainNetwork от Deep Learning Toolbox™.

Обучите семантическую сеть сегментации

Загрузите данные тренировки.

dataSetDir = fullfile(toolboxdir('vision'),'visiondata','triangleImages');
imageDir = fullfile(dataSetDir,'trainingImages');
labelDir = fullfile(dataSetDir,'trainingLabels');

Создайте datastore изображений для изображений.

imds = imageDatastore(imageDir);

Создайте pixelLabelDatastore для заземляющих пиксельных меток истины.

classNames = ["triangle","background"];
labelIDs   = [255 0];
pxds = pixelLabelDatastore(labelDir,classNames,labelIDs);

Визуализируйте учебные изображения и заземляющие пиксельные метки истины.

I = read(imds);
C = read(pxds);

I = imresize(I,5);
L = imresize(uint8(C),5);
imshowpair(I,L,'montage')

Создайте семантическую сеть сегментации. Эта сеть использует простую семантическую сеть сегментации на основе субдискретизации и повышающей дискретизации проекта.

numFilters = 64;
filterSize = 3;
numClasses = 2;
layers = [
    imageInputLayer([32 32 1])
    convolution2dLayer(filterSize,numFilters,'Padding',1)
    reluLayer()
    maxPooling2dLayer(2,'Stride',2)
    convolution2dLayer(filterSize,numFilters,'Padding',1)
    reluLayer()
    transposedConv2dLayer(4,numFilters,'Stride',2,'Cropping',1);
    convolution2dLayer(1,numClasses);
    softmaxLayer()
    pixelClassificationLayer()
    ]
layers = 
  10x1 Layer array with layers:

     1   ''   Image Input                  32x32x1 images with 'zerocenter' normalization
     2   ''   Convolution                  64 3x3 convolutions with stride [1  1] and padding [1  1  1  1]
     3   ''   ReLU                         ReLU
     4   ''   Max Pooling                  2x2 max pooling with stride [2  2] and padding [0  0  0  0]
     5   ''   Convolution                  64 3x3 convolutions with stride [1  1] and padding [1  1  1  1]
     6   ''   ReLU                         ReLU
     7   ''   Transposed Convolution       64 4x4 transposed convolutions with stride [2  2] and output cropping [1  1]
     8   ''   Convolution                  2 1x1 convolutions with stride [1  1] and padding [0  0  0  0]
     9   ''   Softmax                      softmax
    10   ''   Pixel Classification Layer   Cross-entropy loss 

Опции обучения Setup.

opts = trainingOptions('sgdm', ...
    'InitialLearnRate',1e-3, ...
    'MaxEpochs',100, ...
    'MiniBatchSize',64);

Создайте пиксельный datastore метки изображений, который содержит данные тренировки.

trainingData = pixelLabelImageDatastore(imds,pxds);

Обучите сеть.

net = trainNetwork(trainingData,layers,opts);
Training on single GPU.
Initializing image normalization.
|========================================================================================|
|  Epoch  |  Iteration  |  Time Elapsed  |  Mini-batch  |  Mini-batch  |  Base Learning  |
|         |             |   (hh:mm:ss)   |   Accuracy   |     Loss     |      Rate       |
|========================================================================================|
|       1 |           1 |       00:00:00 |       31.86% |       0.6934 |          0.0010 |
|      17 |          50 |       00:00:03 |       94.52% |       0.5564 |          0.0010 |
|      34 |         100 |       00:00:07 |       95.25% |       0.4415 |          0.0010 |
|      50 |         150 |       00:00:11 |       95.14% |       0.3722 |          0.0010 |
|      67 |         200 |       00:00:14 |       94.52% |       0.3336 |          0.0010 |
|      84 |         250 |       00:00:18 |       95.25% |       0.2931 |          0.0010 |
|     100 |         300 |       00:00:21 |       95.14% |       0.2708 |          0.0010 |
|========================================================================================|

Считайте и отобразите тестовое изображение.

testImage = imread('triangleTest.jpg');
imshow(testImage)

Сегментируйте тестовое изображение и отобразите результаты.

C = semanticseg(testImage,net);
B = labeloverlay(testImage,C);
imshow(B)

Улучшите результаты

Сеть не удалась сегментировать треугольники и классифицировала каждый пиксель как "фон". Обучение, казалось, подходило к учебной точности, больше, чем 90%. Однако сеть только училась классифицировать фоновый класс. Чтобы понять, почему это произошло, можно считать вхождение каждой пиксельной метки через набор данных.

tbl = countEachLabel(trainingData)
tbl=2×3 table
        Name        PixelCount    ImagePixelCount
    ____________    __________    _______________

    'triangle'           10326       2.048e+05   
    'background'    1.9447e+05       2.048e+05   

Большинство пиксельных меток для фона. Плохие результаты происходят из-за неустойчивости класса. Неустойчивость класса смещает процесс обучения в пользу доминирующего класса. Вот почему каждый пиксель классифицируется как "фон". Чтобы зафиксировать это, используйте взвешивание класса, чтобы сбалансировать классы. Существует несколько методов для вычислительных весов класса. Одна общепринятая методика является обратным взвешиванием частоты, где веса класса являются инверсией частот класса. Это увеличивает вес, данный недостаточно представленным классам.

totalNumberOfPixels = sum(tbl.PixelCount);
frequency = tbl.PixelCount / totalNumberOfPixels;
classWeights = 1./frequency
classWeights = 2×1

   19.8334
    1.0531

Веса класса могут быть заданы с помощью pixelClassificationLayer. Обновите последний слой, чтобы использовать pixelClassificationLayer с обратными весами класса.

layers(end) = pixelClassificationLayer('Classes',tbl.Name,'ClassWeights',classWeights);

Обучите сеть снова.

net = trainNetwork(trainingData,layers,opts);
Training on single GPU.
Initializing image normalization.
|========================================================================================|
|  Epoch  |  Iteration  |  Time Elapsed  |  Mini-batch  |  Mini-batch  |  Base Learning  |
|         |             |   (hh:mm:ss)   |   Accuracy   |     Loss     |      Rate       |
|========================================================================================|
|       1 |           1 |       00:00:00 |       47.50% |       0.6925 |          0.0010 |
|      17 |          50 |       00:00:04 |       19.67% |       0.6837 |          0.0010 |
|      34 |         100 |       00:00:08 |       75.77% |       0.4433 |          0.0010 |
|      50 |         150 |       00:00:12 |       85.00% |       0.4018 |          0.0010 |
|      67 |         200 |       00:00:16 |       87.00% |       0.3568 |          0.0010 |
|      84 |         250 |       00:00:20 |       88.03% |       0.3153 |          0.0010 |
|     100 |         300 |       00:00:24 |       90.42% |       0.2890 |          0.0010 |
|========================================================================================|

Попытайтесь сегментировать тестовое изображение снова.

C = semanticseg(testImage,net);
B = labeloverlay(testImage,C);
imshow(B)

Используя взвешивание класса, чтобы сбалансировать классы привел к лучшему результату сегментации. Дополнительные шаги, чтобы улучшить результаты включают увеличение числа эпох, используемых для обучения, добавления большего количества данных тренировки или изменения сети.

Оцените и осмотрите результаты семантической сегментации

Импортируйте набор тестовых данных, запустите предварительно обученную семантическую сеть сегментации, и оцените и осмотрите семантические метрики качества сегментации для предсказанных результатов.

Импортируйте набор данных

Набор данных triangleImages имеет 100 тестовых изображений с заземляющими метками истины. Задайте местоположение набора данных.

dataSetDir = fullfile(toolboxdir('vision'),'visiondata','triangleImages');

Задайте местоположение тестовых изображений.

testImagesDir = fullfile(dataSetDir,'testImages');

Создайте объект imageDatastore, содержащий тестовые изображения.

imds = imageDatastore(testImagesDir);

Задайте местоположение заземляющих меток истины.

testLabelsDir = fullfile(dataSetDir,'testLabels');

Задайте имена классов и их связанную метку IDs. Метка IDs является пиксельными значениями, используемыми в файлах изображений, чтобы представлять каждый класс.

classNames = ["triangle" "background"];
labelIDs = [255 0];

Создайте объект pixelLabelDatastore, содержащий заземляющие пиксельные метки истины для тестовых изображений.

pxdsTruth = pixelLabelDatastore(testLabelsDir,classNames,labelIDs);

Запустите семантический классификатор сегментации

Загрузите семантическую сеть сегментации, которая была обучена на учебных изображениях triangleImages.

net = load('triangleSegmentationNetwork.mat');
net = net.net;

Запустите сеть на тестовых изображениях. Предсказанные метки записаны в диск во временной директории и возвращены как объект pixelLabelDatastore.

pxdsResults = semanticseg(imds,net,"WriteLocation",tempdir);
Running semantic segmentation network
-------------------------------------
* Processing 100 images.
* Progress: 100.00%

Оцените качество прогноза

Предсказанные метки сравниваются с заземляющими метками истины. В то время как семантические метрики сегментации вычисляются, прогресс распечатан к Командному окну.

metrics = evaluateSemanticSegmentation(pxdsResults,pxdsTruth);
Evaluating semantic segmentation results
---------------------------------------[==================================================] 100%
Elapsed time: 00:00:01
Estimated time remaining: 00:00:00
* Finalizing... Done.
* Data set metrics:

    GlobalAccuracy    MeanAccuracy    MeanIoU    WeightedIoU    MeanBFScore
    ______________    ____________    _______    ___________    ___________

       0.90624          0.95085       0.61588      0.87529        0.40652  

Осмотрите метрики класса

Отобразите точность классификации, пересечение по объединению (IoU) и контур F-1 счет к каждому классу в наборе данных.

metrics.ClassMetrics
ans=2×3 table
                  Accuracy      IoU      MeanBFScore
                  ________    _______    ___________

    triangle            1     0.33005     0.028664  
    background     0.9017      0.9017      0.78438  

Отобразите матрицу беспорядка

Отобразите матрицу беспорядка.

metrics.ConfusionMatrix
ans=2×2 table
                  triangle    background
                  ________    __________

    triangle        4730            0   
    background      9601        88069   

Визуализируйте нормированную матрицу беспорядка как карту тепла в окне рисунка.

normConfMatData = metrics.NormalizedConfusionMatrix.Variables;
figure
h = heatmap(classNames,classNames,100*normConfMatData);
h.XLabel = 'Predicted Class';
h.YLabel = 'True Class';
h.Title = 'Normalized Confusion Matrix (%)';

Осмотрите метрику изображений

Визуализируйте гистограмму пересечения по объединению (IoU) на изображение.

imageIoU = metrics.ImageMetrics.MeanIoU;
figure
histogram(imageIoU)
title('Image Mean IoU')

Найдите тестовое изображение с самым низким IoU.

[minIoU, worstImageIndex] = min(imageIoU);
minIoU = minIoU(1);
worstImageIndex = worstImageIndex(1);

Считайте тестовое изображение с худшим IoU, его заземляющими метками истины и его предсказанными метками для сравнения.

worstTestImage = readimage(imds,worstImageIndex);
worstTrueLabels = readimage(pxdsTruth,worstImageIndex);
worstPredictedLabels = readimage(pxdsResults,worstImageIndex);

Преобразуйте изображения метки в изображения, которые могут быть отображены в окне рисунка.

worstTrueLabelImage = im2uint8(worstTrueLabels == classNames(1));
worstPredictedLabelImage = im2uint8(worstPredictedLabels == classNames(1));

Отобразите худшее тестовое изображение, наземную истину и прогноз.

worstMontage = cat(4,worstTestImage,worstTrueLabelImage,worstPredictedLabelImage);
worstMontage = imresize(worstMontage,4,"nearest");
figure
montage(worstMontage,'Size',[1 3])
title(['Test Image vs. Truth vs. Prediction. IoU = ' num2str(minIoU)])

Точно так же найдите тестовое изображение с самым высоким IoU.

[maxIoU, bestImageIndex] = max(imageIoU);
maxIoU = maxIoU(1);
bestImageIndex = bestImageIndex(1);

Повторите предыдущие шаги, чтобы считать, преобразовать, и отобразить тестовое изображение с лучшим IoU с его наземной истиной и предсказанными метками.

bestTestImage = readimage(imds,bestImageIndex);
bestTrueLabels = readimage(pxdsTruth,bestImageIndex);
bestPredictedLabels = readimage(pxdsResults,bestImageIndex);

bestTrueLabelImage = im2uint8(bestTrueLabels == classNames(1));
bestPredictedLabelImage = im2uint8(bestPredictedLabels == classNames(1));

bestMontage = cat(4,bestTestImage,bestTrueLabelImage,bestPredictedLabelImage);
bestMontage = imresize(bestMontage,4,"nearest");
figure
montage(bestMontage,'Size',[1 3])
title(['Test Image vs. Truth vs. Prediction. IoU = ' num2str(maxIoU)])

Задайте метрики, чтобы оценить

Опционально, перечислите метрику (метрики), требуется оценить использование параметра 'Metrics'.

Задайте метрики, чтобы вычислить.

evaluationMetrics = ["accuracy" "iou"];

Вычислите эти метрики для набора тестовых данных triangleImages.

metrics = evaluateSemanticSegmentation(pxdsResults,pxdsTruth,"Metrics",evaluationMetrics);
Evaluating semantic segmentation result[==================================================] 100%
Elapsed time: 00:00:00
Estimated time remaining: 00:00:00
* Finalizing... Done.
* Data set metrics:

    MeanAccuracy    MeanIoU
    ____________    _______

      0.95085       0.61588

Отобразите выбранные метрики для каждого класса.

metrics.ClassMetrics
ans=2×2 table
                  Accuracy      IoU  
                  ________    _______

    triangle            1     0.33005
    background     0.9017      0.9017

Импортируйте пиксель маркированный набор данных для семантической сегментации

Этот пример показывает вам, как импортировать пиксель маркированный набор данных для семантических сетей сегментации.

Маркированный набор данных пикселя является набором изображений и соответствующим набором заземляющих пиксельных меток истины, используемых для того, чтобы обучить семантические сети сегментации. Существует много общедоступных наборов данных, которые предоставляют снабженным аннотацией изображениям метки на пиксель. Чтобы проиллюстрировать шаги для импорта этих типов наборов данных, пример использует набор данных CamVid из Кембриджского университета [1].

Набор данных CamVid является набором изображений, содержащих уличные представления уровня, полученные при управлении. Набор данных обеспечивает метки пиксельного уровня для 32 семантических классов включая автомобиль, пешехода и дорогу. Шаги, которые, как показывают, импортировали CamVid, могут использоваться, чтобы импортировать другой пиксель маркированные наборы данных.

Загрузите набор данных CamVid

Загрузите данные изображения CamVid со следующих URL:

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,'images');
labelDir = fullfile(outputFolder,'labels');

if ~exist(outputFolder, 'dir')
    disp('Downloading 557 MB CamVid data set...');
    
    unzip(imageURL, imageDir);
    unzip(labelURL, labelDir);
end

Примечание: время Загрузки данных зависит от вашего интернет-соединения. Команды, используемые выше, блокируют MATLAB®, пока загрузка не будет завершена. Также можно использовать веб-браузер, чтобы сначала загрузить набор данных на локальный диск. Чтобы использовать файл, вы загрузили с сети, замените переменную outputFolder выше к местоположению загруженного файла.

Пиксельные метки CamVid

Набор данных CamVid кодирует пиксельные метки, когда RGB отображает, где каждый класс представлен цветом RGB. Вот классы, которые набор данных задает наряду с их кодировкой RGB.

classNames = [ ...
    "Animal", ...
    "Archway", ...
    "Bicyclist", ...
    "Bridge", ...
    "Building", ...
    "Car", ...
    "CartLuggagePram", ...
    "Child", ...
    "Column_Pole", ...
    "Fence", ...
    "LaneMkgsDriv", ...
    "LaneMkgsNonDriv", ...
    "Misc_Text", ...
    "MotorcycleScooter", ...
    "OtherMoving", ...
    "ParkingBlock", ...
    "Pedestrian", ...
    "Road", ...
    "RoadShoulder", ...
    "Sidewalk", ...
    "SignSymbol", ...
    "Sky", ...
    "SUVPickupTruck", ...
    "TrafficCone", ...
    "TrafficLight", ...
    "Train", ...
    "Tree", ...
    "Truck_Bus", ...
    "Tunnel", ...
    "VegetationMisc", ...
    "Wall"];

Задайте отображение между индексами метки и именами классов, таким образом, что classNames(k) соответствует labelIDs(k,:).

labelIDs = [ ...
    064 128 064; ... % "Animal"
    192 000 128; ... % "Archway"
    000 128 192; ... % "Bicyclist"
    000 128 064; ... % "Bridge"
    128 000 000; ... % "Building"
    064 000 128; ... % "Car"
    064 000 192; ... % "CartLuggagePram"
    192 128 064; ... % "Child"
    192 192 128; ... % "Column_Pole"
    064 064 128; ... % "Fence"
    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; ... % "Pedestrian"
    128 064 128; ... % "Road"
    128 128 192; ... % "RoadShoulder"
    000 000 192; ... % "Sidewalk"
    192 128 128; ... % "SignSymbol"
    128 128 128; ... % "Sky"
    064 128 192; ... % "SUVPickupTruck"
    000 000 064; ... % "TrafficCone"
    000 064 064; ... % "TrafficLight"
    192 064 128; ... % "Train"
    128 128 000; ... % "Tree"
    192 128 192; ... % "Truck_Bus"
    064 000 064; ... % "Tunnel"
    192 192 000; ... % "VegetationMisc"
    064 192 000];    % "Wall"

Обратите внимание на то, что другие наборы данных имеют различные форматы кодирования данных. Например, набор данных PASCAL VOC [2] использует числовую метку IDs между 0 и 21, чтобы закодировать их метки класса.

Визуализируйте пиксельные метки для одного из изображений CamVid.

labels = imread(fullfile(labelDir,'0001TP_006690_L.png'));
figure
imshow(labels)

% Add colorbar to show class to color mapping.
N = numel(classNames);
ticks = 1/(N*2):1/N:1;
colorbar('TickLabels',cellstr(classNames),'Ticks',ticks,'TickLength',0,'TickLabelInterpreter','none');
colormap(labelIDs./255)

Загрузите данные CamVid

Маркированный набор данных пикселя может загрузиться с помощью imageDatastore и pixelLabelDatastore.

Создайте imageDatastore, чтобы загрузить изображения CamVid.

imds = imageDatastore(fullfile(imageDir,'701_StillsRaw_full'));

Создайте pixelLabelDatastore, чтобы загрузить пиксельные метки CamVid.

pxds = pixelLabelDatastore(labelDir,classNames,labelIDs);

Считайте 10-е изображение и соответствующее пиксельное изображение метки.

I = readimage(imds,10);
C = readimage(pxds,10);

Пиксельное изображение метки возвращено как категориальный массив, где C(i,j) является категориальной меткой, присвоенной пикселю I(i,j). Отобразите пиксельное изображение метки сверху изображения.

B = labeloverlay(I,C,'Colormap',labelIDs./255);
figure
imshow(B)

% Add a colorbar.
N = numel(classNames);
ticks = 1/(N*2):1/N:1;
colorbar('TickLabels',cellstr(classNames),'Ticks',ticks,'TickLength',0,'TickLabelInterpreter','none');
colormap(labelIDs./255)

Неопределенные или пустые метки

Пикселю маркированные наборы данных свойственно включать "неопределенные" или "пустые" метки. Они используются, чтобы определять пиксели, которые не были маркированы. Например, в CamVid, метка ID [0 0 0] используется, чтобы определять "пустой" класс. Учебные алгоритмы и алгоритмы оценки, как ожидают, не будут включать эти метки ни в какие вычисления.

"Пустой" класс нельзя явным образом назвать при использовании pixelLabelDatastore. Любая метка ID, которая не сопоставлена с именем класса, автоматически маркирована "неопределенной" и исключена из вычислений. Чтобы видеть неопределенные пиксели, используйте isundefined, чтобы создать маску и затем отобразить его сверху изображения.

undefinedPixels = isundefined(C);
B = labeloverlay(I,undefinedPixels);
figure
imshow(B)
title('Undefined Pixel Labels')

Объедините классы

При работе с общедоступными наборами данных вы, возможно, должны объединить некоторые классы, чтобы лучше удовлетворить вашему приложению. Например, можно хотеть обучить семантическую сеть сегментации, которая сегментирует сцену на 4 класса: дорога, небо, автомобиль, пешеход и фон. Для этого с набором данных CamVid, сгруппируйте метку IDs, заданную выше, чтобы соответствовать новым классам. Во-первых, задайте новые имена классов.

newClassNames = ["road","sky","vehicle","pedestrian","background"];

Затем, метка IDs группы с помощью массива ячеек матриц M-3.

groupedLabelIDs = {
    % road
    [
    128 064 128; ... % "Road"
    128 000 192; ... % "LaneMkgsDriv"
    192 000 064; ... % "LaneMkgsNonDriv"
    000 000 192; ... % "Sidewalk" 
    064 192 128; ... % "ParkingBlock"
    128 128 192; ... % "RoadShoulder"
    ]
   
    % "sky"
    [
    128 128 128; ... % "Sky"
    ]
    
    % "vehicle"
    [
    064 000 128; ... % "Car"
    064 128 192; ... % "SUVPickupTruck"
    192 128 192; ... % "Truck_Bus"
    192 064 128; ... % "Train"
    000 128 192; ... % "Bicyclist"
    192 000 192; ... % "MotorcycleScooter"
    128 064 064; ... % "OtherMoving"
    ]
     
    % "pedestrian"
    [
    064 064 000; ... % "Pedestrian"
    192 128 064; ... % "Child"
    064 000 192; ... % "CartLuggagePram"
    064 128 064; ... % "Animal"
    ]
    
    % "background"      
    [
    128 128 000; ... % "Tree"
    192 192 000; ... % "VegetationMisc"    
    192 128 128; ... % "SignSymbol"
    128 128 064; ... % "Misc_Text"
    000 064 064; ... % "TrafficLight"  
    064 064 128; ... % "Fence"
    192 192 128; ... % "Column_Pole"
    000 000 064; ... % "TrafficCone"
    000 128 064; ... % "Bridge"
    128 000 000; ... % "Building"
    064 192 000; ... % "Wall"
    064 000 064; ... % "Tunnel"
    192 000 128; ... % "Archway"
    ]
    };

Создайте pixelLabelDatastore с помощью нового класса и метки IDs.

pxds = pixelLabelDatastore(labelDir,newClassNames,groupedLabelIDs);

Считайте 10-е пиксельное изображение метки и отобразите его сверху изображения.

C = readimage(pxds,10);
cmap = jet(numel(newClassNames));
B = labeloverlay(I,C,'Colormap',cmap);
figure
imshow(B)

% add colorbar
N = numel(newClassNames);
ticks = 1/(N*2):1/N:1;
colorbar('TickLabels',cellstr(newClassNames),'Ticks',ticks,'TickLength',0,'TickLabelInterpreter','none');
colormap(cmap)

pixelLabelDatastore с новыми именами классов может теперь использоваться, чтобы обучить сеть для этих 4 классов, не имея необходимость изменять исходные пиксельные метки CamVid.

Ссылки

[1] Brostow, Габриэль Дж., Жюльен Фокер и Роберто Сиполья. "Семантические классы объектов в видео: наземная база данных истины высокой четкости". Буквы Распознавания образов 30.2 (2009): 88-97.

[2] Everingham, M., и др. "Классы визуального объекта PASCAL бросают вызов 2 012 результатам". См. http://www. сеть Паскаля. org/challenges/VOC/voc2012/workshop/index. html. Издание 5. 2012.