目标
利用SVD思想将图像做不同程度的压缩,查看效果
思路
主要利用这个近似公式
代码
import numpy as np
from PIL import Image
def rebuild2(u,sigma,v,k):
"k:前k维"
uk = u[:,:k] # 前k列
sigma_k=np.diag(sigma[:k]) # 前k个奇异值
vk = v[:k,:] # 前k行
dot1 = np.dot(uk, sigma_k)
return np.dot(dot1,vk) # uk*Σk*vk
pic = Image.open('/Users/zhengwei/Pictures/zxt.jpg', 'r')
# 灰度转换
pic = pic.convert("L")
# 转换为矩阵
pic_arr = np.array(pic)
print(pic_arr.shape)
# SVD
u, sigma, v = np.linalg.svd(pic_arr[:, :])
print(sigma.shape)
# 十分之一维,前64,共640维
L = rebuild2(u, sigma, v,k=64)
Image.fromarray(L).show()
# 五分之一维,前128,共640维
L = rebuild2(u, sigma, v,k=128)
Image.fromarray(L).show()
控制奇异值占比
即控制
def rebuild(u, sigma, v, per=0.9):
'per:奇异值占比'
m = len(u)
n = len(v)
a = np.zeros((m, n))
sigma_sum = int(sum(sigma))
cur_sum = 0
k = 0
while cur_sum <= sigma_sum * per:
# 取1列
uk = u[:, k].reshape(m, 1)
# 取一行
vk = v[k].reshape(1, n)
a += sigma[k] * np.dot(uk, vk)
cur_sum += sigma[k] # 累加奇异值
k += 1
a[a < 0] = 0
a[a > 255] = 255
print("k/n==%d/%d==%.2f" % (k, n, k / n))
return np.rint(a).astype("uint8")
调用代码同上,传参时注意per是奇异值占比。
经计算per=0.9
时对应k/n==214/640
,也就是说取前三分之的奇异值就能还原原图的百分之九十。