Using SVD to compress an image in MATLAB

Justin picture Justin · Nov 28, 2012 · Viewed 27.2k times · Source

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

Questions

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

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.

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?

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:

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

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

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

Answer

masad picture masad · Jul 16, 2013

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.

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: Original Image

Gives the following result with only first 5 Singular Values,

First 5 Singular Values

with first 30 Singular Values,

First 30 Singular Values

and the first 55 Singular Values,

First 55 Singular Values

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

Error graph

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