Для обучения семантической сети сегментации вам нужна набор изображений и соответствующая ей набор пиксельных маркированных изображений. Пиксельное маркированное изображение является изображением, где каждое значение пикселя представляет категориальную метку этого пикселя.
Следующий код загружает небольшой набор изображений и соответствующих пиксельных маркированных изображений:
dataDir = fullfile(toolboxdir('vision'),'visiondata'); imDir = fullfile(dataDir,'building'); pxDir = fullfile(dataDir,'buildingPixelLabels');
Загрузите данные изображения с помощью imageDatastore
. image datastore может эффективно представлять большой набор изображений, потому что изображения считываются в память только при необходимости.
imds = imageDatastore(imDir);
Чтение и отображение первого изображения.
I = readimage(imds,1); figure imshow(I)
Загрузите изображения меток пикселей с помощью pixelLabelDatastore
для определения отображения между идентификаторами меток и категориальными именами. В используемом здесь наборе данных метки «небо», «трава», «здание» и «тротуар». Идентификаторы меток для этих классов являются 1, 2, 3, 4, соответственно.
Задайте имена классов.
classNames = ["sky" "grass" "building" "sidewalk"];
Определите идентификатор метки для каждого имени класса.
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
, который определяет наименьший размер изображения, который может обработать сеть. Большинство семантических сетей сегментации полностью сверточны, что означает, что они могут обрабатывать изображения, которые больше заданного размера входа. Здесь для обработки изображений RGB 64x64 в сети используется изображение размером [32 32 3].
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» или «deconvolution»). Когда транспонированная свертка используется для увеличения дискретизации, она выполняет усиление дискретизации и фильтрацию одновременно.
Создайте транспонированный слой свертки для увеличения на 2.
filterSize = 4; transposedConvUpsample2x = transposedConv2dLayer(4,numFilters,'Stride',2,'Cropping',1);
Параметр 'Cropping' устанавливается равным 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{1}),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 = 10×1 Layer array with layers: 1 '' Image Input 32×32×1 images with 'zerocenter' normalization 2 '' Convolution 64 3×3 convolutions with stride [1 1] and padding [1 1 1 1] 3 '' ReLU ReLU 4 '' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0] 5 '' Convolution 64 3×3 convolutions with stride [1 1] and padding [1 1 1 1] 6 '' ReLU ReLU 7 '' Transposed Convolution 64 4×4 transposed convolutions with stride [2 2] and cropping [1 1 1 1] 8 '' Convolution 2 1×1 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);
Объедините изображение и pixel label datastore для обучения.
trainingData = pixelLabelImageDatastore(imds,pxds);
Обучите сеть.
net = trainNetwork(trainingData,layers,opts);
Training on single CPU. Initializing input data normalization. |========================================================================================| | Epoch | Iteration | Time Elapsed | Mini-batch | Mini-batch | Base Learning | | | | (hh:mm:ss) | Accuracy | Loss | Rate | |========================================================================================| | 1 | 1 | 00:00:00 | 58.11% | 1.3458 | 0.0010 | | 17 | 50 | 00:00:11 | 97.30% | 0.0924 | 0.0010 | | 34 | 100 | 00:00:23 | 98.09% | 0.0575 | 0.0010 | | 50 | 150 | 00:00:34 | 98.56% | 0.0424 | 0.0010 | | 67 | 200 | 00:00:46 | 98.48% | 0.0435 | 0.0010 | | 84 | 250 | 00:00:58 | 98.66% | 0.0363 | 0.0010 | | 100 | 300 | 00:01:09 | 98.90% | 0.0310 | 0.0010 | |========================================================================================|
Чтение и отображение тестового изображения.
testImage = imread('triangleTest.jpg');
imshow(testImage)
Сегментируйте тестовое изображение и отображайте результаты.
C = semanticseg(testImage,net); B = labeloverlay(testImage,C); imshow(B)
Улучшите результаты
Сеть не смогла сегментировать треугольники и классифицировала каждый пиксель как «фон». Обучение, по-видимому, идет хорошо с точностями обучения более 90%. Однако сеть научилась только классифицировать фоновый класс. Чтобы понять, почему это произошло, можно подсчитать вхождение каждой пиксельной метки на наборе данных.
tbl = countEachLabel(pxds)
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 CPU. Initializing input data normalization. |========================================================================================| | Epoch | Iteration | Time Elapsed | Mini-batch | Mini-batch | Base Learning | | | | (hh:mm:ss) | Accuracy | Loss | Rate | |========================================================================================| | 1 | 1 | 00:00:00 | 72.27% | 5.4135 | 0.0010 | | 17 | 50 | 00:00:11 | 94.84% | 0.1188 | 0.0010 | | 34 | 100 | 00:00:23 | 96.52% | 0.0871 | 0.0010 | | 50 | 150 | 00:00:35 | 97.29% | 0.0599 | 0.0010 | | 67 | 200 | 00:00:47 | 97.46% | 0.0628 | 0.0010 | | 84 | 250 | 00:00:59 | 97.64% | 0.0586 | 0.0010 | | 100 | 300 | 00:01:10 | 97.99% | 0.0451 | 0.0010 | |========================================================================================|
Повторите попытку сегментации тестового изображения.
C = semanticseg(testImage,net); B = labeloverlay(testImage,C); imshow(B)
Использование взвешивания классов для балансировки классов дало лучший результат сегментации. Дополнительные шаги по улучшению результатов включают увеличение количества эпох, используемых для обучения, добавление дополнительных обучающих данных или изменение сети.
Импортируйте набор тестовых данных, запустите предварительно обученную сеть семантической сегментации и оцените и проверьте метрики качества семантической сегментации для предсказанных результатов.
Импорт набора данных
The triangleImages
набор данных имеет 100 тестовых изображений с основной истиной метками. Определите местоположение набора данных.
dataSetDir = fullfile(toolboxdir('vision'),'visiondata','triangleImages');
Определите местоположение тестовых изображений.
testImagesDir = fullfile(dataSetDir,'testImages');
Создайте imageDatastore
объект, содержащий тестовые изображения.
imds = imageDatastore(testImagesDir);
Определите местоположение меток основной истины.
testLabelsDir = fullfile(dataSetDir,'testLabels');
Задайте имена классов и связанные с ними идентификаторы меток. Идентификаторы меток являются пиксельными значениями, используемыми в файлах изображений для представления каждого класса.
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] использует числовые идентификаторы меток от 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
и a 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 идентификатор метки [0 0 0] используется для обозначения класса «void». Ожидается, что алгоритмы настройки и алгоритмы оценки не будут включать эти метки в какие-либо расчеты.
Класс «void» не должен быть явно назван при использовании pixelLabelDatastore
. Любой идентификатор метки, который не сопоставлен с именем класса, автоматически помечается как «неопределенный» и исключается из расчетов. Чтобы увидеть неопределенные пиксели, используйте isundefined
чтобы создать маску и отобразить ее поверх изображения.
undefinedPixels = isundefined(C);
B = labeloverlay(I,undefinedPixels);
figure
imshow(B)
title('Undefined Pixel Labels')
Объединение классов
При работе с общедоступными наборами данных, возможно, потребуется объединить некоторые классы, чтобы лучше подойти вашему приложению. Например, вы можете захотеть обучить сеть семантической сегментации, которая сегментирует сцену в 4 класса: дорога, небо, транспортное средство, пешеходный и фон. Для этого с набором данных CamVid сгруппируйте идентификаторы меток, определенные выше, чтобы соответствовать новым классам. Во-первых, задайте новые имена классов.
newClassNames = ["road","sky","vehicle","pedestrian","background"];
Затем сгруппируйте идентификаторы меток, используя массив ячеек из M-by-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
использование новых идентификаторов классов и меток.
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)
The pixelLabelDatastore
с новыми именами классов теперь можно использовать для обучения сети для 4 классов без необходимости изменения исходных меток пикселей CamVid.
Ссылки
[1] Brostow, Gabriel J., Julien Fauqueur, and Roberto Cipolla. Semantic object classes in video: A high-definition основная истина database (неопр.) (недоступная ссылка). Pattern Recognition Letters 30.2 (2009): 88-97.
[2] Everingham, M. et al. «Визуальный объект PASCAL классов результаты задачи 2012». См. http ://www. pascal-network. org/challenges/VOC/voc2012/workshop/index. html. Том 5. 2012.