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

В этом примере показано, как аппроксимировать операцию фильтрации изображений с помощью многомасштабной сети агрегирования контекста (CAN).

Приближение оператора находит альтернативные способы обработки изображений таким образом, чтобы результат напоминал выход от обычной операции обработки изображений или конвейера. Цель приближения часто состоит в том, чтобы уменьшить время, необходимое для обработки изображения.

Для выполнения операторских приближений было предложено несколько классических и глубокое обучение техник. Некоторые классические методы улучшают эффективность одного алгоритма, но не могут быть обобщены на другие операции. Другой распространенный метод аппроксимирует широкую область значений операций путем применения оператора к копии изображения с низким разрешением, но потеря высокочастотного содержимого ограничивает точность приближения.

Решения для глубокого обучения позволяют аппроксимировать более общие и сложные операции. Например, многомасштабная сеть агрегирования контекста (CAN), представленная Q. Chen [1], может аппроксимировать многомасштабное отображение тонов, передачу фотографического стиля, нелокальное обезвреживание и рисунок карандаша. Multiscale CAN обучает на изображениях с полным разрешением для большей точности при обработке высокочастотных деталей. После обучения сети сеть может обойти обычную операцию обработки и обрабатывать изображения непосредственно.

Этот пример исследует, как обучить multiscale CAN аппроксимировать операцию двусторонней фильтрации изображений, которая уменьшает шум изображения при сохранении резкости ребра. В примере представлен полный рабочий процесс обучения и вывода, который включает процесс создания обучающего datastore, выбора опций обучения, обучения сети и использования сети для обработки тестовых изображений.

Сеть приближения оператора

Многомасштабный CAN обучен минимизации l2 потеря между обычным выходом операции обработки изображений и сетевым откликом после обработки входа изображения с помощью многомасштабной контекстной агрегации. Многомасштабная контекстная агрегация ищет информацию о каждом пикселе со всего изображения, а не ограничивает поиск небольшим соседством, окружающим пиксель.

Чтобы помочь сети узнать глобальные свойства изображений, многомасштабная архитектура CAN имеет большое восприимчивое поле. Первый и последний слои имеют одинаковый размер, потому что оператор не должен изменять размер изображения. Последующие промежуточные слои расширены экспоненциально увеличивающимися масштабными факторами (отсюда и «многомасштабная» природа CAN). Расширение позволяет сети искать пространственно разделённые функции на различных пространственных частотах, не снижая разрешение изображения. После каждого слоя свертки сеть использует адаптивную нормализацию, чтобы сбалансировать влияние нормализации партии . и единичного отображения на аппроксимированный оператор.

Загрузка обучающих и тестовых данных

Загрузите IAPR TC-12 Benchmark, который состоит из 20 000 все еще естественных изображений [2]. Набор данных включает фотографии людей, животных, городов и многое другое. Размер файла данных составляет ~ 1,8 ГБ. Если вы не хотите загружать обучающий набор обучающих данных, необходимый для обучения сети, то можно загрузить предварительно обученный CAN, набрав load('trainedOperatorLearning-Epoch-181.mat'); в командной строке. Затем перейдите непосредственно к разделу «Выполнение двухсторонней фильтрации приближения с использованием многомасштабного CAN» в этом примере.

imagesDir = tempdir;
url_1 = 'http://www-i6.informatik.rwth-aachen.de/imageclef/resources/iaprtc12.tgz';
downloadIAPRTC12Data(url_1,imagesDir);

Этот пример обучает сеть с небольшим подмножеством данных IAPRTC-12 Benchmark.

trainImagesDir = fullfile(imagesDir,'iaprtc12','images','39');
exts = {'.jpg','.bmp','.png'};
pristineImages = imageDatastore(trainImagesDir,'FileExtensions',exts);

Перечислите количество обучающих изображений.

numel(pristineImages.Files)
ans = 916

Подготовка обучающих данных

Чтобы создать обучающие данные набор, читайте в нетронутых изображениях и выписывайте изображения, которые были отфильтрованы по двусторонним каналам. Отфильтрованные изображения хранятся на диске в директории, заданной preprocessDataDir.

preprocessDataDir = [trainImagesDir filesep 'preprocessedDataset'];

