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

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

Пример показывает, как обучить многошкальную сеть CAN, чтобы аппроксимировать двусторонний фильтр, и также обеспечивает предварительно обученную сеть. Если вы принимаете решение обучить сеть, использование CUDA-способного графического процессора NVIDIA™ с вычисляют возможность 3.0, или выше настоятельно рекомендован. Использование графического процессора требует Parallel Computing Toolbox™.

Введение

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

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

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

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

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

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

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

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

Загрузите Сравнительный тест IAPR TC-12, который состоит из 20 000 все еще естественных изображений [2]. Набор данных включает фотографии людей, животных, города и т.д. Размер файла данных составляет ~1.8 Гбайт. Если вы не хотите загружать обучающий набор данных, должен был обучить сеть, то можно загрузить предварительно обученный CAN путем ввода load('trainedOperatorLearning-Epoch-181.mat'); в командной строке. Затем перейдите непосредственно к разделу Perform Bilateral Filtering Approximation Using Multiscale CAN в этом примере.

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

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

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'];

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

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

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

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

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

bilateralFilterDataset(pristineImages,preprocessDataDir);

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

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

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

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

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

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

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

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

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

Настройте многошкальные слои CAN

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

  • imageInputLayer (Deep Learning Toolbox) - Слой входа Image

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

  • batchNormalizationLayer (Deep Learning Toolbox) - Слой нормализации партии.

  • leakyReluLayer (Deep Learning Toolbox) - Текучий исправленный линейный модульный слой

  • regressionLayer (Deep Learning Toolbox) - Regression слой выхода для нейронной сети

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

  • adaptiveNormalizationMu - Слой Scale, который настраивает сильные места ветви нормализации партии.

  • adaptiveNormalizationLambda - Слой Scale, который настраивает сильные места единичной ветви

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

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

Входной слой изображений сопровождается 2D слоем свертки, который содержит 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)

Задайте опции обучения

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

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

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

Обучите сеть

Теперь, когда источник данных и опции обучения сконфигурированы, обучают многошкальный CAN с помощью trainNetwork (Deep Learning Toolbox) function. Чтобы обучить сеть, установите doTraining параметр в следующем коде к true. CUDA-способный графический процессор NVIDIA™ с вычисляет возможность 3.0, или выше настоятельно рекомендован для обучения.

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

Примечание: Обучение обычно занимает приблизительно 15 часов на NVIDIA™ Titan X и может взять еще дольше в зависимости от вашего оборудования графического процессора.

doTraining = false;
if doTraining
    modelDateTime = datestr(now,'dd-mmm-yyyy-HH-MM-SS');
    net = trainNetwork(dsTrain,lgraph,options);
    save(['trainedOperatorLearning-' modelDateTime '-Epoch-' num2str(maxEpochs) '.mat'],'net');
else
    load('trainedOperatorLearning-Epoch-181.mat');
end

Выполните двустороннее приближение фильтрации Используя многошкальный CAN

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

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

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

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

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

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

Создайте демонстрационное шумное изображение

Создайте демонстрационное шумное изображение, которое будет использоваться, чтобы сравнить результаты приближения оператора к обычной двусторонней фильтрации. Набор тестовых данных, 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(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 функция. Сеть также требует тестового изображения RGB. Если тестовое изображение является шкалой полутонов, то преобразуйте изображение в RGB при помощи cat функция, чтобы конкатенировать три копии оригинального изображения по третьему измерению.

Отобразите ссылочное изображение.

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

Используйте imnoise функция, чтобы добавить нулевой средний Гауссов белый шум с отклонением 0,00001 к ссылочному изображению.

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

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

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

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

Изображение процесса Используя обучило сеть

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

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')

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

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

roi = [300 30 50 50];

Обрежьте изображения к этому ROI и отобразите результат как монтаж.

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 для получения дополнительной информации об этой метрике.

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 для получения дополнительной информации об этой метрике.

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

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

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] Чен, Ц. Цз. Сюй и В. Колтун. "Быстрая Обработка изображений с Полностью сверточными Сетями". В Продолжениях 2 017 Конференций по IEEE по Компьютерному зрению. Венеция, Италия, октябрь 2017, стр 2516-2525.

[2] Grubinger, M. P. Ущелье, Х. Мюллер и Т. Дезелэерс. "Сравнительный тест IAPR TC-12: Новый Ресурс Оценки для Визуальных Информационных систем". Продолжения ресурсов OntoImage 2006 Языка Для Извлечения Изображений На основе содержимого. Генуя, Италия. Издание 5, май 2006, p. 10.

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

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

Похожие темы