Чтобы обучить сеть семантической сегментации, вам нужны набор изображений и его соответствующий набор пикселя помеченные изображения. Помеченное изображение пикселя является изображением, где каждое пиксельное значение представляет категориальную метку того пикселя.
Следующий код загружает маленький набор изображений и их соответствующего пикселя помеченные изображения:
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 ------------------------------------- * Processed 100 images.
Оцените качество прогноза
Предсказанные метки сравниваются с метками основной истины. В то время как метрики семантической сегментации вычисляются, прогресс распечатан к Командному окну.
metrics = evaluateSemanticSegmentation(pxdsResults,pxdsTruth);
Evaluating semantic segmentation results ---------------------------------------- * Selected metrics: global accuracy, class accuracy, IoU, weighted IoU, BF score. * Processed 100 images. * 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 results ---------------------------------------- * Selected metrics: class accuracy, IoU. * Processed 100 images. * 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.