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

В этом примере показано, как анализировать эстетическое качество изображений с помощью сверточной нейронной сети (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 в диком наборе данных

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

Загрузите набор данных путем следования инструкциям, обрисованным в общих чертах в LIVE В Дикой Базе данных проблемы Качества изображения. Извлеките данные в директорию, заданную imageDir переменная. Когда экстракция успешна, imageDir содержит две директории: Data и Images.

Загрузите LIVE в диких данных

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

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

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

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

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

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

Сбросьте datastore к его начальному состоянию.

reset(dsTrain);

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

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

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

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)

Градиенты модели Define и функции потерь

modelGradients функция помощника вычисляет градиенты и потери для каждой итерации обучения сети. Эта функция задана в разделе Supporting Functions этого примера.

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

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

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

Задайте опции для оптимизации SGDM. Обучите сеть в течение 150 эпох с мини-пакетным размером 128.

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

Пакетные обучающие данные

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

Задайте мини-пакетный формат экстракции данных как 'SSCB' (пространственный, пространственный, канал, пакет). Установите 'DispatchInBackground' аргумент значения имени к булевской переменной, возвращенной 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 функция.

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

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 функция. Эта функция задана в разделе Supporting Functions этого примера.

[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-нормы с 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 функционируйте берет в качестве входа 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-нормы. 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] Talebi, Хоссейн и Пеимен Милэнфэр. “NIMA: Нейронная Оценка Изображений”. Транзакции IEEE на Обработке изображений 27, № 8 (август 2018): 3998–4011. https://doi.org/10.1109/TIP.2018.2831899.

[2] LIVE: Лаборатория для Изображения и Видео Разработки. "LIVE В Дикой Базе данных проблемы Качества изображения". 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] Как, Le, Chen-Ping Ю и Димитрис Самарас. “Основанная на расстоянии Потеря Двигателя Земли в квадрате для Учебных Глубоких нейронных сетей”. Предварительно распечатайте, представленный 30 ноября 2016. https://arxiv.org/abs/1611.05916.

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

| | | | | | |

Похожие темы