exponenta event banner

Количественное определение качества изображения с помощью оценки нейронного изображения

В этом примере показано, как анализировать эстетическое качество изображений с помощью сверточной нейронной сети (CNN) Neural Image Assessment (NIMA).

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

NIMA [1] - это метод без ссылок, который предсказывает качество изображения без использования неточного опорного изображения, которое часто недоступно. NIMA использует CNN для прогнозирования распределения показателей качества для каждого изображения.

Оценка качества изображения с использованием обученной модели NIMA

Загрузите предварительно обученную нейронную сеть NIMA с помощью функции помощника downloadTrainedNIMANet. Вспомогательная функция прикрепляется к примеру как вспомогательный файл. Эта модель предсказывает распределение показателей качества для каждого изображения в диапазоне [1, 10], где 1 и 10 являются самыми низкими и самыми высокими возможными значениями для оценки, соответственно. Высокий балл указывает на хорошее качество изображения.

imageDir = fullfile(tempdir,"LIVEInTheWild");
if ~exist(imageDir,'dir')
    mkdir(imageDir);
end
trainedNIMA_url = 'https://ssd.mathworks.com/supportfiles/image/data/trainedNIMA.zip';
downloadTrainedNIMANet(trainedNIMA_url,imageDir);
load(fullfile(imageDir,'trainedNIMA.mat'));

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

Чтение высококачественного изображения в рабочую область.

imOriginal = imread('kobi.png'); 

Уменьшите эстетическое качество изображения, применив размытие по Гауссу. Отображение исходного изображения и размытого изображения при монтаже. Субъективно эстетическое качество размытого изображения хуже, чем качество оригинального изображения.

imBlur = imgaussfilt(imOriginal,5);
montage({imOriginal,imBlur})

Прогнозирование распределения показателей качества NIMA для двух изображений с использованием predictNIMAScore функция помощника. Эта функция присоединена к примеру как вспомогательный файл.

predictNIMAScore функция возвращает среднее и стандартное отклонение распределения баллов NIMA для изображения. Прогнозируемый средний балл является мерой качества изображения. Стандартное отклонение баллов можно считать мерой доверительного уровня прогнозируемого среднего балла.

[meanOriginal,stdOriginal] = predictNIMAScore(dlnet,imOriginal);
[meanBlur,stdBlur] = predictNIMAScore(dlnet,imBlur);

Отображение изображений вместе со средним и стандартным отклонением распределения баллов, прогнозируемым моделью NIMA. The Модель NIMA правильно предсказывает оценки для этих изображений, которые согласуются с субъективной визуальной оценкой.

figure
t = tiledlayout(1,2);
displayImageAndScoresForNIMA(t,imOriginal,meanOriginal,stdOriginal,"Original Image")
displayImageAndScoresForNIMA(t,imBlur,meanBlur,stdBlur,"Blurred Image")

В остальном примере показано, как обучать и оценивать модель NIMA.

Загрузить LIVE в Wild Data Set

В этом примере используется набор данных LIVE In the Wild [2], который представляет собой общедоступную базу данных субъективных запросов качества изображения. Набор данных содержит 1162 фотографии, снятые мобильными устройствами, с 7 дополнительными изображениями, предоставленными для обучения человеческих бомбардиров. Каждое изображение оценивается в среднем 175 особями по шкале [1, 100]. Набор данных обеспечивает среднее и стандартное отклонение субъективных оценок для каждого изображения.

Загрузите набор данных, следуя инструкциям, приведенным в разделе LIVE In the Wild Image Quality Challenge Database. Извлеките данные в каталог, указанный imageDir переменная. При успешном извлечении imageDir содержит два каталога: Data и Images.

Загрузить LIVE в Wild Data

Получите пути к изображениям.

imageData = load(fullfile(imageDir,'Data','AllImages_release.mat'));
imageData = imageData.AllImages_release;
nImg = length(imageData);
imageList(1:7) = fullfile(imageDir,'Images','trainingImages',imageData(1:7));
imageList(8:nImg) = fullfile(imageDir,'Images',imageData(8:end));

Создайте хранилище данных изображения, которое управляет данными изображения.

imds = imageDatastore(imageList);

Загрузите данные среднего и стандартного отклонения, соответствующие изображениям.

