python对图片svd分解_QR分解

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]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值