在MATLAB中使用SVD压缩图像。

时间:2022-03-31 08:18:53

I am brand new to MATLAB but am trying to do some image compression code for grayscale images.

我是全新的MATLAB,但我正在尝试做一些图像压缩编码的灰度图像。

Questions

问题

How can I use SVD to trim off low-valued eigenvalues to reconstruct a compressed image?

如何使用SVD来修剪低值特征值以重构压缩图像?

Work/Attempts so far

到目前为止工作/努力

My code so far is:

到目前为止,我的代码是:

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

This allows me to successfully decompose the image matrix with eigenvalues stored in variable S.

这使我能够成功地分解存储在变量S中的特征值的图像矩阵。

How do I truncate S (which is 167x301, class double)? Let's say of the 167 eigenvalues I want to take only the top 100 (or any n really), how do I do that and reconstruct the compressed image?

如何截断S (167x301, class double)?假设有167个特征值,我想只取前100(或任何n),我怎么做,然后重建压缩图像?

Updated code/thoughts

更新的代码/想法

Instead of putting a bunch of code in the comments section, this is the current draft I have. I have been able to successfully create the compressed image by manually changing N, but I would like to do 2 additional things:

而不是在评论区放一堆代码,这是我现在的草稿。我已经能够通过手动改变N来成功地创建压缩图像,但是我想做另外两件事:

1- Show a pannel of images for various compressions (i/e, run a loop for N = 5,10,25, etc.)

1-显示各种压缩的图片(i/e,为N = 5、10、25等)运行一个循环。

2- Somehow calculate the difference (error) between each image and the original and graph it.

2-以某种方式计算每个图像与原始图像之间的差异(误差),并将其绘制出来。

I am horrible with understanding loops and output, but this is what I have tried:

我很讨厌理解循环和输出,但这就是我所尝试的:

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

Obviously there are some errors because I don't get multiple pictures or know how to "graph" the error matrix

显然有一些错误,因为我没有得到多个图片或者知道如何“绘制”错误矩阵。

4 个解决方案

#1


11  

Just to start, I assume you're aware that the SVD is really not the best tool to decorrelate the pixels in a single image. But it is good practice.

首先,我假设您已经意识到SVD并不是在单个图像中对像素进行修饰的最佳工具。但这是很好的练习。

OK, so we know that B = U*S*V'. And we know S is diagonal, and sorted by magnitude. So by using only the top few values of S, you'll get an approximation of your image. Let's say C=U*S2*V', where S2 is your modified S. The sizes of U and V haven't changed, so the easiest thing to do for now is to zero the elements of S that you don't want to use, and run the reconstruction. (Easiest way to do this: S2=S; S2(N+1:end, :) = 0; S2(:, N+1:end) = 0;).

好的,我们知道B = U*S*V。我们知道S是对角的,按大小排序。所以只使用S的前几个值,就得到了图像的近似值。假设C=U*S2*V',其中S2是你修改过的S, U和V的大小没有改变,所以现在最容易做的就是把你不想用的S的元素归零,然后进行重建。(最简单的方法是:S2=S;S2(N + 1:最终,)= 0;S2(:,N + 1:结束)= 0;)。

Now for the compression part. U is full, and so is V, so no matter what happens to S2, your data volume doesn't change. But look at what happens to U*S2. (Plot the image). If you kept N singular values in S2, then only the first N rows of S2 are nonzero. Compression! Except you still have to deal with V. You can't use the same trick after you've already done (U*S2), since more of U*S2 is nonzero than S2 was by itself. How can we use S2 on both sides? Well, it's diagonal, so use D=sqrt(S2), and now C=U*D*D*V'. So now U*D has only N nonzero rows, and D*V' has only N nonzero columns. Transmit only those quantities, and you can reconstruct C, which is approximately like B.

现在对于压缩部分。U是满的,V也是,所以无论S2发生什么,你的数据量都不会改变。但是看看U*S2会发生什么。(画出图片)。如果在S2中保留N个奇异值,那么只有第N行S2是非零的。压缩!除非你仍然要处理v。你不能在你已经完成(U*S2)之后使用同样的技巧,因为更多的U*S2不是0,而不是S2本身。我们如何在等式两边同时使用S2呢?它是对角线,所以用D=sqrt(S2),现在C=U*D* V'所以现在U*D只有N个非零行,而D*V'只有N个非零列。只传输这些量,你可以重建C,它近似于B。

