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

В этом примере показано, как использовать методы семантической сегментации на основе глубокого обучения для расчета процентного содержания растительного покрова в регионе на основе набора многоспектральных изображений.
В этом примере используется многоспектральный набор данных высокого разрешения для обучения сети [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
Данные многоспектрального изображения расположены в виде массивов numChannel-by-width-by-height. Однако в MATLAB ® многоканальные изображения располагаются в виде массивов width-by-height-by-numChannel. Чтобы изменить форму данных таким образом, чтобы каналы находились в третьем измерении, используйте вспомогательную функцию ,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 функция.
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 title('Training Labels') imshow(B) 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');
Используйте хранилище данных случайного извлечения исправлений для передачи обучающих данных в сеть. Это хранилище данных извлекает несколько соответствующих случайных исправлений из хранилища данных изображения и хранилища данных метки пикселя, которые содержат изображения истинности земли и данные метки пикселя. Исправление является обычным методом предотвращения нехватки памяти для больших изображений и эффективного увеличения объема доступных обучающих данных.
Начните с сохранения обучающих изображений из 'train_data.mat' в imageDatastore. Поскольку формат файла MAT является нестандартным форматом изображения, для включения чтения данных изображения необходимо использовать средство чтения файлов MAT. Можно использовать средство чтения файлов MAT, matReader, который извлекает первые шесть каналов из обучающих данных и пропускает последний канал, содержащий маску. Эта функция присоединена к примеру как вспомогательный файл.
imds = imageDatastore('train_data.mat','FileExtensions','.mat','ReadFcn',@matReader);
Создать pixelLabelDatastore для хранения фрагментов меток, содержащих 18 помеченных областей.
pixelLabelIds = 1:18;
pxds = pixelLabelDatastore('train_labels.png',classNames,pixelLabelIds);Создать randomPatchExtractionDatastore из хранилища данных изображения и хранилища данных метки пикселя. Каждая мини-партия содержит 16 патчей размером 256 на 256 пикселей. На каждой итерации эпохи извлекается тысяча мини-партий.
dsTrain = randomPatchExtractionDatastore(imds,pxds,[256,256],'PatchesPerImage',16000);Хранилище данных для случайного извлечения исправлений dsTrain предоставляет мини-пакеты данных в сеть на каждой итерации эпохи. Просмотрите хранилище данных для просмотра данных.
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)
58x1 Layer array with layers:
1 'ImageInputLayer' Image Input 256x256x6 images with 'zerocenter' normalization
2 'Encoder-Section-1-Conv-1' Convolution 64 3x3x6 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 3x3x64 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 2x2 max pooling with stride [2 2] and padding [0 0 0 0]
7 'Encoder-Section-2-Conv-1' Convolution 128 3x3x64 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 3x3x128 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 2x2 max pooling with stride [2 2] and padding [0 0 0 0]
12 'Encoder-Section-3-Conv-1' Convolution 256 3x3x128 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 3x3x256 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 2x2 max pooling with stride [2 2] and padding [0 0 0 0]
17 'Encoder-Section-4-Conv-1' Convolution 512 3x3x256 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 3x3x512 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 2x2 max pooling with stride [2 2] and padding [0 0 0 0]
23 'Mid-Conv-1' Convolution 1024 3x3x512 convolutions with stride [1 1] and padding [1 1 1 1]
24 'Mid-ReLU-1' ReLU ReLU
25 'Mid-Conv-2' Convolution 1024 3x3x1024 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 2x2x1024 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 3x3x1024 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 3x3x512 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 2x2x512 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 3x3x512 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 3x3x256 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 2x2x256 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 3x3x256 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 3x3x128 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 2x2x128 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 3x3x128 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 3x3x64 convolutions with stride [1 1] and padding [1 1 1 1]
55 'Decoder-Section-4-ReLU-2' ReLU ReLU
56 'Final-ConvolutionLayer' Convolution 18 1x1x64 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 (Deep Learning Toolbox).
Обучение глубокой сети занимает много времени. Ускорьте обучение, указав высокий уровень обучения. Однако это может привести к взрыву или неконтролируемому росту градиентов сети, препятствуя успешному обучению сети. Чтобы сохранить градиенты в значимом диапазоне, включите отсечение градиента, указав 'GradientThreshold' как 0.05, и указать 'GradientThresholdMethod' для использования L2-norm градиентов.
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 (Deep Learning Toolbox).
Обучение на GPU, если он доступен. Для использования графического процессора требуются параллельные вычислительные Toolbox™ и графический процессор NVIDIA ® с поддержкой CUDA ®. Дополнительные сведения см. в разделе Поддержка графического процессора по выпуску (Панель инструментов параллельных вычислений). Обучение занимает около 20 часов на NVIDIA Titan 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 функция.
predictPatchSize = [1024 1024]; segmentedImage = segmentImage(val_data,net,predictPatchSize);
Чтобы извлечь только допустимую часть сегментации, умножьте сегментированное изображение на канал маски данных проверки.
segmentedImage = uint8(val_data(:,:,7)~=0) .* segmentedImage;
figure
imshow(segmentedImage,[])
title('Segmented Image')
Выход семантической сегментации шумен. Выполните постобработку изображения для удаления шумов и паразитных пикселей. Используйте medfilt2 функция удаления солево-перцового шума из сегментации. Визуализация сегментированного изображения с удалением шума.
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 для результатов сегментации и меток истинности основания.
pxdsResults = pixelLabelDatastore('results.png',classNames,pixelLabelIds); pxdsTruth = pixelLabelDatastore('gtruth.png',classNames,pixelLabelIds);
Измерьте глобальную точность семантической сегментации с помощью evaluateSemanticSegmentation функция.
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% пикселей классифицированы правильно.
Конечная цель этого примера заключается в расчете объема растительного покрова на многоспектральном изображении.
Найдите число пикселов, помеченных растительностью. Идентификаторы меток 2 («Деревья»), 13 («LowLeign Vegetation») и 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] Кемкер, Р., С. Сальваджо и К. Канан. «Многоспектральный набор данных высокого разрешения для семантической сегментации». CoRR, abs/1703.01918. 2017.
[2] Ronneberger, O., П. Фишер и Т. Брокс. «U-Net: сверточные сети для сегментации биомедицинских изображений». CoRR, abs/1505.04597. 2015.
evaluateSemanticSegmentation | histeq | imageDatastore | pixelLabelDatastore | randomPatchExtractionDatastore | semanticseg | unetLayers | trainingOptions (глубоко изучение комплекта инструментов) | trainNetwork (инструментарий для глубокого обучения)