meanData = load(fullfile(imageDir,'Data','AllMOS_release.mat'));
meanData = meanData.AllMOS_release;
stdData = load(fullfile(imageDir,'Data','AllStdDev_release.mat'));
stdData = stdData.AllStdDev_release;

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

figure
t = tiledlayout(1,3);
idx1 = 785;
displayImageAndScoresForNIMA(t,readimage(imds,idx1), ...
    meanData(idx1),stdData(idx1),"Image "+imageData(idx1))
idx2 = 203;
displayImageAndScoresForNIMA(t,readimage(imds,idx2), ...
    meanData(idx2),stdData(idx2),"Image "+imageData(idx2))
idx3 = 777;
displayImageAndScoresForNIMA(t,readimage(imds,idx3), ...
    meanData(idx3),stdData(idx3),"Image "+imageData(idx3))

Данные предварительной обработки и дополнения

Выполните предварительную обработку изображений, изменив их размер до 256 на 256 пикселей.

rescaleSize = [256 256];
imds = transform(imds,@(x)imresize(x,rescaleSize));

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

createNIMAScoreDistribution масштабирует баллы до диапазона [1, 10], затем генерирует распределение максимальной энтропии баллов из значений среднего и стандартного отклонения.

newMaxScore = 10;
prob = createNIMAScoreDistribution(meanData,stdData);
cumProb = cumsum(prob,2);

Создание arrayDatastore который управляет распределением баллов.