#2


15  

Although this question is old, it has helped me a lot to understand SVD. I have modified the code you have written in your question to make it work.

虽然这个问题由来已久,但它帮助我理解了SVD。我已经修改了你写在你的问题中的代码以使它工作。

I believe you might have solved the problem, however just for the future reference for anyone visiting this page, I am including the complete code here with the output images and graph.

我相信您可能已经解决了这个问题,但是对于访问这个页面的任何人来说,我在这里包括了完整的代码,包括输出图像和图形。

Below is the code:

下面是代码:

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

Applying this to the following image: 在MATLAB中使用SVD压缩图像。

将其应用于以下图像:

Gives the following result with only first 5 Singular Values,

给出的结果只有前5个奇异值,

在MATLAB中使用SVD压缩图像。

with first 30 Singular Values,

前30个奇异值,

在MATLAB中使用SVD压缩图像。

and the first 55 Singular Values,

第一个55个奇异值,

在MATLAB中使用SVD压缩图像。

The change in error with increasing number of singular values can be seen in the graph below.

在下面的图中可以看到越来越多的奇异值的误差的变化。

在MATLAB中使用SVD压缩图像。

Here you can notice the graph is showing that using approximately 200 first singular values yields to approximately zero error.

这里你可以注意到,这个图显示,使用大约200个第一个奇异值,可以得到近似为零的误差。

#3


3  

For example, here's a 512 x 512 B&W image of Lena:

例如,这里有一个512 x 512 B&W的Lena图像:

在MATLAB中使用SVD压缩图像。

We compute the SVD of Lena. Choosing the singular values above 1% of the maximum singular value, we are left with just 53 singular values. Reconstructing Lena with these singular values and the corresponding (left and right) singular vectors, we obtain a low-rank approximation of Lena:

我们计算了Lena的SVD。选择奇异值大于最大值的1%时,我们只剩下53个奇异值。用这些奇异值和相应的(左、右)奇异向量重构Lena,得到了Lena的低秩近似:

在MATLAB中使用SVD压缩图像。

Instead of storing 512 * 512 = 262144 values (each taking 8 bits), we can store 2 x (512 x 53) + 53 = 54325 values, which is approximately 20% of the original size. This is one example of how SVD can be used to do lossy image compression.

我们可以存储2个x (512 x 53) + 53 = 54325值,而不是存储512 * 512 = 262144个值(每个值8位),这大约是原始大小的20%。这是SVD如何用于有损图像压缩的一个示例。


Here's the MATLAB code:

这是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


0  

taking the first n max number of eigenvalues and their corresponding eigenvectors may solve your problem.For PCA, the original data multiplied by the first ascending eigenvectors will construct your image by n x d where d represents the number of eigenvectors.

取本征值的前n个最大值及其对应的特征向量可以解决你的问题。对于PCA,原始数据乘以第一个上升特征向量将会构造你的图像,在n x d中d表示特征向量的个数。

#1


11  

Just to start, I assume you're aware that the SVD is really not the best tool to decorrelate the pixels in a single image. But it is good practice.

首先,我假设您已经意识到SVD并不是在单个图像中对像素进行修饰的最佳工具。但这是很好的练习。

OK, so we know that B = U*S*V'. And we know S is diagonal, and sorted by magnitude. So by using only the top few values of S, you'll get an approximation of your image. Let's say C=U*S2*V', where S2 is your modified S. The sizes of U and V haven't changed, so the easiest thing to do for now is to zero the elements of S that you don't want to use, and run the reconstruction. (Easiest way to do this: S2=S; S2(N+1:end, :) = 0; S2(:, N+1:end) = 0;).

好的,我们知道B = U*S*V。我们知道S是对角的,按大小排序。所以只使用S的前几个值,就得到了图像的近似值。假设C=U*S2*V',其中S2是你修改过的S, U和V的大小没有改变,所以现在最容易做的就是把你不想用的S的元素归零,然后进行重建。(最简单的方法是:S2=S;S2(N + 1:最终,)= 0;S2(:,N + 1:结束)= 0;)。