Используйте функцию helper bilateralFilterDataset для предварительной обработки обучающих данных. Эта функция присоединена к примеру как вспомогательный файл.

Функция helper выполняет эти операции для каждого первозданного изображения в inputImages:

  • Вычислите степень сглаживания для двусторонней фильтрации. Сглаживание фильтрованного изображения уменьшает шум изображения.

  • Выполните двустороннюю фильтрацию с помощью imbilatfilt (Image Processing Toolbox).

  • Сохраните отфильтрованное изображение на диск с помощью imwrite.

bilateralFilterDataset(pristineImages,preprocessDataDir);

Задайте Datastore извлечения случайных закрашенных фигур для обучения

Используйте datastore случайного извлечения закрашенных фигур, чтобы передать обучающие данные в сеть. Этот datastore извлекает случайные соответствующие закрашенные фигуры из двух хранилищ данных изображений, которые содержат входы сети и желаемые сетевые отклики.

В этом примере сетевые входы являются первозданными изображениями в pristineImages. Желаемыми сетевыми откликами являются обработанные изображения после двусторонней фильтрации. Создайте изображение datastore под названием bilatFilteredImages из набора двусторонних фильтрованных файлов изображений.

bilatFilteredImages = imageDatastore(preprocessDataDir,'FileExtensions',exts);

Создайте randomPatchExtractionDatastore (Image Processing Toolbox) из двух хранилищ данных изображений. Задайте размер закрашенной фигуры 256 на 256 пикселей. Задайте 'PatchesPerImage', чтобы извлечь один случайно расположенный закрашенную фигуру из каждой пары изображений во время обучения. Задайте размер мини-пакета, равный единице.

miniBatchSize = 1;
patchSize = [256 256];
dsTrain = randomPatchExtractionDatastore(pristineImages,bilatFilteredImages,patchSize, ....
    'PatchesPerImage',1);
dsTrain.MiniBatchSize = miniBatchSize;

The randomPatchExtractionDatastore предоставляет мини-пакеты данных в сеть в каждую итерацию эпохи. Выполните операцию read на datastore, чтобы исследовать данные.

inputBatch = read(dsTrain);
disp(inputBatch)
       InputImage          ResponseImage  
    _________________    _________________

    {256×256×3 uint8}    {256×256×3 uint8}

Настройка многоуровневых слоев CAN

Этот пример задает многомасштабный CAN с использованием слоев из Deep Learning Toolbox™, включая:

  • imageInputLayer - Входной слой изображения

  • convolution2dLayer - 2D слой свертки для сверточных нейронных сетей

  • batchNormalizationLayer - Слой нормализации партии .

  • leakyReluLayer - Утечка выпрямленного слоя линейного модуля

  • regressionLayer - Регрессионный выходной слой для нейронной сети

Для реализации адаптивного слоя нормализации партии . добавляются два пользовательских слоя шкалы. Эти слои присоединены как вспомогательные файлы к этому примеру.

  • adaptiveNormalizationMu - Масштабный слой, который корректирует сильные стороны ветви нормализации партии .

  • adaptiveNormalizationLambda - Шкала слой, который корректирует сильные стороны тождеств ветви

Первый слой, imageInputLayer, работает с закрашенными фигурами изображений. Размер закрашенной фигуры основан на сетевом приемном поле, которое является пространственной областью изображения, которая влияет на ответ самого верхнего слоя в сети. В идеале сетевое поле приема совпадает с размером изображения, так что оно может видеть все функции высокого уровня в изображении. Для двустороннего фильтра размер закрашенной фигуры изображения приближения прикреплен к 256 на 256.

networkDepth = 10;
numberOfFilters = 32;
firstLayer = imageInputLayer([256 256 3],'Name','InputLayer','Normalization','none');

За входным слоем изображения следует слой свертки 2-D, который содержит 32 фильтра размера 3 на 3. Обнулите входы каждого слоя свертки так, чтобы карты функций оставались такими же размерами, как вход после каждой свертки. Инициализируйте веса к матрице тождеств.

Wgts = zeros(3,3,3,numberOfFilters); 
for ii = 1:3
    Wgts(2,2,ii,ii) = 1;
end
convolutionLayer = convolution2dLayer(3,numberOfFilters,'Padding',1, ...
    'Weights',Wgts,'Name','Conv1');

