我是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)?让我们说一下我想要的前100个(或任何n个)的167个特征值,我该怎么做并重建压缩图像呢?
更新了代码/想法
这不是在评论部分放置一堆代码,而是我现有的草案。我已经能够通过手动更改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
显然存在一些错误,因为我没有获得多张图片或知道如何“绘制”错误矩阵
答案 0 :(得分:17)
虽然这个问题已经过时了,但是对于理解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');
将此应用于以下图像:
仅使用前5个奇异值
给出以下结果
前30个奇异值,
和前55个奇异值,
随着奇异值数量的增加,误差的变化可以在下图中看到。
在这里你可以注意到图表显示使用大约200个第一个奇异值产生大约零误差。
答案 1 :(得分:12)
刚开始,我假设您已经意识到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
会发生什么。 (绘制图像)。如果您在S2
中保留了N个奇异值,则只有S2
的前N行非零。压缩!除了你还需要处理V
。在您完成(U*S2)
之后,您无法使用相同的技巧,因为U*S2
的更多内容本身不是S2
。我们如何在双方使用S2?嗯,这是对角线,所以请使用D=sqrt(S2)
,现在使用C=U*D*D*V'
。所以现在U*D
只有N个非零行,而D*V'
只有N个非零列。只传输那些数量,你可以重建C,大致类似于B。
答案 2 :(得分:3)
例如,这是Lena的512 x 512 B& W图像:
我们计算Lena的SVD。选择高于最大奇异值1%的奇异值,我们只剩下 53个奇异值。用这些奇异值和相应的(左和右)奇异向量重建Lena,我们得到一个low-rank approximation的Lena:
我们可以存储2 x(512 x 53)+ 53 = 54325的值,而不是存储512 * 512 = 262144的值,而是大约原始大小的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');
答案 3 :(得分:0)
取第一个n max个特征值及其对应的特征向量可以解决你的问题。对于PCA,原始数据乘以第一个上升的特征向量将构造你的图像n x d,其中d代表特征向量的数量。