图像SVD分解与重构
将图像看成一个二维矩阵,三个通道的彩色图像就是3个二维矩阵,对矩阵分别进行svd分解。svd分解是将一个矩阵A写成
U
∗
Σ
∗
V
T
U*\Sigma*V^T
U∗Σ∗VT的形式,U和V都是单位正交矩阵,
Σ
=
(
σ
1
0
⋯
0
0
σ
2
⋯
0
⋮
⋮
⋱
⋮
0
0
⋯
σ
n
)
\Sigma=\begin{pmatrix} \sigma_1 & 0 &\cdots &0 \\ 0 & \sigma_2 & \cdots&0\\ \vdots &\vdots&\ddots &\vdots \\ 0& 0 & \cdots&\sigma_n \end{pmatrix}
Σ=⎝⎜⎜⎜⎛σ10⋮00σ2⋮0⋯⋯⋱⋯00⋮σn⎠⎟⎟⎟⎞
Σ
\Sigma
Σ是一个主对角线为矩阵奇异值,其余值为0的矩阵,并且
σ
1
>
σ
2
>
.
.
.
>
σ
n
\sigma_1>\sigma_2>...>\sigma_n
σ1>σ2>...>σn由大到小排列。
利用svd压缩图像(
m
∗
n
m*n
m∗n)就是将u取前K列(
m
∗
K
m*K
m∗K),
Σ
\Sigma
Σ取
K
∗
K
K*K
K∗K大小,v取
K
∗
n
K*n
K∗n,将这三个矩阵连乘起来就得到一副压缩之后的图像。具体原理与PCA主成分分析类似。
下面给出代码:
import numpy as np
import cv2
f=cv2.imread('bai.jpg')
# cv2.imshow('',f)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
img=f.copy()
u_r,sigma_r,v_r=np.linalg.svd(img[:,:,0])
u_g,sigma_g,v_g=np.linalg.svd(img[:,:,1])
u_b,sigma_b,v_b=np.linalg.svd(img[:,:,2])
print(u_r.shape)
print(sigma_r.shape)#这是一个一维向量
print(v_r.shape)
def restore(sigma,u,v,K):
'''
svd分解出来的三个参数,u,sigma,v=svd(img)
:param K: 为取前K个特征值
图像重构就是按照u*sigma*v再乘回去,只不过这里的u,sigma,v是取前K个特征值之后的缩小的矩阵
:return:
'''
m=len(u)
n=len(v[1])
a=np.zeros((m,n))
for k in range(K+1):
u[:,k]=u[:,k]*sigma[k]
a=np.dot(u[:,:K+1],v[:K+1,:])
a[a<0]=0
a[a>255]=255
return a.astype(np.uint8)
#分解之后进行重构
K=200#取前100个奇异值重构时就能得到比较清晰的图像,而原图像的奇异值有500个
restore_r=restore(sigma_r,u_r,v_r,K)
restore_g=restore(sigma_g,u_g,v_g,K)
restore_b=restore(sigma_b,u_b,v_b,K)
restore_img=np.stack((restore_r,restore_g,restore_b),axis=2)
cv2.imshow('',restore_img)
cv2.waitKey(0)
cv2.destroyAllWindows()