Чтобы обучить семантическую сеть сегментации, вам нужны набор изображений и его соответствующий набор пикселя маркированные изображения. Маркированное изображение пикселя является изображением, где каждое пиксельное значение представляет категориальную метку того пикселя.
Следующий код загружает маленький набор изображений и их соответствующего пикселя маркированные изображения:
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.