python對圖片svd分解_QR分解
阿新 • • 發佈:2020-12-10
1、SVD分解
1、描述
在程式碼中使用到了一些圖片,大家只需要將圖片放到pycharm指定的路徑中既可以使用,為了方便大家的學習,現將圖片儲存到部落格的資源中,資源路徑如下:
https://download.csdn.net/download/weixin_43334389/13569487
2、程式碼
# @Time : 2020/12/7 15:19
# @Description : 對圖片進行SVD奇異值分解程式碼
import numpy as np
import os
from PIL import Image
import matplotlib. pyplot as plt
import matplotlib as mpl
from pprint import pprint
def restore1(sigma, u, v, K):
"""
@desc:
@param sigma:奇異值
@param u:左特徵向量
@param v:右特徵向量
@param K:需要的維度資訊
@return:返回一個在k(k<n)維度下的影象
"""
m = len(u)
n = len(v[0])
a = np.zeros((m, n))
for k in range(K):
uk = u[:, k].reshape(m, 1)
vk = v[k].reshape(1, n)
# a為(m*n)的矩陣,將左右特徵向量轉化尺寸後
a += sigma[k] * np.dot(uk, vk)
a[a < 0] = 0
a[a > 255] = 255
return np.rint(a).astype('uint8')
def restore2(sigma, u, v, K):
# 列向量
m = len(u)
# 行向量
n = len(v[0])
a = np.zeros((m, n))
for k in range(K + 1):
for i in range(m):
# u的列向量和v的每一行向量進行相乘
# a[0] = sigma * u的第一列的第一個值 * v的第一行所對應的向量
# a一共有m行
a[i] += sigma[k] * u[i][k] * v[k]
a[a < 0] = 0
a[a > 255] = 255
return np.rint(a).astype('uint8')
if __name__ == "__main__":
# 引入照片的路徑
A = Image.open("son.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])
plt.figure(figsize=(10, 10), facecolor='w')
mpl.rcParams['font.sans-serif'] = [u'simHei']
mpl.rcParams['axes.unicode_minus'] = False
# 取前k個特徵(R,G,B這三個通道),再將影象拼出來
for k in range(1, K + 1):
R = restore1(sigma_r, u_r, v_r, k)
G = restore1(sigma_g, u_g, v_g, k)
B = restore1(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()
3、結果展示
2、QR分解
1、描述
使用QR分解計算A矩陣的特徵值,原理:對A一直求合同,上三角矩陣會越來越弱,最後Ak只剩下對角線上的值,此時Ak對角線上的值即為特徵值,也為A的特徵值。
2、程式碼
# @Time : 2020/12/7 17:47
# @Description : 使用QR分解計算特徵值
import math
import numpy as np
def is_same(a, b):
"""
@desc: 比較a_k和a_k+1這兩個矩陣對角線上的值,如果很相近就結束迭代。
@param a:r,q相乘得到的矩陣對角線上的值
@param b:是上一個a對應的矩陣對角線上的值
@return:
"""
n = len(a)
for i in range(n):
if math.fabs(a[i] - b[i]) > 1e-6:
return False
return True
if __name__ == "__main__":
a = np.array([0.65, 0.28, 0.07, 0.15, 0.67, 0.18, 0.12, 0.36, 0.52])
n = int(math.sqrt(len(a)))
# 3*3矩陣
a = a.reshape((n, n))
# 特徵值,特徵向量
value, v = np.linalg.eig(a)
times = 0
# 返回True時結束迭代過程
# 隨著迭代次數的進行,a對應的對角陣r上三角部分會越來越弱(特徵值),最後對角線
# 的值即為特徵值
while (times == 0) or (not is_same(np.diag(a), v)):
# 對角矩陣的值
v = np.diag(a)
q, r = np.linalg.qr(a)
# qr分解
a = np.dot(r, q)
times += 1
print("正交陣:\n", q)
print("三角陣:\n", r)
print("近似陣:\n", a)
print("次數:", times, "近似值:", np.diag(a))
print("精確特徵值:", value)
3、結果展示
最後一次控制檯輸出:
正交陣:
[[-1.00000000e+00 2.14199684e-05 -1.59459985e-09]
[-2.14199681e-05 -9.99999995e-01 -1.01004056e-04]
[-3.75810352e-09 -1.01004056e-04 9.99999995e-01]]
三角陣:
[[-9.99998810e-01 -2.68197256e-02 2.26014254e-01]
[ 0.00000000e+00 -5.18489185e-01 -7.96303223e-05]
[ 0.00000000e+00 0.00000000e+00 3.21511428e-01]]
近似陣:
[[ 9.99999383e-01 2.67754771e-02 2.26016964e-01]
[ 1.11060221e-05 5.18489190e-01 -2.72608113e-05]
[-1.20827323e-09 -3.24739582e-05 3.21511427e-01]]
次數: 17 近似值: [0.99999938 0.51848919 0.32151143]
精確特徵值: [1. 0.51848858 0.32151142]