Использование SVD для сжатия изображения в MATLAB - программирование
Подтвердить что ты не робот

Использование SVD для сжатия изображения в MATLAB

Я новичок в MATLAB, но пытаюсь сделать код сжатия изображений для изображений в оттенках серого.

Вопросы

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

Работа/попытки до сих пор

Мой код до сих пор:

B=imread('images1.jpeg');   
B=rgb2gray(B);  
doubleB=double(B);  
%read the image and store it as matrix B, convert the image to a grayscale
photo and convert the matrix to a class 'double' for values 0-255  
[U,S,V]=svd(doubleB);

Это позволяет мне успешно разложить матрицу изображений с собственными значениями, хранящимися в переменной S.

Как усечь S (что 167x301, класс double)? Скажем, из 167 собственных значений я хочу взять только 100 лучших (или любой n действительно), как это сделать и восстановить сжатое изображение?

Обновленный код/​​мысли

Вместо того, чтобы помещать кучу кода в раздел комментариев, это текущий проект, который у меня есть. Я смог успешно создать сжатый образ, вручную изменив N, но я хотел бы сделать еще две вещи:

1- Показать панель изображений для различных сжатий (i/e, запустить цикл для N = 5,10,25 и т.д.)

2- Как-то вычислите разницу (ошибку) между каждым изображением и оригиналом и нарисуйте его.

Я ужасен с пониманием циклов и вывода, но это то, что я пробовал:

B=imread('images1.jpeg');  
B=rgb2gray(B);  
doubleB=im2double(B);%  
%read the image and store it as matrix B, convert the image to a grayscale  
%photo and convert the image to a class 'double'  
[U,S,V]=svd(doubleB);   
C=S;  
for N=[5,10,25,50,100]  
C(N+1:end,:)=0;  
C(:,N+1:end)=0;  
D=U*C*V';  
%Use singular value decomposition on the image doubleB, create a new matrix  
%C (for Compression diagonal) and zero out all entries above N, (which in  
%this case is 100). Then construct a new image, D, by using the new  
%diagonal matrix C.  
imshow(D);  
error=C-D;  
end

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

4b9b3361

Ответ 1

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

ОК, поэтому мы знаем, что B = U*S*V'. И мы знаем, что S диагональна и отсортирована по величине. Таким образом, используя только верхние несколько значений S, вы получите приблизительное изображение. Скажем, C=U*S2*V', где S2 - ваш модифицированный S. Размеры U и V не изменились, поэтому на данный момент проще всего обнулить элементы S, которые вы не хотите использовать, и запустить реконструкции. (Самый простой способ сделать это: S2=S; S2(N+1:end, :) = 0; S2(:, N+1:end) = 0;).

Теперь для части сжатия. U заполнен, и поэтому V, поэтому независимо от того, что происходит с S2, ваш объем данных не изменяется. Но посмотрите, что происходит с U*S2. (Настройте изображение). Если вы сохранили N особых значений в S2, то только первые N строк из S2 отличны от нуля. Сжатие! Кроме того, вам все равно придется иметь дело с V. Вы не можете использовать тот же трюк после того, как вы уже сделали (U*S2), так как больше U*S2 отличен от нуля, чем S2. Как мы можем использовать S2 с обеих сторон? Ну, это диагональ, поэтому используйте D=sqrt(S2), а теперь C=U*D*D*V'. Итак, теперь U*D имеет только N ненулевых строк, а D*V' имеет только N отличных от нуля столбцов. Передавайте только эти величины, и вы можете восстановить C, который примерно похож на B.

Ответ 2

Хотя этот вопрос устарел, он очень помог мне понять SVD. Я изменил код, который вы написали в своем вопросе, чтобы он работал.

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

Ниже приведен код:

close all
clear all
clc

%reading and converting the image
inImage=imread('fruits.jpg');
inImage=rgb2gray(inImage);
inImageD=double(inImage);

% decomposing the image using singular value decomposition
[U,S,V]=svd(inImageD);

% Using different number of singular values (diagonal of S) to compress and
% reconstruct the image
dispEr = [];
numSVals = [];
for N=5:25:300
    % store the singular values in a temporary var
    C = S;

    % discard the diagonal values not required for compression
    C(N+1:end,:)=0;
    C(:,N+1:end)=0;

    % Construct an Image using the selected singular values
    D=U*C*V';


    % display and compute error
    figure;
    buffer = sprintf('Image output using %d singular values', N)
    imshow(uint8(D));
    title(buffer);
    error=sum(sum((inImageD-D).^2));

    % store vals for display
    dispEr = [dispEr; error];
    numSVals = [numSVals; N];
end

% dislay the error graph
figure; 
title('Error in compression');
plot(numSVals, dispEr);
grid on
xlabel('Number of Singular Values used');
ylabel('Error between compress and original image');

Применяя это к следующему изображению: Original Image

Дает следующий результат только с первыми 5 сингулярными значениями,

First 5 Singular Values

с первыми 30 уникальными значениями,

First 30 Singular Values

и первые 55 сингулярных значений,

First 55 Singular Values

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

Error graph

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

Ответ 3

Например, здесь изображение 512 x 512 B & W Лена:

Lena

Мы вычисляем СВД Лены. Выбирая сингулярные значения выше 1% от максимального сингулярного значения, мы оставляем только 53 сингулярных значения. Реконструируя Лену с этими сингулярными значениями и соответствующие (левые и правые) сингулярные векторы, получим низкое рандомизированное приближение Лены:

введите описание изображения здесь

Вместо хранения значений 512 * 512 = 262144 (каждый из которых принимает 8 бит), мы можем сохранить 2 x (512 x 53) + 53 = 54325 значений, что приблизительно 20% от исходного размера. Это один пример того, как SVD можно использовать для сжатия изображений с потерями.


Здесь код MATLAB:

% open Lena image and convert from uint8 to double
Lena = double(imread('LenaBW.bmp'));

% perform SVD on Lena
[U,S,V] = svd(Lena);

% extract singular values
singvals = diag(S);

% find out where to truncate the U, S, V matrices
indices = find(singvals >= 0.01 * singvals(1));

% reduce SVD matrices
U_red = U(:,indices);
S_red = S(indices,indices);
V_red = V(:,indices);

% construct low-rank approximation of Lena
Lena_red = U_red * S_red * V_red';

% print results to command window
r = num2str(length(indices));
m = num2str(length(singvals));
disp(['Low-rank approximation used ',r,' of ',m,' singular values']);

% save reduced Lena
imwrite(uint8(Lena_red),'Reduced Lena.bmp');

Ответ 4

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