奇异值分解(SVD)是一种矩阵分解的方法,
假设有矩阵
A
A
为行
n
n
列,那么通过SVD,我们可以得到如下式子:
其中 U U 定义为的左奇异向量, V V 定义为右奇异向量,对角线上的值为 A A 的奇异值。
这里可以看成 m m 列的列向量组成的的正交矩阵; V V 可以看成行的行向量组成的 n×n n × n 的正交矩阵;
所以要求矩阵A的奇异值分解值主要有一下四个部分。
- 分别计算正交矩阵 AAT A A T 和 ATA A T A
- U U 中的列由的单位特征向量组成。
- V V 中的列由的单位特征向量组成。
- Σ Σ 对角线上的值由 ATA A T A 的特征值的平方根得出。
SVD的应用可以应用在很多场景,如在对数据处理时可以通过SVD选取重要的维度即 Σ Σ 中的特征值(其实按照从大到小的顺序排列),也可以对图像进行做特征提取处理,同时也可以应用于基于协同过滤的推荐中,也可以对数据进行压缩处理。
这里我们举例,SVD对图像中基本的特征提取应用。
#!/usr/bin/python
# -*- coding:utf-8 -*-
import numpy as np
import os
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib as mpl
from pprint import pprint
def restorel(sigma, u, v, K):
m = len(u)
n = len(v[0])
a = np.zeros((m,n))
for k in range(K):
print("==============",u.shape)
uk = u[:,k].reshape(m,1)
vk = v[k].reshape(1,n)
print("=======================")
print(sigma[k].shape)
a += sigma[k]*np.dot(uk,vk)
print("a:",a.shape)
print("**********************")
print(a)
a[a < 0] = 0
a[a > 255] = 255
return np.rint(a).astype('uint8')
if __name__ == "__main__":
A = Image.open("A.png",'r')
print(A)
output_path = r'.\Pic'
if not os.path.exists(output_path):
os.mkdir(output_path)
a = np.array(A)
# print(a.shape)
K = 50
u_r, sigma_r, v_r = np.linalg.svd(a[:,:,0])
u_g, sigma_g, v_g = np.linalg.svd(a[:,:,1])
u_b, sigma_b, v_b = np.linalg.svd(a[:,:,2])
# print("====================")
# print(u_r.shape)
# print(sigma_r.shape)
# print(v_r.shape)
plt.figure(figsize=(10,10),facecolor='w')
mpl.rcParams['font.sans-serif'] = [u'simHei']
mpl.rcParams['axes.unicode_minus'] = False
for k in range(1,K+1):
print(k)
R = restorel(sigma_r, u_r, v_r, k)
G = restorel(sigma_g, u_g, v_g, k)
B = restorel(sigma_b, u_b, v_b, k)
I = np.stack((R,G,B),axis=2)
Image.fromarray(I).save("%s\\svd_%d.png"%(output_path,k))
if k <= 12:
plt.subplot(3, 4, k)
plt.imshow(I)
plt.axis('off')
plt.title(u'奇异值个数:%d' % k)
plt.suptitle(u'SVD与图像分解',fontsize = 20)
plt.tight_layout(0.3, rect=(0,0,1,0.92))
plt.show()