probDS = arrayDatastore(cumProb','IterationDimension',2); 

Объединение хранилищ данных, содержащих данные изображения и данные распределения баллов.

dsCombined = combine(imds,probDS);

Предварительный просмотр результатов чтения из объединенного хранилища данных.

sampleRead = preview(dsCombined)
sampleRead=1×2 cell array
    {256×256×3 uint8}    {10×1 double}

figure
tiledlayout(1,2)
nexttile
imshow(sampleRead{1})
title("Sample Image from Data Set")
nexttile
plot(sampleRead{2})
title("Cumulative Score Distribution")

Разделение данных для обучения, проверки и тестирования

Разбейте данные на обучающие, проверочные и тестовые наборы. Распределите 70% данных для обучения, 15% - для проверки, а остальные - для тестирования.

numTrain = floor(0.70 * nImg);
numVal = floor(0.15 * nImg);

Idx = randperm(nImg);
idxTrain = Idx(1:numTrain);
idxVal = Idx(numTrain+1:numTrain+numVal);
idxTest = Idx(numTrain+numVal+1:nImg);

dsTrain = subset(dsCombined,idxTrain);
dsVal = subset(dsCombined,idxVal);
dsTest = subset(dsCombined,idxTest);

Дополнительные данные по обучению

Увеличение данных обучения с помощью augmentImageTest функция помощника. Эта функция присоединена к примеру как вспомогательный файл. augmentDataForNIMA функция выполняет следующие операции по увеличению на каждом обучающем изображении:

  • Обрезайте изображение до 224 на 244 пикселов, чтобы уменьшить переоборудование.

  • Переверните изображение по горизонтали с вероятностью 50%.

inputSize = [224 224];
dsTrain = transform(dsTrain,@(x)augmentDataForNIMA(x,inputSize));

Расчет статистики обучающего набора для нормализации входных данных

Входной уровень сети выполняет нормализацию по шкале z обучающих изображений. Рассчитайте среднее и стандартное отклонение обучающих изображений для использования в нормализации z-показателя.

meanImage = zeros([inputSize 3]);
meanImageSq = zeros([inputSize 3]);
while hasdata(dsTrain)
    dat = read(dsTrain);
    img = double(dat{1});
    meanImage = meanImage + img;
    meanImageSq = meanImageSq + img.^2;
end
meanImage = meanImage/numTrain;
meanImageSq = meanImageSq/numTrain;
varImage = meanImageSq - meanImage.^2;
stdImage = sqrt(varImage);

Восстановите исходное состояние хранилища данных.

reset(dsTrain);

Загрузите и измените сеть MobileNet-v2

Этот пример начинается с MobileNet-v2 [3] CNN, обученного на ImageNet [4]. Пример модифицирует сеть, заменяя последний уровень MobileNet-v2 сети полностью связанным слоем с 10 нейронами, каждый из которых представляет дискретную оценку от 1 до 10. Сеть прогнозирует вероятность каждого балла для каждого изображения. Пример нормализует выходы полностью подключенного уровня с помощью уровня активации softmax.

mobilenetv2 функция возвращает предварительно подготовленную сеть MobileNet-v2. Для этой функции требуется модель Deep Learning Toolbox™ для пакета поддержки MobileNet-v2 Network. Если этот пакет поддержки не установлен, функция предоставляет ссылку для загрузки.

net = mobilenetv2;

Преобразование сети в layerGraph объект.

lgraph = layerGraph(net);

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

inLayer = imageInputLayer([inputSize 3],'Name','input','Normalization','zscore','Mean',meanImage,'StandardDeviation',stdImage);
lgraph = replaceLayer(lgraph,'input_1',inLayer);

Замените исходный окончательный классификационный слой полностью связанным слоем с 10 нейронами. Добавьте уровень softmax для нормализации выходных данных. Установите скорость обучения полностью подключенного уровня в 10 раз больше скорости обучения базовых уровней CNN. Применить отсев 75%.

lgraph = removeLayers(lgraph,{'ClassificationLayer_Logits','Logits_softmax','Logits'});
newFinalLayers = [
    dropoutLayer(0.75,'Name','drop')
    fullyConnectedLayer(newMaxScore,'Name','fc','WeightLearnRateFactor',10,'BiasLearnRateFactor',10)
    softmaxLayer('Name','prob')];    
lgraph = addLayers(lgraph,newFinalLayers);
lgraph = connectLayers(lgraph,'global_average_pooling2d_1','drop');
dlnet = dlnetwork(lgraph);

Визуализация сети с помощью приложения Deep Network Designer.

deepNetworkDesigner(lgraph)

Определение градиентов модели и функций потерь

modelGradients вспомогательная функция вычисляет градиенты и потери для каждой итерации обучения сети. Эта функция определена в разделе «Вспомогательные функции» данного примера.

Целью сети NIMA является минимизация расстояния земного движителя (EMD) между достоверностью земли и прогнозируемыми распределениями баллов. Потеря EMD учитывает расстояние между классами при наказании за неправильную классификацию. Таким образом, потеря EMD лучше, чем типичная потеря взаимной энтропии softmax, используемая в задачах классификации [5]. В этом примере вычисляется потеря EMD с помощью earthMoverDistance вспомогательная функция, которая определена в разделе «Вспомогательные функции» данного примера.

Для функции потерь EMD используйте расстояние r-norm с r = 2. Это расстояние позволяет легко оптимизировать работу с градиентным спуском.

Укажите параметры обучения

Укажите параметры оптимизации SGDM. Обучение сети за 150 эпох с размером мини-партии 128.

numEpochs = 150;
miniBatchSize = 128;
momentum = 0.9;
initialLearnRate = 3e-3;
decay = 0.95;

Данные пакетного обучения

Создать minibatchqueue объект, который управляет мини-пакетами наблюдений в пользовательском учебном цикле. minibatchqueue объект также передает данные в dlarray объект, обеспечивающий автоматическую дифференциацию в приложениях глубокого обучения.

Укажите формат извлечения данных мини-пакета как 'SSCB' (пространственный, пространственный, канальный, пакетный). Установите 'DispatchInBackground' аргумент name-value к логическому значению, возвращенному canUseGPU. Если поддерживаемый графический процессор доступен для вычисления, то minibatchqueue объект предварительно обрабатывает мини-пакеты в фоновом режиме в параллельном пуле во время обучения.

mbqTrain = minibatchqueue(dsTrain,'MiniBatchSize',miniBatchSize, ...
    'PartialMiniBatch','discard','MiniBatchFormat',{'SSCB',''}, ...
    'DispatchInBackground',canUseGPU);
mbqVal = minibatchqueue(dsVal,'MiniBatchSize',miniBatchSize, ...
    'MiniBatchFormat',{'SSCB',''},'DispatchInBackground',canUseGPU);

Железнодорожная сеть

По умолчанию в примере загружается предварительно подготовленная версия сети NIMA. Предварительно обученная сеть позволяет выполнять весь пример без ожидания завершения обучения.

Для обучения сети установите doTraining переменная в следующем коде true. Обучение модели в индивидуальном цикле обучения. Для каждой итерации:

  • Считывание данных для текущего мини-пакета с помощью next функция.

  • Оцените градиенты модели с помощью dlfeval функции и modelGradients функция помощника.

  • Обновление параметров сети с помощью sgdmupdate функция.

Обучение на GPU, если он доступен. Для использования графического процессора требуются параллельные вычислительные Toolbox™ и графический процессор NVIDIA ® с поддержкой CUDA ®. Дополнительные сведения см. в разделе Поддержка графического процессора по выпуску (Панель инструментов параллельных вычислений).

doTraining = false;
if doTraining
    iteration = 0;
    velocity = [];
    start = tic;
    
    [hFig,lineLossTrain,lineLossVal] = initializeTrainingPlotNIMA;
    
    for epoch = 1:numEpochs
        
        shuffle (mbqTrain);    
        learnRate = initialLearnRate/(1+decay*floor(epoch/10));
        
        while hasdata(mbqTrain)
            iteration = iteration + 1;        
            [dlX,cdfY] = next(mbqTrain);
            [grad,loss] = dlfeval(@modelGradients,dlnet,dlX,cdfY);        
            [dlnet,velocity] = sgdmupdate(dlnet,grad,velocity,learnRate,momentum);
            
            updateTrainingPlotNIMA(lineLossTrain,loss,epoch,iteration,start)      
            
        end
        
        % Add validation data to plot
        [~,lossVal,~] = modelPredictions(dlnet,mbqVal);
        updateTrainingPlotNIMA(lineLossVal,lossVal,epoch,iteration,start) 
        
    end
    
    % Save the trained network
    modelDateTime = string(datetime('now','Format',"yyyy-MM-dd-HH-mm-ss"));
    save(strcat("trainedNIMA-",modelDateTime,"-Epoch-",num2str(numEpochs),".mat"),'dlnet');

else
    load(fullfile(imageDir,'trainedNIMA.mat'));    
end

Оценка модели NIMA

Оцените производительность модели в наборе тестовых данных, используя три метрики: EMD, точность двоичной классификации и коэффициенты корреляции. Производительность сети NIMA на тестовом наборе данных соответствует производительности эталонной модели NIMA, сообщенной Talebi и Milanfar [1].

Создать minibatchqueue объект, который управляет мини-пакетированием тестовых данных.

mbqTest = minibatchqueue(dsTest,'MiniBatchSize',miniBatchSize,'MiniBatchFormat',{'SSCB',''});

Рассчитайте прогнозируемые вероятности и кумулятивные вероятности истинности земли мини-партий тестовых данных с помощью modelPredictions функция. Эта функция определена в разделе «Вспомогательные функции» данного примера.

[YPredTest,~,cdfYTest] = modelPredictions(dlnet,mbqTest);

Рассчитайте среднее и стандартное значения отклонения истинности земли и прогнозируемых распределений.

meanPred = extractdata(YPredTest)' * (1:10)';
stdPred = sqrt(extractdata(YPredTest)'*((1:10).^2)' - meanPred.^2);
origCdf = extractdata(cdfYTest);
origPdf = [origCdf(1,:); diff(origCdf)];
meanOrig = origPdf' * (1:10)';
stdOrig = sqrt(origPdf'*((1:10).^2)' - meanOrig.^2);

Расчет EMD

Вычислите EMD истинности земли и прогнозируемые распределения баллов. Для прогнозирования используйте расстояние r-norm с r = 1. Значение EMD указывает на близость прогнозируемого и базового распределения оценок истинности.

EMDTest = earthMoverDistance(YPredTest,cdfYTest,1)
EMDTest = 
  1×1 single gpuArray dlarray

    0.1158

Вычислить точность двоичной классификации

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

qualityThreshold = 5;
binaryPred = meanPred > qualityThreshold;    
binaryOrig = meanOrig > qualityThreshold;

Вычислите точность двоичной классификации.

binaryAccuracy = 100 * sum(binaryPred==binaryOrig)/length(binaryPred)
binaryAccuracy =

   84.6591

Вычислить коэффициенты корреляции

Большие значения корреляции указывают на большую положительную корреляцию между истинностью основания и прогнозируемыми показателями. Вычислите коэффициент линейной корреляции (LCC) и коэффициент ранговой корреляции Спирмена (SRCC) для средних баллов.

meanLCC = corr(meanOrig,meanPred)
meanLCC =

  gpuArray single

    0.7265
meanSRCC = corr(meanOrig,meanPred,'type','Spearman')
meanSRCC =

  gpuArray single

    0.6451

Вспомогательные функции

Функция градиентов модели

modelGradients функция принимает в качестве входного значения a dlnetwork объект dlnet и мини-пакет входных данных dlX с соответствующими целевыми кумулятивными вероятностями cdfY. Функция возвращает градиенты потерь относительно обучаемых параметров в dlnet а также потери. Для автоматического вычисления градиентов используйте dlgradient функция.

function [gradients,loss] = modelGradients(dlnet,dlX,cdfY)
    dlYPred = forward(dlnet,dlX);    
    loss = earthMoverDistance(dlYPred,cdfY,2);    
    gradients = dlgradient(loss,dlnet.Learnables);    
end

Функция потерь

earthMoverDistance функция вычисляет EMD между истинностью основания и предсказанными распределениями для заданного значения r-norm. earthMoverDistance использует computeCDF вспомогательная функция для вычисления совокупных вероятностей прогнозируемого распределения.

function loss = earthMoverDistance(YPred,cdfY,r)
    N = size(cdfY,1);
    cdfYPred = computeCDF(YPred);
    cdfDiff = (1/N) * (abs(cdfY - cdfYPred).^r);
    lossArray = sum(cdfDiff,1).^(1/r);
    loss = mean(lossArray);
    
end
function cdfY = computeCDF(Y)
% Given a probability mass function Y, compute the cumulative probabilities
    [N,miniBatchSize] = size(Y);
    L = repmat(triu(ones(N)),1,1,miniBatchSize);
    L3d = permute(L,[1 3 2]);
    prod = Y.*L3d;
    prodSum = sum(prod,1);
    cdfY = reshape(prodSum(:)',miniBatchSize,N)';
end

Функция прогнозирования модели

modelPredictions функция вычисляет оцененные вероятности, потери и кумулятивные вероятности истинности основания мини-пакетов данных.

function [dlYPred,loss,cdfYOrig] = modelPredictions(dlnet,mbq)
    reset(mbq);
    loss = 0;
    numObservations = 0;
    dlYPred = [];    
    cdfYOrig = [];
    
    while hasdata(mbq)     
        [dlX,cdfY] = next(mbq);
        miniBatchSize = size(dlX,4);
        
        dlY = predict(dlnet,dlX);
        loss = loss + earthMoverDistance(dlY,cdfY,2)*miniBatchSize;
        dlYPred = [dlYPred dlY];
        cdfYOrig = [cdfYOrig cdfY];
        
        numObservations = numObservations + miniBatchSize;
        
    end
    loss = loss / numObservations;
end

Ссылки

[1] Талеби, Хоссейн и Пейман Миланфар. «NIMA: оценка нейронных изображений». Транзакции IEEE по обработке изображений 27, № 8 (август 2018 г.): 3998-4011. https://doi.org/10.1109/TIP.2018.2831899.

[2] LIVE: Лаборатория по созданию изображений и видео. «LIVE In the Wild Image Quality Challenge Database». https://live.ece.utexas.edu/research/ChallengeDB/index.html.

[3] Сандлер, Марк, Эндрю Говард, Менглонг Чжу, Андрей Жмогинов и Лян-Чех Чен. «MobileNetV2: инвертированные остатки и линейные узкие места». В 2018 году конференция IEEE/CVF по компьютерному зрению и распознаванию образов, 4510-20. Солт-Лейк-Сити, UT: IEEE, 2018. https://doi.org/10.1109/CVPR.2018.00474.

[4] ImageNet. http://www.image-net.org.

[5] Хоу, Ле, Чэнь-Пин Ю и Димитрис Самарас. «Потери на расстоянии в квадрате земного движителя для обучения глубоким нейронным сетям». Препринт, представлен 30 ноября 2016 года. https://arxiv.org/abs/1611.05916.

См. также

| | | | | | |

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