Main Content

低ランク SVD を使用したイメージの圧縮

この例では、svdsketch を使用してイメージを圧縮する方法を説明します。svdsketch では低ランク行列による近似が使用され、イメージの重要な特徴は保持したまま、比較的重要でない特徴を除外します。svdsketch で使用される許容誤差が大きいほど、より多くの特徴が除外され、イメージの詳細度が変化します。

イメージの読み込み

ある都市の道路を写した写真である、イメージ street1.jpg を読み込みます。このイメージを構成する 3 次元行列は uint8 であるため、イメージをグレースケールの行列に変換します。元の行列のランクを注釈に含めて、イメージを表示します。

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

イメージの圧縮

svdsketch を使用して、1e-2 の許容誤差内で A を近似する低ランクの行列を計算します。svdsketch によって返された SVD 係数を乗算することで低ランクの行列を形成し、それを uint8 に変換して、結果のイメージを表示します。

[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 からはランク 288 の近似が出力され、イメージの境界線上の一部にわずかな粒状性が生じます。

次に、1e-1 の許容誤差を使用して、2 回目となるイメージの圧縮を行います。一般に、許容誤差が大きくなるにつれて svdsketch が出力する近似のランクは低くなります。

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

今回は、svdsketch によってランク 48 の近似が出力されます。イメージの大まかな特徴はほとんどがそのまま視認できますが、圧縮を追加したことで不鮮明さが増しています。

部分空間のサイズ制限

svdsketch は、指定された許容誤差に基づき、行列スケッチに使用するランクを適応的に特定します。一方で、MaxSubspaceDimension の名前と値のペアを使用して、行列スケッチの形成に使用する部分空間の最大サイズを指定できます。このオプションでは、指定する部分空間が小さすぎるために、許容誤差を満たさない行列が出力される場合があります。そうした場合、svdsketch は許容される最大サイズの部分空間をもつ行列スケッチを返します。

許容誤差を 1e-1 とし、部分空間の最大サイズを 15 として、svdsketch を使用します。相対的な近似誤差を返すための 4 番目の出力を指定します。

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

結果の相対的近似誤差を、指定した許容誤差と比較します。svdsketch が解の計算に要する反復が 1 回のみであるため、apxErr に含まれる要素は 1 つとなります。

apxErr <= 1e-1
ans = logical
   0

結果から、指定した許容誤差を行列スケッチが満たしていないことが分かります。

高度に圧縮されたランク 15 のイメージを表示します。

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

結果の比較

最後に、比較のためすべてのイメージを並べて表示します。

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

参考

| |

関連するトピック