В этом примере показано, как выполнить семантическую сегментацию многоспектрального изображения с семью каналами с помощью U-Net.
Семантическая сегментация вовлекает маркировку каждого пикселя в изображение с классом. Одно приложение семантической сегментации отслеживает вырубку леса, которая является изменением в лесном покрове в зависимости от времени. Экологические агентства отслеживают вырубку леса, чтобы оценить и определить количество экологического и экологического здоровья области.
Основанная на глубоком обучении семантическая сегментация может дать к точному измерению растительного покрова из воздушных фотографий с высоким разрешением. Одна проблема дифференцирует классы с подобными визуальными характеристиками, такими как попытка классифицировать зеленый пиксель как траву, кустарник или дерево. Чтобы увеличить точность классификации, некоторые наборы данных содержат многоспектральные изображения, которые предоставляют дополнительную информацию о каждом пикселе. Например, набор данных национального парка Hamlin Beach добавляет цветные изображения с тремя почти инфракрасными каналами, которые обеспечивают более ясное разделение классов.
В этом примере показано, как использовать основанные на глубоком обучении методы семантической сегментации, чтобы вычислить растительный покров процента в области от набора многоспектральных изображений.
Этот пример использует многоспектральный набор данных с высоким разрешением, чтобы обучить сеть [1]. Набор изображений был получен с помощью беспилотника по Хэмлин-Бич-Стэйт-Парк, Нью-Йорк. Данные содержат помеченное обучение, валидацию и наборы тестов, с 18 метками класса объекта. Размер файла данных составляет ~3.0 Гбайт.
Загрузите версию MAT-файла набора данных с помощью downloadHamlinBeachMSIData
функция помощника. Эта функция присоединена к примеру как вспомогательный файл.
imageDir = tempdir;
url = 'http://www.cis.rit.edu/~rmk6217/rit18_data.mat';
downloadHamlinBeachMSIData(url,imageDir);
Загрузите набор данных в рабочую область.
load(fullfile(imageDir,'rit18_data','rit18_data.mat'));
Исследуйте структуру данных.
whos train_data val_data test_data
Name Size Bytes Class Attributes test_data 7x12446x7654 1333663576 uint16 train_data 7x9393x5642 741934284 uint16 val_data 7x8833x6918 855493716 uint16
Многоспектральные данные изображения располагаются как numChannels шириной массивами высоты. Однако в MATLAB®, многоканальные изображения располагаются как ширина высотой numChannels массивами. Чтобы изменить данные так, чтобы каналы были в третьей размерности, используйте функцию помощника, switchChannelsToThirdPlane
Эта функция присоединена к примеру как вспомогательный файл.
train_data = switchChannelsToThirdPlane(train_data); val_data = switchChannelsToThirdPlane(val_data); test_data = switchChannelsToThirdPlane(test_data);
Подтвердите, что данные имеют правильную структуру.
whos train_data val_data test_data
Name Size Bytes Class Attributes test_data 12446x7654x7 1333663576 uint16 train_data 9393x5642x7 741934284 uint16 val_data 8833x6918x7 855493716 uint16
Цветовые каналы RGB являются 3-ми, 2-ми, и 1-ми каналами изображений. Отобразите компонент цвета обучения, валидации, и протестируйте изображения как монтаж. Чтобы заставить изображения казаться более яркими на экране, компенсируйте их гистограммы при помощи histeq
(Image Processing Toolbox) функция.
figure montage(... {histeq(train_data(:,:,[3 2 1])), ... histeq(val_data(:,:,[3 2 1])), ... histeq(test_data(:,:,[3 2 1]))}, ... 'BorderSize',10,'BackgroundColor','white') title('RGB Component of Training Image (Left), Validation Image (Center), and Test Image (Right)')
Отобразите последние три компенсируемых гистограммой канала обучающих данных как монтаж. Эти каналы соответствуют почти инфракрасным полосам и подсвечивают различные компоненты изображения на основе их подписей тепла. Например, деревья около центра второго изображения канала показывают больше детали, чем деревья в других двух каналах.
figure montage(... {histeq(train_data(:,:,4)), ... histeq(train_data(:,:,5)), ... histeq(train_data(:,:,6))}, ... 'BorderSize',10,'BackgroundColor','white') title('IR Channels 1 (Left), 2, (Center), and 3 (Right) of Training Image')
Канал 7 является маской, которая указывает на допустимую область сегментации. Отобразите маску для обучения, валидации, и протестируйте изображения.
figure montage(... {train_data(:,:,7), ... val_data(:,:,7), ... test_data(:,:,7)}, ... 'BorderSize',10,'BackgroundColor','white') title('Mask of Training Image (Left), Validation Image (Center), and Test Image (Right)')
Помеченные изображения содержат достоверные данные для сегментации с каждым пикселем, присвоенным одному из этих 18 классов. Получите список классов с их соответствующими идентификаторами.
disp(classes)
0. Other Class/Image Border 1. Road Markings 2. Tree 3. Building 4. Vehicle (Car, Truck, or Bus) 5. Person 6. Lifeguard Chair 7. Picnic Table 8. Black Wood Panel 9. White Wood Panel 10. Orange Landing Pad 11. Water Buoy 12. Rocks 13. Other Vegetation 14. Grass 15. Sand 16. Water (Lake) 17. Water (Pond) 18. Asphalt (Parking Lot/Walkway)
Создайте вектор из имен классов.
classNames = [ "RoadMarkings","Tree","Building","Vehicle","Person", ... "LifeguardChair","PicnicTable","BlackWoodPanel",... "WhiteWoodPanel","OrangeLandingPad","Buoy","Rocks",... "LowLevelVegetation","Grass_Lawn","Sand_Beach",... "Water_Lake","Water_Pond","Asphalt"];
Наложите метки на компенсируемом гистограммой изображении обучения RGB. Добавьте цветную полосу в изображение.
cmap = jet(numel(classNames)); B = labeloverlay(histeq(train_data(:,:,4:6)),train_labels,'Transparency',0.8,'Colormap',cmap); figure imshow(B) title('Training Labels') N = numel(classNames); ticks = 1/(N*2):1/N:1; colorbar('TickLabels',cellstr(classNames),'Ticks',ticks,'TickLength',0,'TickLabelInterpreter','none'); colormap(cmap)
Сохраните обучающие данные как файл MAT и учебные метки как файл PNG.
save('train_data.mat','train_data'); imwrite(train_labels,'train_labels.png');
Используйте случайный datastore экстракции закрашенной фигуры, чтобы накормить обучающими данными сеть. Этот datastore извлекает несколько соответствующих случайных закрашенных фигур из datastore изображений и пиксельного datastore метки, которые содержат изображения основной истины и данные о пиксельных метках. Исправление является общим методом, чтобы предотвратить исчерпывание памяти для больших изображений и эффективно увеличить сумму доступных обучающих данных.
Начните путем хранения учебных изображений от 'train_data.mat'
в imageDatastore
. Поскольку формат файла MAT является нестандартным форматом изображения, необходимо использовать средство чтения файлов MAT, чтобы позволить читать данные изображения. Можно использовать средство чтения файлов MAT помощника, matReader
, это извлекает первые шесть каналов из обучающих данных и не использует последний канал, содержащий маску. Эта функция присоединена к примеру как вспомогательный файл.
imds = imageDatastore('train_data.mat','FileExtensions','.mat','ReadFcn',@matReader);
Создайте pixelLabelDatastore
(Computer Vision Toolbox), чтобы сохранить закрашенные фигуры метки, содержащие 18 помеченных областей.
pixelLabelIds = 1:18;
pxds = pixelLabelDatastore('train_labels.png',classNames,pixelLabelIds);
Создайте randomPatchExtractionDatastore
(Image Processing Toolbox) от datastore изображений и пикселя помечает datastore. Каждый мини-пакет содержит 16 закрашенных фигур размера 256 256 пиксели. Одна тысяча мини-пакетов извлечена в каждой итерации эпохи.
dsTrain = randomPatchExtractionDatastore(imds,pxds,[256,256],'PatchesPerImage',16000);
Случайный datastore экстракции закрашенной фигуры dsTrain
обеспечивает мини-пакеты данных к сети в каждой итерации эпохи. Предварительно просмотрите datastore, чтобы исследовать данные.
inputBatch = preview(dsTrain); disp(inputBatch)
InputImage ResponsePixelLabelImage __________________ _______________________ {256×256×6 uint16} {256×256 categorical} {256×256×6 uint16} {256×256 categorical} {256×256×6 uint16} {256×256 categorical} {256×256×6 uint16} {256×256 categorical} {256×256×6 uint16} {256×256 categorical} {256×256×6 uint16} {256×256 categorical} {256×256×6 uint16} {256×256 categorical} {256×256×6 uint16} {256×256 categorical}
Этот пример использует изменение сети U-Net. В U-Net начальные серии сверточных слоев вкраплены макс. слоями объединения, последовательно уменьшив разрешение входного изображения. Эти слои сопровождаются серией сверточных слоев, вкрапленных повышающей дискретизацией операторов, последовательно увеличивая разрешение входного изображения [2]. U-Net имени прибывает из того, что сеть может чертиться с симметричной формой как буква U.
Этот пример изменяет U-Net, чтобы использовать дополнение нуля в свертках, так, чтобы вход и выход к сверткам имели тот же размер. Используйте функцию помощника, createUnet
, создать U-Net несколькими предварительно выобранными гиперпараметрами. Эта функция присоединена к примеру как вспомогательный файл.
inputTileSize = [256,256,6]; lgraph = createUnet(inputTileSize); disp(lgraph.Layers)
58×1 Layer array with layers: 1 'ImageInputLayer' Image Input 256×256×6 images with 'zerocenter' normalization 2 'Encoder-Section-1-Conv-1' Convolution 64 3×3×6 convolutions with stride [1 1] and padding [1 1 1 1] 3 'Encoder-Section-1-ReLU-1' ReLU ReLU 4 'Encoder-Section-1-Conv-2' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 5 'Encoder-Section-1-ReLU-2' ReLU ReLU 6 'Encoder-Section-1-MaxPool' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0] 7 'Encoder-Section-2-Conv-1' Convolution 128 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 8 'Encoder-Section-2-ReLU-1' ReLU ReLU 9 'Encoder-Section-2-Conv-2' Convolution 128 3×3×128 convolutions with stride [1 1] and padding [1 1 1 1] 10 'Encoder-Section-2-ReLU-2' ReLU ReLU 11 'Encoder-Section-2-MaxPool' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0] 12 'Encoder-Section-3-Conv-1' Convolution 256 3×3×128 convolutions with stride [1 1] and padding [1 1 1 1] 13 'Encoder-Section-3-ReLU-1' ReLU ReLU 14 'Encoder-Section-3-Conv-2' Convolution 256 3×3×256 convolutions with stride [1 1] and padding [1 1 1 1] 15 'Encoder-Section-3-ReLU-2' ReLU ReLU 16 'Encoder-Section-3-MaxPool' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0] 17 'Encoder-Section-4-Conv-1' Convolution 512 3×3×256 convolutions with stride [1 1] and padding [1 1 1 1] 18 'Encoder-Section-4-ReLU-1' ReLU ReLU 19 'Encoder-Section-4-Conv-2' Convolution 512 3×3×512 convolutions with stride [1 1] and padding [1 1 1 1] 20 'Encoder-Section-4-ReLU-2' ReLU ReLU 21 'Encoder-Section-4-DropOut' Dropout 50% dropout 22 'Encoder-Section-4-MaxPool' Max Pooling 2×2 max pooling with stride [2 2] and padding [0 0 0 0] 23 'Mid-Conv-1' Convolution 1024 3×3×512 convolutions with stride [1 1] and padding [1 1 1 1] 24 'Mid-ReLU-1' ReLU ReLU 25 'Mid-Conv-2' Convolution 1024 3×3×1024 convolutions with stride [1 1] and padding [1 1 1 1] 26 'Mid-ReLU-2' ReLU ReLU 27 'Mid-DropOut' Dropout 50% dropout 28 'Decoder-Section-1-UpConv' Transposed Convolution 512 2×2×1024 transposed convolutions with stride [2 2] and cropping [0 0 0 0] 29 'Decoder-Section-1-UpReLU' ReLU ReLU 30 'Decoder-Section-1-DepthConcatenation' Depth concatenation Depth concatenation of 2 inputs 31 'Decoder-Section-1-Conv-1' Convolution 512 3×3×1024 convolutions with stride [1 1] and padding [1 1 1 1] 32 'Decoder-Section-1-ReLU-1' ReLU ReLU 33 'Decoder-Section-1-Conv-2' Convolution 512 3×3×512 convolutions with stride [1 1] and padding [1 1 1 1] 34 'Decoder-Section-1-ReLU-2' ReLU ReLU 35 'Decoder-Section-2-UpConv' Transposed Convolution 256 2×2×512 transposed convolutions with stride [2 2] and cropping [0 0 0 0] 36 'Decoder-Section-2-UpReLU' ReLU ReLU 37 'Decoder-Section-2-DepthConcatenation' Depth concatenation Depth concatenation of 2 inputs 38 'Decoder-Section-2-Conv-1' Convolution 256 3×3×512 convolutions with stride [1 1] and padding [1 1 1 1] 39 'Decoder-Section-2-ReLU-1' ReLU ReLU 40 'Decoder-Section-2-Conv-2' Convolution 256 3×3×256 convolutions with stride [1 1] and padding [1 1 1 1] 41 'Decoder-Section-2-ReLU-2' ReLU ReLU 42 'Decoder-Section-3-UpConv' Transposed Convolution 128 2×2×256 transposed convolutions with stride [2 2] and cropping [0 0 0 0] 43 'Decoder-Section-3-UpReLU' ReLU ReLU 44 'Decoder-Section-3-DepthConcatenation' Depth concatenation Depth concatenation of 2 inputs 45 'Decoder-Section-3-Conv-1' Convolution 128 3×3×256 convolutions with stride [1 1] and padding [1 1 1 1] 46 'Decoder-Section-3-ReLU-1' ReLU ReLU 47 'Decoder-Section-3-Conv-2' Convolution 128 3×3×128 convolutions with stride [1 1] and padding [1 1 1 1] 48 'Decoder-Section-3-ReLU-2' ReLU ReLU 49 'Decoder-Section-4-UpConv' Transposed Convolution 64 2×2×128 transposed convolutions with stride [2 2] and cropping [0 0 0 0] 50 'Decoder-Section-4-UpReLU' ReLU ReLU 51 'Decoder-Section-4-DepthConcatenation' Depth concatenation Depth concatenation of 2 inputs 52 'Decoder-Section-4-Conv-1' Convolution 64 3×3×128 convolutions with stride [1 1] and padding [1 1 1 1] 53 'Decoder-Section-4-ReLU-1' ReLU ReLU 54 'Decoder-Section-4-Conv-2' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 55 'Decoder-Section-4-ReLU-2' ReLU ReLU 56 'Final-ConvolutionLayer' Convolution 18 1×1×64 convolutions with stride [1 1] and padding [0 0 0 0] 57 'Softmax-Layer' Softmax softmax 58 'Segmentation-Layer' Pixel Classification Layer Cross-entropy loss
Обучите сеть с помощью стохастического градиентного спуска с импульсом (SGDM) оптимизация. Задайте установки гиперпараметров для SGDM при помощи trainingOptions
функция.
Обучение глубокой сети длительно. Ускорьте обучение путем определения высокой скорости обучения. Однако это может заставить градиенты сети взрываться или расти неудержимо, предотвратив сеть от обучения успешно. Чтобы сохранить градиенты в значимой области значений, включите усечение градиента путем определения 'GradientThreshold'
как 0.05
, и задайте 'GradientThresholdMethod'
использовать L2-норму градиентов.
initialLearningRate = 0.05; maxEpochs = 150; minibatchSize = 16; l2reg = 0.0001; options = trainingOptions('sgdm',... 'InitialLearnRate',initialLearningRate, ... 'Momentum',0.9,... 'L2Regularization',l2reg,... 'MaxEpochs',maxEpochs,... 'MiniBatchSize',minibatchSize,... 'LearnRateSchedule','piecewise',... 'Shuffle','every-epoch',... 'GradientThresholdMethod','l2norm',... 'GradientThreshold',0.05, ... 'Plots','training-progress', ... 'VerboseFrequency',20);
По умолчанию пример загружает предварительно обученную версию U-Net для этого набора данных с помощью downloadTrainedUnet
функция помощника. Эта функция присоединена к примеру как вспомогательный файл. Предварительно обученная сеть позволяет вам запустить целый пример, не имея необходимость ожидать обучения завершиться.
Чтобы обучить сеть, установите doTraining
переменная в следующем коде к true
. Обучите модель при помощи trainNetwork
функция.
Обучайтесь на графическом процессоре, если вы доступны. Используя графический процессор требует Parallel Computing Toolbox™, и CUDA® включил NVIDIA® графический процессор. Для получения дополнительной информации смотрите Поддержку графического процессора Релизом (Parallel Computing Toolbox). Обучение занимает приблизительно 20 часов на Титане NVIDIA X.
doTraining = false; if doTraining [net,info] = trainNetwork(dsTrain,lgraph,options); modelDateTime = string(datetime('now','Format',"yyyy-MM-dd-HH-mm-ss")); save(strcat("multispectralUnet-",modelDateTime,"-Epoch-",num2str(maxEpochs),".mat"),'net'); else trainedUnet_url = 'https://www.mathworks.com/supportfiles/vision/data/multispectralUnet.mat'; downloadTrainedUnet(trainedUnet_url,imageDir); load(fullfile(imageDir,'trainedUnet','multispectralUnet.mat')); end
Можно теперь использовать U-Net, чтобы семантически сегментировать многоспектральное изображение.
Чтобы выполнить форварда передают обучивший сеть, используют функцию помощника, segmentImage
, с набором данных валидации. Эта функция присоединена к примеру как вспомогательный файл. segmentImage
выполняет сегментацию на закрашенных фигурах изображений с помощью semanticseg
(Computer Vision Toolbox) функция.
predictPatchSize = [1024 1024]; segmentedImage = segmentImage(val_data,net,predictPatchSize);
Чтобы извлечь только допустимый фрагмент сегментации, умножьте сегментированное изображение на канал маски данных о валидации.
segmentedImage = uint8(val_data(:,:,7)~=0) .* segmentedImage;
figure
imshow(segmentedImage,[])
title('Segmented Image')
Выход семантической сегментации является шумным. Выполните обработку изображений сообщения, чтобы удалить шум и случайные пиксели. Используйте medfilt2
(Image Processing Toolbox) функция, чтобы удалить шум соли-и-перца из сегментации. Визуализируйте сегментированное изображение с удаленным шумом.
segmentedImage = medfilt2(segmentedImage,[7,7]);
imshow(segmentedImage,[]);
title('Segmented Image with Noise Removed')
Наложите сегментированное изображение на компенсируемом гистограммой изображении валидации RGB.
B = labeloverlay(histeq(val_data(:,:,[3 2 1])),segmentedImage,'Transparency',0.8,'Colormap',cmap); figure imshow(B) title('Labeled Validation Image') colorbar('TickLabels',cellstr(classNames),'Ticks',ticks,'TickLength',0,'TickLabelInterpreter','none'); colormap(cmap)
Сохраните сегментированный образ и метки основной истины как файлы PNG. Они будут использованными для расчета метриками точности.
imwrite(segmentedImage,'results.png'); imwrite(val_labels,'gtruth.png');
Создайте pixelLabelDatastore
(Computer Vision Toolbox) для сегментации заканчивается и метки основной истины.
pxdsResults = pixelLabelDatastore('results.png',classNames,pixelLabelIds); pxdsTruth = pixelLabelDatastore('gtruth.png',classNames,pixelLabelIds);
Измерьте глобальную точность семантической сегментации при помощи evaluateSemanticSegmentation
(Computer Vision Toolbox) функция.
ssm = evaluateSemanticSegmentation(pxdsResults,pxdsTruth,'Metrics','global-accuracy');
Evaluating semantic segmentation results ---------------------------------------- * Selected metrics: global accuracy. * Processed 1 images. * Finalizing... Done. * Data set metrics: GlobalAccuracy ______________ 0.90698
Глобальный счет точности указывает, что чуть более чем 90% пикселей классифицируются правильно.
Итоговая цель этого примера состоит в том, чтобы вычислить степень растительного покрова в многоспектральном изображении.
Найдите количество пикселей помеченной растительностью. Метка IDs 2 ("Деревья"), 13 ("LowLevelVegetation"), и 14 ("Grass_Lawn") является классами растительности. Также найдите общее количество допустимых пикселей путем подведения итогов пикселей в ROI рисунка маски.
vegetationClassIds = uint8([2,13,14]); vegetationPixels = ismember(segmentedImage(:),vegetationClassIds); validPixels = (segmentedImage~=0); numVegetationPixels = sum(vegetationPixels(:)); numValidPixels = sum(validPixels(:));
Вычислите процент растительного покрова путем деления количества пикселей растительности количеством допустимых пикселей.
percentVegetationCover = (numVegetationPixels/numValidPixels)*100;
fprintf('The percentage of vegetation cover is %3.2f%%.',percentVegetationCover);
The percentage of vegetation cover is 51.72%.
[1] Kemker, R., К. Сальвагхио и К. Кэнэн. "Многоспектральный Набор данных с высоким разрешением для Семантической Сегментации". CoRR, abs/1703.01918. 2017.
[2] Ronneberger, O., П. Фишер и Т. Брокс. "U-Net: Сверточные Сети для Биомедицинской Сегментации Изображений". CoRR, abs/1505.04597. 2015.
trainingOptions
| trainNetwork
| randomPatchExtractionDatastore
(Image Processing Toolbox) | pixelLabelDatastore
(Computer Vision Toolbox) | semanticseg
(Computer Vision Toolbox) | evaluateSemanticSegmentation
(Computer Vision Toolbox) | imageDatastore
| histeq
(Image Processing Toolbox) | unetLayers
(Computer Vision Toolbox)