Каждый слой свертки сопровождается слоем нормализации партии . и слоем адаптивной шкалы нормализации, который регулирует сильные стороны ветви нормализации партии .. Позже этот пример создаст соответствующий адаптивный слой шкалы нормализации, который корректирует прочность тождеств ветви. Пока следуйте adaptiveNormalizationMu слой с сложением слоем. Наконец, задайте утечку слоя ReLU со скалярным умножителем 0.2 для отрицательных входов.

batchNorm = batchNormalizationLayer('Name','BN1');
adaptiveMu = adaptiveNormalizationMu(numberOfFilters,'Mu1');
addLayer = additionLayer(2,'Name','add1');
leakyrelLayer = leakyReluLayer(0.2,'Name','Leaky1');

Задайте средние слои сети, следующие тому же шаблону. Последовательные слои свертки имеют коэффициент расширения, который масштабируется экспоненциально с глубиной сети.

middleLayers = [convolutionLayer batchNorm adaptiveMu addLayer leakyrelLayer];
    
Wgts = zeros(3,3,numberOfFilters,numberOfFilters);
for ii = 1:numberOfFilters
    Wgts(2,2,ii,ii) = 1;
end
    
for layerNumber = 2:networkDepth-2
    dilationFactor = 2^(layerNumber-1);
    padding = dilationFactor;
    conv2dLayer = convolution2dLayer(3,numberOfFilters, ...
        'Padding',padding,'DilationFactor',dilationFactor, ...
        'Weights',Wgts,'Name',['Conv' num2str(layerNumber)]);
    batchNorm = batchNormalizationLayer('Name',['BN' num2str(layerNumber)]);
    adaptiveMu = adaptiveNormalizationMu(numberOfFilters,['Mu' num2str(layerNumber)]);
    addLayer = additionLayer(2,'Name',['add' num2str(layerNumber)]);
    leakyrelLayer = leakyReluLayer(0.2, 'Name', ['Leaky' num2str(layerNumber)]);
    middleLayers = [middleLayers conv2dLayer batchNorm adaptiveMu addLayer leakyrelLayer];    
end

Не применяйте коэффициент расширения ко второму к последнему слою свертки.

conv2dLayer = convolution2dLayer(3,numberOfFilters, ...
    'Padding',1,'Weights',Wgts,'Name','Conv9');

batchNorm = batchNormalizationLayer('Name','AN9');
adaptiveMu = adaptiveNormalizationMu(numberOfFilters,'Mu9');
addLayer = additionLayer(2,'Name','add9');
leakyrelLayer = leakyReluLayer(0.2,'Name','Leaky9');
middleLayers = [middleLayers conv2dLayer batchNorm adaptiveMu addLayer leakyrelLayer];

У последнего слоя скручивания есть единственный фильтр размера 1 на 1 на 32 на 3, который восстанавливает изображение.

Wgts = sqrt(2/(9*numberOfFilters))*randn(1,1,numberOfFilters,3);
conv2dLayer = convolution2dLayer(1,3,'NumChannels',numberOfFilters, ...
    'Weights',Wgts,'Name','Conv10');

Последний слой является регрессионным слоем вместо утечки слоя ReLU. Регрессионный слой вычисляет среднюю квадратную ошибку между двухсторонним фильтрованным изображением и сетевым предсказанием.

finalLayers = [conv2dLayer 
    regressionLayer('Name','FinalRegressionLayer')
];

Сцепить все слои.

