SVD应用示例:图像压缩

目标

利用SVD思想将图像做不同程度的压缩,查看效果

思路

主要利用这个近似公式 Am×n=Um×mΣm×nVTn×nUm×kΣk×kVTk×n

代码

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

这里写图片描述

控制奇异值占比

即控制 ki=1σini=1σi 的比例。

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,也就是说取前三分之的奇异值就能还原原图的百分之九十。

猜你喜欢

转载自blog.csdn.net/zhengwei223/article/details/78942822
SVD