web-dev-qa-db-ja.com

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)を切り捨てるにはどうすればよいですか?上位100個(または実際には任意のn個)のみを取得したい167個の固有値について、どうすれば圧縮画像を再構築できますか?

更新されたコード/考え

コメントセクションにたくさんのコードを入れる代わりに、これは私が持っている現在のドラフトです。 Nを手動で変更することで圧縮画像を正常に作成できましたが、さらに2つのことを実行したいと思います。

1-さまざまな圧縮の画像のパネルを表示します(つまり、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

複数の写真を取得していないか、エラーマトリックスを「グラフ化」する方法を知らないため、明らかにいくつかのエラーがあります

15
Justin

はじめに、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個の非ゼロ列しかありません。それらの量だけを送信すると、ほぼBに似たCを再構築できます。

12
Peter

この質問は古いものですが、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個の最初の特異値を使用するとエラーがほぼゼロになることを示していることがわかります。

17
masad

たとえば、これは Lena の512 x 512 B&W画像です。

Lena

LenaのSVDを計算します。最大特異値の1%を超える特異値を選択すると、53個の特異値だけが残ります。これらの特異値と対応する(左と右の)特異ベクトルを使用してLenaを再構築すると、Lenaの 低ランク近似 が得られます。

enter image description here

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

固有値の最初の最大n個とそれに対応する固有ベクトルを取得すると、問題が解決する場合があります。PCAの場合、元のデータに最初の昇順の固有ベクトルを掛けると、画像はn x dで構成されます。ここで、dは固有ベクトルの数を表します。

0
berkay