Now for the compression part. U is full, and so is V, so no matter what happens to S2, your data volume doesn't change. But look at what happens to U*S2. (Plot the image). If you kept N singular values in S2, then only the first N rows of S2 are nonzero. Compression! Except you still have to deal with V. You can't use the same trick after you've already done (U*S2), since more of U*S2 is nonzero than S2 was by itself. How can we use S2 on both sides? Well, it's diagonal, so use D=sqrt(S2), and now C=U*D*D*V'. So now U*D has only N nonzero rows, and D*V' has only N nonzero columns. Transmit only those quantities, and you can reconstruct C, which is approximately like B.

现在对于压缩部分。U是满的,V也是,所以无论S2发生什么,你的数据量都不会改变。但是看看U*S2会发生什么。(画出图片)。如果在S2中保留N个奇异值,那么只有第N行S2是非零的。压缩!除非你仍然要处理v。你不能在你已经完成(U*S2)之后使用同样的技巧,因为更多的U*S2不是0,而不是S2本身。我们如何在等式两边同时使用S2呢?它是对角线,所以用D=sqrt(S2),现在C=U*D* V'所以现在U*D只有N个非零行,而D*V'只有N个非零列。只传输这些量,你可以重建C,它近似于B。

#2


15  

Although this question is old, it has helped me a lot to understand SVD. I have modified the code you have written in your question to make it work.

虽然这个问题由来已久,但它帮助我理解了SVD。我已经修改了你写在你的问题中的代码以使它工作。

I believe you might have solved the problem, however just for the future reference for anyone visiting this page, I am including the complete code here with the output images and graph.

我相信您可能已经解决了这个问题,但是对于访问这个页面的任何人来说,我在这里包括了完整的代码,包括输出图像和图形。

Below is the code:

下面是代码:

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

Applying this to the following image: 在MATLAB中使用SVD压缩图像。

将其应用于以下图像:

Gives the following result with only first 5 Singular Values,

给出的结果只有前5个奇异值,

在MATLAB中使用SVD压缩图像。

with first 30 Singular Values,

前30个奇异值,

在MATLAB中使用SVD压缩图像。

and the first 55 Singular Values,

第一个55个奇异值,

在MATLAB中使用SVD压缩图像。

The change in error with increasing number of singular values can be seen in the graph below.

在下面的图中可以看到越来越多的奇异值的误差的变化。

在MATLAB中使用SVD压缩图像。

Here you can notice the graph is showing that using approximately 200 first singular values yields to approximately zero error.

这里你可以注意到,这个图显示,使用大约200个第一个奇异值,可以得到近似为零的误差。

#3


3  

For example, here's a 512 x 512 B&W image of Lena:

例如,这里有一个512 x 512 B&W的Lena图像:

在MATLAB中使用SVD压缩图像。

We compute the SVD of Lena. Choosing the singular values above 1% of the maximum singular value, we are left with just 53 singular values. Reconstructing Lena with these singular values and the corresponding (left and right) singular vectors, we obtain a low-rank approximation of Lena:

我们计算了Lena的SVD。选择奇异值大于最大值的1%时,我们只剩下53个奇异值。用这些奇异值和相应的(左、右)奇异向量重构Lena,得到了Lena的低秩近似:

在MATLAB中使用SVD压缩图像。

Instead of storing 512 * 512 = 262144 values (each taking 8 bits), we can store 2 x (512 x 53) + 53 = 54325 values, which is approximately 20% of the original size. This is one example of how SVD can be used to do lossy image compression.

我们可以存储2个x (512 x 53) + 53 = 54325值,而不是存储512 * 512 = 262144个值(每个值8位),这大约是原始大小的20%。这是SVD如何用于有损图像压缩的一个示例。


Here's the MATLAB code:

这是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


0  

taking the first n max number of eigenvalues and their corresponding eigenvectors may solve your problem.For PCA, the original data multiplied by the first ascending eigenvectors will construct your image by n x d where d represents the number of eigenvectors.

取本征值的前n个最大值及其对应的特征向量可以解决你的问题。对于PCA,原始数据乘以第一个上升特征向量将会构造你的图像,在n x d中d表示特征向量的个数。