exponenta event banner

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

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

См. также

| | | | | | | (глубоко изучение комплекта инструментов) | (инструментарий для глубокого обучения)

Связанные темы

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