layers = [firstLayer middleLayers finalLayers'];
lgraph = layerGraph(layers);

Создайте скиповые соединения, которые выступают в качестве единичной ветви для адаптивного уравнения нормализации. Соедините пропущенные соединения со слоями сложения.

skipConv1 = adaptiveNormalizationLambda(numberOfFilters,'Lambda1');
skipConv2 = adaptiveNormalizationLambda(numberOfFilters,'Lambda2');
skipConv3 = adaptiveNormalizationLambda(numberOfFilters,'Lambda3');
skipConv4 = adaptiveNormalizationLambda(numberOfFilters,'Lambda4');
skipConv5 = adaptiveNormalizationLambda(numberOfFilters,'Lambda5');
skipConv6 = adaptiveNormalizationLambda(numberOfFilters,'Lambda6');
skipConv7 = adaptiveNormalizationLambda(numberOfFilters,'Lambda7');
skipConv8 = adaptiveNormalizationLambda(numberOfFilters,'Lambda8');
skipConv9 = adaptiveNormalizationLambda(numberOfFilters,'Lambda9');

lgraph = addLayers(lgraph,skipConv1);
lgraph = connectLayers(lgraph,'Conv1','Lambda1');
lgraph = connectLayers(lgraph,'Lambda1','add1/in2');

lgraph = addLayers(lgraph,skipConv2);
lgraph = connectLayers(lgraph,'Conv2','Lambda2');
lgraph = connectLayers(lgraph,'Lambda2','add2/in2');

lgraph = addLayers(lgraph,skipConv3);
lgraph = connectLayers(lgraph,'Conv3','Lambda3');
lgraph = connectLayers(lgraph,'Lambda3','add3/in2');

lgraph = addLayers(lgraph,skipConv4);
lgraph = connectLayers(lgraph,'Conv4','Lambda4');
lgraph = connectLayers(lgraph,'Lambda4','add4/in2');

lgraph = addLayers(lgraph,skipConv5);
lgraph = connectLayers(lgraph,'Conv5','Lambda5');
lgraph = connectLayers(lgraph,'Lambda5','add5/in2');

lgraph = addLayers(lgraph,skipConv6);
lgraph = connectLayers(lgraph,'Conv6','Lambda6');
lgraph = connectLayers(lgraph,'Lambda6','add6/in2');

lgraph = addLayers(lgraph,skipConv7);
lgraph = connectLayers(lgraph,'Conv7','Lambda7');
lgraph = connectLayers(lgraph,'Lambda7','add7/in2');

lgraph = addLayers(lgraph,skipConv8);
lgraph = connectLayers(lgraph,'Conv8','Lambda8');
lgraph = connectLayers(lgraph,'Lambda8','add8/in2');

lgraph = addLayers(lgraph,skipConv9);
lgraph = connectLayers(lgraph,'Conv9','Lambda9');
lgraph = connectLayers(lgraph,'Lambda9','add9/in2');

Постройте график графика слоев.

plot(lgraph)

Настройка опций обучения

Обучите сеть с помощью оптимизатора Adam. Задайте установки гиперпараметров при помощи trainingOptions функция. Используйте значения по умолчанию 0.9 для 'Momentum0.0001 для 'L2Regularization'(массовый распад). Задайте постоянную скорость обучения 0.0001. Train на 181 эпоху.

maxEpochs = 181;
initLearningRate = 0.0001;
miniBatchSize = 1;

options = trainingOptions('adam', ...
    'InitialLearnRate',initLearningRate, ...
    'MaxEpochs',maxEpochs, ...
    'MiniBatchSize',miniBatchSize, ...
    'Plots','training-progress', ...
    'Verbose',false);

Обучите сеть

По умолчанию пример загружает предварительно обученный многомасштабный CAN, который аппроксимирует двусторонний фильтр. Предварительно обученная сеть позволяет вам выполнить приближение двусторонней фильтрации, не дожидаясь завершения обучения.

Чтобы обучить сеть, установите doTraining переменная в следующем коде, для true. Обучите многомасштабный CAN с помощью trainNetwork функция.

Обучите на графическом процессоре, если он доступен. Для использования GPU требуется Parallel Computing Toolbox™ и графический процессор с поддержкой CUDA ® NVIDIA ®. Для получения дополнительной информации смотрите Поддержку GPU by Release (Parallel Computing Toolbox). Обучение занимает около 15 часов на NVIDIA™ Titan X.

doTraining = false;
if doTraining
    modelDateTime = string(datetime('now','Format',"yyyy-MM-dd-HH-mm-ss"));
    net = trainNetwork(dsTrain,lgraph,options);
    save(strcat("trainedOperatorLearning-",modelDateTime,"-Epoch-",num2str(maxEpochs),".mat"),'net');
else
    load('trainedOperatorLearning-Epoch-181.mat');
end

Выполните двустороннюю фильтрацию Приближения используя Multiscale CAN

Чтобы обработать изображение с помощью обученной многомасштабной сети CAN, которая аппроксимирует двусторонний фильтр, следуйте оставшимся шагам этого примера. Остальная часть примера показывает, как:

  • Создайте выборку шумный вход изображение из ссылки изображения.

  • Выполните обычную двустороннюю фильтрацию шумного изображения с помощью imbilatfilt (Image Processing Toolbox) функция.

  • Выполните приближение к двусторонней фильтрации на шумном изображении с помощью CAN.

  • Визуально сравните деноизированные изображения из операторного приближения и обычной двусторонней фильтрации.

  • Оцените качество деноцированных изображений путем количественной оценки подобия изображений к первозданному эталонному изображению.

Создайте выборку шумного изображения

Создайте выборку шумное изображение, которое будет использоваться для сравнения результатов оператора приближения с обычной двусторонней фильтрацией. Набор тестовых данных, testImages, содержит 21 первозданное изображение, поставляемое в Image Processing Toolbox™. Загрузите изображения в imageDatastore.

exts = {'.jpg','.png'};
fileNames = {'sherlock.jpg','car2.jpg','fabric.png','greens.jpg','hands1.jpg','kobi.png',...
    'lighthouse.png','micromarket.jpg','office_4.jpg','onion.png','pears.png','yellowlily.jpg',...
    'indiancorn.jpg','flamingos.jpg','sevilla.jpg','llama.jpg','parkavenue.jpg',...
    'peacock.jpg','car1.jpg','strawberries.jpg','wagon.jpg'};
filePath = [fullfile(matlabroot,'toolbox','images','imdata') filesep];
filePathNames = strcat(filePath,fileNames);
testImages = imageDatastore(filePathNames,'FileExtensions',exts);

Отобразите тестовые изображения как montage.

montage(testImages)

Выберите одно из изображений для использования в качестве эталонного изображения для двусторонней фильтрации. Преобразуйте изображение в тип данных uint8.

indx = 3; % Index of image to read from the test image datastore
Ireference = readimage(testImages,indx);
Ireference = im2uint8(Ireference);

Вы можете опционально использовать свое собственное изображение в качестве ссылки изображения. Обратите внимание, что размер тестового изображения должен быть не менее 256 на 256. Если тестовое изображение меньше 256 на 256, увеличьте размер изображения при помощи imresize (Image Processing Toolbox) функция. Сети также требуется тестовое изображение RGB. Если тестовое изображение является полутоновым, преобразуйте изображение в RGB с помощью cat функция для конкатенации трех копий оригинального изображения по третьей размерности.

Отобразите эталонное изображение.

imshow(Ireference)
title('Pristine Reference Image')

Используйте imnoise (Image Processing Toolbox) функция для добавления нулевого среднего Гауссова белого шума с отклонением 0,00001 к эталонному изображению.

Inoisy = imnoise(Ireference,'gaussian',0.00001);
imshow(Inoisy)
title('Noisy Image')

Фильтрация изображения с помощью двусторонней фильтрации

Обычная двусторонняя фильтрация является стандартным способом уменьшить шум изображения при сохранении резкости ребра. Используйте imbilatfilt (Image Processing Toolbox) функция для применения двустороннего фильтра к шумному изображению. Задайте степень сглаживания, равную отклонению значений пикселей.

degreeOfSmoothing = var(double(Inoisy(:)));
Ibilat = imbilatfilt(Inoisy,degreeOfSmoothing);
imshow(Ibilat)
title('Denoised Image Obtained Using Bilateral Filtering')

Обработка изображения с помощью обученной сети

Передайте нормированное входное изображение через обученную сеть и наблюдайте за activations от последнего слоя (регрессионного слоя). Выходы сети являются желаемым деноизированным изображением.

Iapprox = activations(net,Inoisy,'FinalRegressionLayer');

Для Image Processing Toolbox™ требуется, чтобы изображения с плавающей точкой имели пиксельные значения в области значений [0, 1]. Используйте rescale функция, чтобы масштабировать значения пикселей в эту область значений, затем преобразует изображение в uint8.

Iapprox = rescale(Iapprox);
Iapprox = im2uint8(Iapprox);
imshow(Iapprox)
title('Denoised Image Obtained Using Multiscale CAN')

Визуальное и количественное сравнение

Чтобы получить лучшее визуальное понимание деноизированных изображений, исследуйте небольшую область внутри каждого изображения. Задайте видимую область (ROI) с помощью вектора roi в формате [x y ширина высота]. Элементы определяют координаты x и y верхнего левого угла, ширину и высоту информация только для чтения.

roi = [300 30 50 50];

Обрезайте изображения в этот информация только для чтения и отобразите результат как монтаж.

montage({imcrop(Ireference,roi),imcrop(Inoisy,roi), ...
    imcrop(Ibilat,roi),imcrop(Iapprox,roi)}, ...
    'Size',[1 4]);
title('Reference Image | Noisy Image | Bilateral-Filtered Image | CAN Prediction');

CAN удаляет больше шума, чем обычная двусторонняя фильтрация. Оба методов сохраняют резкость ребра.

Используйте метрики качества изображения, чтобы количественно сравнить шумное входное изображение, двухстороннее отфильтрованное изображение и аппроксимированное оператором изображение. Эталонное изображение является исходным эталонным изображением, Ireference, перед добавлением шума.

Измерьте отношение пикового сигнала к шуму (PSNR) каждого изображения относительно ссылки изображения. Большие значения PSNR обычно указывают на лучшее качество изображения. См. psnr (Image Processing Toolbox) для получения дополнительной информации об этой метрике.

noisyPSNR = psnr(Inoisy,Ireference);
bilatPSNR = psnr(Ibilat,Ireference);
approxPSNR = psnr(Iapprox,Ireference);
disp(['PSNR of: Noisy Image / Bilateral-Filtered Image / Operator Approximated Image = ', ...
    num2str([noisyPSNR bilatPSNR approxPSNR])])
PSNR of: Noisy Image / Bilateral-Filtered Image / Operator Approximated Image = 20.2857      25.7978      26.2011

Измерьте индекс структурного подобия (SSIM) каждого изображения. SSIM оценивает визуальное влияние трех характеристик изображения: яркость, контрастность и структуру, по сравнению с ссылкой изображением. Чем ближе значение SSIM к 1, тем лучше тестовое изображение согласуется с ссылкой изображением. См. ssim (Image Processing Toolbox) для получения дополнительной информации об этой метрике.

noisySSIM = ssim(Inoisy,Ireference);
bilatSSIM = ssim(Ibilat,Ireference);
approxSSIM = ssim(Iapprox,Ireference);
disp(['SSIM of: Noisy Image / Bilateral-Filtered Image / Operator Approximated Image = ', ...
    num2str([noisySSIM bilatSSIM approxSSIM])])
SSIM of: Noisy Image / Bilateral-Filtered Image / Operator Approximated Image = 0.76251     0.91576     0.92663

Измерьте качество перцептивного изображения с помощью Naturalness Image Quality Evaluator (NIQE). Меньшие счета NIQE указывают на лучшее качество восприятия. См. niqe (Image Processing Toolbox) для получения дополнительной информации об этой метрике.

noisyNIQE = niqe(Inoisy);
bilatNIQE = niqe(Ibilat);
approxNIQE = niqe(Iapprox);
disp(['NIQE score of: Noisy Image / Bilateral-Filtered Image / Operator Approximated Image = ', ...
    num2str([noisyNIQE bilatNIQE approxNIQE])])
NIQE score of: Noisy Image / Bilateral-Filtered Image / Operator Approximated Image = 12.1865      7.22606      6.18105

По сравнению с обычной двусторонней фильтрацией приближение оператора даёт лучшие метрические счета.

Ссылки

[1] Chen, Q. J. Xu, and V. Koltun. «Быстрая обработка изображений с полностью сверточными сетями». В трудах конференции IEEE 2017 по компьютерному зрению. Венеция, Италия, октябрь 2017, стр. 2516-2525.

[2] Грубингер, М., П. Клаф, Х. Мюллер и Т. Дезелаерс. «IAPR TC-12 Benchmark: A New Evaluation Resource for Visual Information Systems». Сведения о языковых ресурсах OntoImage 2006 для поиска изображений на основе содержимого. Генуя, Италия. Том 5, май 2006, стр. 10.

См. также

| | | | | (Image Processing Toolbox) | (Набор Image Processing Toolbox)

Похожие темы