0%

基于奇异值分解的图像压缩

By Z.H. Fu
https://fuzihaofzh.github.io/blog/
最近学习线性代数的有关东西,在看到奇异值分解(svd)时,发现了一个在图像压缩上的应用。 奇异值分解:在线性代数中,我们知道对任意一个矩阵都存在奇异值分解,$\boldsymbol{A}=\boldsymbol{U\Sigma V^\mathrm{T}}$,其中$\boldsymbol{U}$和$\boldsymbol{V}$是标准正交矩阵,而$\boldsymbol{\Sigma}$是一个对角矩阵,每一个对角元是该矩阵的一个奇异值,奇异值指的是矩阵的特征值开根号。其具体分解形式如下: $$ \boldsymbol{A}=\begin{bmatrix}u_1 &u_2 &\cdots &u_m\end{bmatrix}\begin{bmatrix}\boldsymbol{D} & \boldsymbol{0} \\\boldsymbol{0} &\boldsymbol{0}\end{bmatrix}\begin{bmatrix}v_1^\mathrm{T}\\ v_2^\mathrm{T} \\ \vdots \\ u_n^\mathrm{T}\end{bmatrix} $$ 其中 $$\boldsymbol{D}=\begin{bmatrix} \sigma_1 &0 &\cdots &0 \\ 0 & \sigma_2 &\vdots &0 \\ \vdots &\vdots &\ddots &\vdots \\ 0 &0 &\cdots &\sigma_r\end{bmatrix}$$ 将$\boldsymbol{A}$展开得 $$\boldsymbol{A}=\sigma_1\boldsymbol{u_1v_1^\mathrm{T}}+\sigma_2\boldsymbol{u_2v_2^\mathrm{T}}+\cdots+\sigma_r\boldsymbol{u_rv_r^\mathrm{T}}$$ 将$\boldsymbol{A}$看成一个图像的矩阵,上面和式的每一个分量按大小排序,越大,说明越重要。而后面的权很小,可以舍去,如果只取前面k项,则数据量为$(m+n+1)k\ll mn$因而达到了压缩图像的目的。 通过对比发现,当$k=\frac{r}{20} $时,能基本看清图像。当$k=\frac{r}{4} $时基本看不出任何区别,对于长宽相等的图像,此时数据量占原数据量的$k=\frac{2k}{n} $,在测试图像中,这个数值为0.5 。可见图像压缩的效果是显著的。 处理结果如下: 原始图像:
![svdori.png](/blog/images/svdori.png)
k=1:
![svdk=1.png](/blog/images/svdk=1.png)
k=2:
![svdk=2.png](/blog/images/svdk=2.png)
k=3:
![svdk=3.png](/blog/images/svdk=3.png)
k=4:
![svdk=4.png](/blog/images/svdk=4.png)
k=21:
![svdk=21.png](/blog/images/svdk=21.png)
k=50:
![svdk=50.png](/blog/images/svdk=50.png)
k=105:
![svdk=105.png](/blog/images/svdk=105.png)
k=r=420:
![svdk=r=420.png](/blog/images/svdk=r=420.png)
附matlab测试代码:
matlab
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
SNum = 21;
I = imread('img.bmp');
h = size(I,1);
w = size(I,2);
R = I(:,:,1);
G = I(:,:,2);
B = I(:,:,3);
debug = 'RGB disposed'
Rd = im2double(R);
Gd = im2double(G);
Bd = im2double(B);
[Ur,Sr,Vr] = svd(Rd);
[Ug,Sg,Vg] = svd(Gd);
[Ub,Sb,Vb] = svd(Bd);
debug = 'end SVD decomposition'
Rt = zeros(h,w);
Gt = zeros(h,w);
Bt = zeros(h,w);
for i = 1:SNum
Rt = Rt + Sr(i,i)*Ur(:,i)*Vr(:,i)';
Gt = Gt + Sg(i,i)*Ug(:,i)*Vg(:,i)';
Bt = Bt + Sb(i,i)*Ub(:,i)*Vb(:,i)';
end
I2(:,:,1) = im2uint8(Rt);
I2(:,:,2) = im2uint8(Gt);
I2(:,:,3) = im2uint8(Bt);
imshow(I2);