1. 程式人生 > 其它 >python對圖片svd分解_QR分解

python對圖片svd分解_QR分解

技術標籤:pythonpython

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]