%% Image Compression with Low-Rank SVD
% This example shows how to use svdsketch to compress an image. svdsketch uses a low-rank matrix approximation to preserve important features of the image, while filtering out less important features. As the tolerance used with svdsketch increases in magnitude, more features are filtered out, changing the level of detail in the image.
%
%% Load Image
% Load the image street1.jpg, which is a picture of a city street. The 3-D matrix that forms this image is uint8, so convert the image to a grayscale matrix. View the image with an annotation of the original matrix rank.

A = imread('street1.jpg');
A = rgb2gray(A);
imshow(A)
title(['Original (',sprintf('Rank %d)',rank(double(A)))])

%
%% Compress Image
% Use svdsketch to calculate a low-rank matrix that approximates A within a tolerance of 1e-2. Form the low-rank matrix by multiplying the SVD factors returned by svdsketch, convert the result to uint8, and view the resulting image.

[U1,S1,V1] = svdsketch(double(A),1e-2);
Anew1 = uint8(U1*S1*V1');
imshow(uint8(Anew1))
title(sprintf('Rank %d approximation',size(S1,1)))

% svdsketch produces a rank 288 approximation, which results in some minor graininess in some of the boundary lines of the image.
%
% Now, compress the image a second time using a tolerance of 1e-1. As the magnitude of the tolerance increases, the rank of the approximation produced by svdsketch generally decreases.

[U2,S2,V2] = svdsketch(double(A),1e-1);
Anew2 = uint8(U2*S2*V2');
imshow(Anew2)
title(sprintf('Rank %d approximation',size(S2,1)))

% This time, svdsketch produces a rank 48 approximation. Most of the major aspects of the image are still visible, but the additional compression increases the blurriness.
%
%% Limit Subspace Size
% svdsketch adaptively determines what rank to use for the matrix sketch based on the specified tolerance. However, you can use the MaxSubspaceDimension name-value pair to specify the maximum subspace size that should be used to form the matrix sketch. This option can produce matrices that do not satisfy the tolerance, since the subspace you specify might be too small. In these cases, svdsketch returns a matrix sketch with the maximum allowed subspace size.
% Use svdsketch with a tolerance of 1e-1 and a maximum subspace size of 15. Specify a fourth output to return the relative approximation error.

[U3,S3,V3,apxErr] = svdsketch(double(A),1e-1,'MaxSubspaceDimension',15);

% Compare the relative approximation error of the result with the specified tolerance. apxErr contains one element since svdsketch only needs one iteration to compute the answer.

apxErr <= 1e-1

% The result indicates that the matrix sketch does not satisfy the specified tolerance.
% View the heavily compressed rank 15 image.

Anew3 = uint8(U3*S3*V3');
imshow(Anew3)
title(sprintf('Rank %d approximation',size(S3,1)))

%
%% Compare Results
% Finally, view all of the images side-by-side for comparison.

tiledlayout(2,2,'TileSpacing','Compact')
nexttile
imshow(A)
title('Original')
nexttile
imshow(Anew1)
title(sprintf('Rank %d approximation',size(S1,1)))
nexttile
imshow(Anew2)
title(sprintf('Rank %d approximation',size(S2,1)))
nexttile
imshow(Anew3)
title(sprintf('Rank %d approximation',size(S3,1)))

%
% Copyright 2020 The MathWorks, Inc.