Семантическая Сегментация многоспектральных изображений Используя глубокое обучение

В этом примере показано, как выполнить семантическую сегментацию многоспектрального изображения с семью каналами с помощью 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 функция.

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 изображений и пиксельного datastore метки, которые содержат изображения основной истины и данные о пиксельных метках. Исправление является общим методом, чтобы предотвратить исчерпывание памяти для больших изображений и эффективно увеличить сумму доступных обучающих данных.

Начните путем хранения учебных изображений от '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 от 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. В 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 

Выберите Training Options

Обучите сеть с помощью стохастического градиентного спуска с импульсом (SGDM) оптимизация. Задайте установки гиперпараметров для SGDM при помощи trainingOptions (Deep Learning Toolbox) функция.

Обучение глубокой сети длительно. Ускорьте обучение путем определения высокой скорости обучения. Однако это может заставить градиенты сети взрываться или расти неудержимо, предотвратив сеть от обучения успешно. Чтобы сохранить градиенты в значимой области значений, включите усечение градиента путем определения '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 (Deep Learning Toolbox) функция.

Обучайтесь на графическом процессоре, если вы доступны. Используя графический процессор требует 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 функция.

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% пикселей классифицируются правильно.

Вычислите степень растительного покрова

Итоговая цель этого примера состоит в том, чтобы вычислить степень растительного покрова в многоспектральном изображении.

Найдите количество пикселей помеченной растительностью. Метка 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.

Смотрите также

(Deep Learning Toolbox) | (Deep Learning Toolbox) | | | | | | |

Похожие темы

Внешние веб-сайты

Для просмотра документации необходимо авторизоваться на сайте