用Manim简单解释奇异值分解(SVD)和图像处理方面的应

一,介绍  

      奇异值分解(SVD)是一种重要的矩阵分解技术,在统计学、信号处理和机器学习等领域有广泛应用。对于任意给定的矩阵 A(可以是任意形状的矩阵),SVD将其分解为三个特定的矩阵的乘积:

A=USV^{T}

其中,U是一个 m×m 的正交矩阵,表示左奇异向量;S 是一个 m×n 的对角矩阵,包含了非负的奇异值,按照从大到小排序;V^{T} 是一个 n×n 的正交矩阵,表示右奇异向量。

        奇异值反映了矩阵的特征,最大的奇异值对应着数据中最重要的结构或信息。通过选择前 kk 个奇异值及其对应的奇异向量,可以有效地构建出对原矩阵的近似,这为很多应用提供了基础,如数据压缩、特征提取和降噪。例如,在图像处理中,SVD 可以将图像矩阵进行分解与近似,从而实现图像的压缩。

        此外,SVD 还具有良好的数值稳定性,能够处理病态矩阵,这使得它成为处理高维数据时的重要工具。总之,奇异值分解不仅是理论研究的重要工具,也是实际应用中的关键技术。

 二,SVD的基本原理

使用奇异值分解(SVD)压缩图像是一种有效的图像压缩方法,其基本原理如下:

1. 奇异值分解(SVD)的概念

奇异值分解是一种矩阵分解方法,可以将任意一个矩阵 AA分解为三个矩阵的乘积:

A=USV^{T}

其中,U和 V是正交矩阵,S 是对角矩阵,包含了奇异值(表示矩阵 A的重要特征)。

2. 图像表示

在图像处理中,图像通常被表示为一个矩阵。例如,一个灰度图像可以看作是一个大小为 m×n 的矩阵,其中每个元素代表一个像素的灰度值。

3. 图像压缩过程

  • 步骤一:分解图像矩阵
    首先,使用 SVD 将图像矩阵 A进行分解,得到 U、S 和 V。

  • 步骤二:选择前 kk 个奇异值
    为了压缩图像,可以仅保留前 k个最大的奇异值,并相应地截断 U和 V。这意味着丢弃较小的奇异值,从而降低数据的复杂度。

  • 步骤三:重构图像
    使用保留下来的奇异值及其对应的向量重构一个新的矩阵:

A_{K}=U_{K}S_{K}V_{K}^{T}

其中,U_{K} 和 V_{K}​ 只包含前 k 列,并且 S_{K}​ 是一个 k×k的对角矩阵。

4. 压缩效果

通过保留较少的奇异值,压缩后的图像矩阵 A_{K} 将会显著减少所需的存储空间,同时尽可能保持图像的主要特征和质量。与此同时,丢弃高频信息(如细节和噪声)有助于实现压缩。

5. 应用场景

这种压缩方法广泛应用于图像存储和传输,尤其在带宽和存储空间受限的情况下。它还用于图像处理、特征提取和降噪。

总结来说,利用 SVD 来压缩图像是通过矩阵分解技术减少数据存储需求,同时尽量保留图像的视觉质量。

用manim可视化计算

        考虑如下简单的剪切矩阵:

A=\begin{bmatrix} 2 &2 \\ 0 &2 \end{bmatrix}

 我们可以使用开源的manim python库来可视化一个A和它的分解

A=USV^{T} :

 

from manim import *  
import numpy as np  

secondary_color = DARK_GREY  # 设置背景颜色  
axes_color = GREY             # 设置坐标轴颜色  
i_hat_color = RED             # 设置 i 方向颜色  
j_hat_color = YELLOW          # 设置 j 方向颜色  

class SVD_2D112201(LinearTransformationScene):  
    def construct(self):  
        
        self.camera.background_color = secondary_color  # 设置场景背景颜色  
        
        # 创建一个圆形并移动到右上角  
        circle = Circle()  
        circle.move_to(RIGHT + UP)  

        # 添加可变换的对象(圆形)  
        self.add_transformable_mobject(circle)  

        # 各种文本说明  
        text_applying = Tex("Applying $ A $ (overall transformation)")  
        text_applying.to_edge([0, 5, 0])  # 将文本移动到上方位置  

        text_applying_inverse = Tex("Applying $ A^{-1} $ (resetting)")  
        text_applying_inverse.to_edge([0, 4, 0])  # 将文本移动到稍低位置  

        text_applying_vt = Tex(r"Applying $ V^\top $ (rotating)")  
        text_applying_vt.to_edge([0, 3, 0])  # 将文本移动到更低的位置  

        text_applying_s = Tex(r"Applying $ S $ (stretching)")  
        text_applying_s.to_edge([0, -4, 0])  # 将文本移动到底部位置  

        text_applying_u = Tex("Applying $ U $ (rotating)")  
        text_applying_u.to_edge([0, -4, 0])  # 将文本移动到底部位置  
        
        # 定义矩阵 A  
        A = np.array([  
            [2, 2],  
            [0, 2]  
        ])  

        # 播放写入文本的动画  
        self.play(Write(text_applying), run_time=0.5)  
        # 应用矩阵 A 进行变换  
        self.apply_matrix(A)  

        self.wait()  # 等待  
        self.wait(0.5)  

        # self.leave_ghost_vectors = True  # 是否留下一些轨迹  

        # 变换文本,表示重置操作  
        self.play(Transform(text_applying, text_applying_inverse), run_time=0.5)  
        # 应用矩阵 A 的逆进行变换  
        self.apply_inverse(A)  

        self.wait()  # 等待  
        self.wait(0.5)  

        # self.leave_ghost_vectors = False  # 不留下一些轨迹  

        # 使用 SVD 分解矩阵 A  
        U, S, VT = np.linalg.svd(A)  
        
        # 变换文本为表示应用 V^T  
        self.play(Transform(text_applying_inverse, text_applying_vt), run_time=0.5)  
        # 应用 V^T 进行旋转变换  
        self.apply_matrix(VT)  

        self.wait()  # 等待  
        self.wait(0.5)  

        # 变换文本为表示应用 S  
        self.play(Transform(text_applying_vt, text_applying_s), run_time=0.5)  
        # 应用奇异值矩阵 S 进行拉伸变换  
        self.apply_matrix(np.diag(S))  

        self.wait()  # 等待  
        self.wait(0.5)  

        # 变换文本为表示应用 U  
        self.play(Transform(text_applying_s, text_applying_u), run_time=0.5)  
        # 清除文本  
        self.play(FadeOut(text_applying_s))   
        # 应用 U 进行旋转变换  
        self.apply_matrix(U)  

        self.wait()  # 等待  
        self.wait(0.5)  
        
        # 在每次变换后,处理文本的层次关系

 为了计算SVD分解,我使用了np. linear . SVD函数,该函数返回带有U,S和V^{T}。如预期的矩阵。然而,出于效率原因,numpy回报S作为一个向量(存储不在对角线上的零没有意义)。这就是我后来用np的原因。将一个向量转换成一个在对角线上的矩阵。

运行后我们得到结果:

 

目的是用于演示二维空间中的矩阵变换,特别是奇异值分解(SVD)的过程。下面是对代码的详细解释:

1. 导入库

from manim import * import numpy as np 
  • 导入 Manim 库,主要用于创建动画。
  • 导入 NumPy 库,用于数学计算和数组操作。

2. 配置颜色

secondary_color = DARK_GREY 
axes_color = GREY 
i_hat_color = RED 
j_hat_color = YELLOW 
  • 设定动画中使用的颜色,以便后续使用。

3. 定义类

class SVD_2D112201(LinearTransformationScene): 
  • 定义一个新的场景类 SVD_2D112201,该类继承自 LinearTransformationScene,后者提供了处理线性变换和动画的基本功能。

4. 构造函数

def construct(self): 
  • construct 方法是所有 Manim 场景的入口,定义了这个场景中将要展示的内容。

5. 设置背景和添加对象

self.camera.background_color = secondary_color 
circle = Circle() 
circle.move_to(RIGHT + UP) 
self.add_transformable_mobject(circle) 
  • 设置相机的背景颜色。
  • 创建一个圆,并将其移动到右上角的位置。
  • 将圆添加到场景中,使其成为可变换的对象。

6. 创建文本标签

text_applying = Tex("Applying $ A $ (overall transformation)") 
text_applying.to_edge([0, 5, 0]) 
  • 创建多个文本对象,用于描述矩阵操作的每一步。
  • 使用 to_edge 方法将文本移动到场景中的不同位置。

7. 定义变换矩阵

A = np.array([ [2, 2], [0, 2] ]) 
  • 定义一个 2x2 矩阵 A,这个矩阵将用于后续的线性变换。

8. 播放动画

self.play(Write(text_applying), run_time=0.5) 
self.apply_matrix(A) 
  • 播放一个写入文本的动画,持续时间为 0.5 秒。
  • 应用矩阵 A 进行空间变换,使用 apply_matrix 方法。

9. 表示逆变换

self.play(Transform(text_applying, text_applying_inverse), run_time=0.5) 
self.apply_inverse(A) 
  • 将当前文本变换为表示逆变换的文本。
  • 应用矩阵 A 的逆进行变换(即复原原来的状态)。

10. 奇异值分解 (SVD)

U, S, VT = np.linalg.svd(A) 
  • 对矩阵 A 进行奇异值分解,得到 U、S 和 V^T。

11. 继续动画并逐步应用变换

self.play(Transform(text_applying_inverse, text_applying_vt), run_time=0.5) 
self.apply_matrix(VT) 
  • 变换文本为表示旋转的部分,应用 V^T 进行变换。

12. 应用奇异值矩阵 S

self.play(Transform(text_applying_vt, text_applying_s), run_time=0.5) 
self.apply_matrix(np.diag(S)) 
  • 继续变换文本,表示对 S 的应用,并用对角矩阵形式的 S 进行拉伸变换。

13. 最后应用 U 矩阵

self.play(Transform(text_applying_s, text_applying_u), run_time=0.5) 
self.play(FadeOut(text_applying_s)) 
self.apply_matrix(U) 
  • 最后变换文本为表示 U 的应用,清除 S 的文本并应用 U 的变换。

14. 等待动画

self.wait() self.wait(0.5) 
  • 在每个变换后设置等待时间,以便观众能够看到效果。

15. 总结

整个代码通过奇异值分解的一系列变换过程,展现了一个原始矩阵(A)如何通过三个不同的矩阵(V^T、S、U)的组合,实现从原始形状到变换后形状的过渡。这是线性代数和图形学中非常重要的概念,通过这样的可视化演示,能够帮助观众更好地理解矩阵变换的过程及其几何意义。

 

利用SVD进行图片压缩

让我们专注于压缩一个矩阵, 如上所述,应用SVD分解得到:

 我们可以用一种稍微不同的方式重写这个分解:

 有了这个符号,我们可以从稍微不同的角度来考虑SVD允许我们取任意矩阵并将其写成秩1矩阵的和。如果我们取一个随机矩阵A,它不太可能不是全秩的。所以对于一个宽度为w,高度为h的随机图像。

import numpy as np  # 导入 NumPy 库,用于数值计算和数组处理  
import matplotlib.image as image  # 导入 Matplotlib 的图像处理模块  
import matplotlib.pyplot as plt  # 导入 Matplotlib 的绘图库,用于可视化  

# 读取图像文件 "img.jpg"  
A = image.imread("myimg.jpg")  # 使用 Matplotlib 读取指定路径的图像  

# 将图像的 RGB 通道分离并归一化  
R = A[:,:,0] / 0xff  # 提取红色通道并归一化到 [0, 1] 区间  
G = A[:,:,1] / 0xff  # 提取绿色通道并归一化到 [0, 1] 区间  
B = A[:,:,2] / 0xff  # 提取蓝色通道并归一化到 [0, 1] 区间  

# 对每个颜色通道进行奇异值分解 (SVD)  
R_U, R_S, R_VT = np.linalg.svd(R)  # 对红色通道进行 SVD 分解  
G_U, G_S, G_VT = np.linalg.svd(G)  # 对绿色通道进行 SVD 分解  
B_U, B_S, B_VT = np.linalg.svd(B)  # 对蓝色通道进行 SVD 分解  

# 设置相对秩来控制压缩级别  
relative_rank = 0.05  # 定义相对秩的比例  
max_rank = int(relative_rank * min(R.shape[0], R.shape[1]))  # 计算最大秩,基于图像的最小维度  
print("max rank = %d" % max_rank)  # 打印最大秩(此处为 144)  

# 定义函数以使用给定秩 k 读取压缩的图像  
def read_as_compressed(U, S, VT, k):  
    A = np.zeros((U.shape[0], VT.shape[1]))  # 初始化一个零矩阵以存储重建的图像  
    for i in range(k):  # 遍历每个奇异值  
        U_i = U[:,[i]]  # 提取第 i 列 U 矩阵  
        VT_i = np.array([VT[i]])  # 提取第 i 行 V^T 矩阵  
        A += S[i] * (U_i @ VT_i)  # 更新重建图像,乘以对应的奇异值  
    return A  # 返回压缩图像  

# 定义另一种形式的读入压缩图像的函数(冗余定义)  
def read_as_compressed(U, S, VT, k):  
    return (U[:,:k] @ np.diag(S[:k])) @ VT[:k]  # 直接计算压缩图像矩阵  

# 使用 SVD 结果和最大秩计算压缩后的 RGB 通道  
R_compressed = read_as_compressed(R_U, R_S, R_VT, max_rank)  # 压缩红色通道  
G_compressed = read_as_compressed(G_U, G_S, G_VT, max_rank)  # 压缩绿色通道  
B_compressed = read_as_compressed(B_U, B_S, B_VT, max_rank)  # 压缩蓝色通道  

# 将压缩的 RGB 通道合并为一张图像  
compressed_float = np.dstack((R_compressed, G_compressed, B_compressed))  # 将压缩通道堆叠成一个三维数组  
compressed = (np.minimum(compressed_float, 1.0) * 0xff).astype(np.uint8)  # 将值限制在 [0, 255] 范围内并转化为 uint8 类型  

# 显示原始图像和压缩图像并排  
plt.figure(figsize=(160, 90))  # 创建一个 16:9 的图形窗口  
plt.subplot(1, 2, 1)  # 在图形的 1 行 2 列的第 1 个位置上创建子图  
plt.title("Original Image")  # 设置子图标题为 “Original Image”  
plt.imshow(A)  # 显示原始图像  

plt.subplot(1, 2, 2)  # 在图形的 1 行 2 列的第 2 个位置上创建子图  
plt.title("Compressed Image")  # 设置子图标题为 “Compressed Image”  
plt.imshow(compressed)  # 显示压缩后图像  

plt.show()  # 展示整个图形窗口  

# 保存压缩图像到文件  
image.imsave("com160-90.png", compressed)  # 将压缩后的图像保存为 “compressed001122.png”

 当秩序比=0.05时

 当秩序比=0.5时

 

秩序比rank=0时,我们根本不进行近似,因此得到零矩阵,这意味着所有像素都是黑色的:

 如果。先看到详细的过程可以看看这个文章https://download.csdn.net/download/qq_45449625/89856632icon-default.png?t=O83Ahttps://download.csdn.net/download/qq_45449625/89856632

在这个文章中提到:

内容概要:本文介绍了利用奇异值分解(SVD)进行图像压缩的基本数学理论和技术细节,并展示了应用效果以及与传统JPEG压缩对比的优点,详细探讨了不同参数设置对图像质量和压缩比的影响。

适用人群:专注于信号处理的研究员、数据分析师和技术专家;从事图像编码相关工作的程序员。 使用场景及目标:适用于图像处理领域的应用场景,在需要高效储存并保持一定质量水平时,可以运用SVD压缩算法来减小占用的空间。 其他说明:选择合适的重要系数值‘k’来确保既能达到期望的压缩率又不会使重建后的图片质量降低过多是图像压缩的核心课题之一,文中提供了依据实际效果调整参数的方法和标准。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/888172.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

idea2024设置中文

今天下载idea2024.2版本,发现已经装过中文插件,但是还是不显示中文,找了半天原来还需要设置中文选项 方案一 点击文件 -> 关闭项目 点击自定义 -> 选择语言 方案二 点击文件 -> 设置 外观与行为 -> 系统设置 -> 语言和地区…

LSTM时序预测 | Python实现LSTM长短期记忆神经网络时间序列预测

本文内容:Python实现LSTM长短期记忆神经网络时间序列预测,使用的数据集为AirPassengers 目录 数据集简介 1.步骤一 2.步骤二 3.步骤三 4.步骤四 数据集简介 AirPassengers 数据集的来源可以追溯到经典的统计和时间序列分析文献。原始数据集由 Box,…

增强分析:新时代的数据洞察工具

随着数据科学和人工智能的迅猛发展,分析数据的方式也发生了显著的变化。增强分析(Augmented Analytics)是近年来涌现出的新概念,它将人工智能(AI)、机器学习(ML)和自然语言处理&…

HarmonyOS NEXT - 表单录入组件封装(TextInput)

demo 地址: https://github.com/iotjin/JhHarmonyDemo 组件对应代码实现地址 代码不定时更新,请前往github查看最新代码 HarmonyOS NEXT - 表单录入组件封装(TextInput) 序JhFormInputCellJhFormSelectCellJhLoginTextField 序 鸿蒙next中有两…

java 的三种IO模型(BIO、NIO、AIO)

java 的三种IO模型(BIO、NIO、AIO) 一、BIO 阻塞式 IO(Blocking IO)1.1、BIO 工作机制1.2、BIO 实现单发单收1.3、BIO 实现多发多收1.4、BIO 实现客户端服务端多对一1.5、BIO 模式下的端口转发思想 二、NIO 同步非阻塞式 IO&#…

Android15车载音频之Virtualbox中QACT实时调试(八十八)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+…

Pikachu- Over Permission-垂直越权

以admin 账号登陆,添加一个用户; 把添加用户的这个请求发送到 repeater; 退出admin,使用普通用户pikachu登陆; 只有查看权限; 使用pikachu 用户的认证信息,替换repeater处管理员创建用户请求的…

六、索引的数据结构

文章目录 1. 为什么使用索引2. 索引及其优缺点2.1 索引概述2.2 优点2.3 缺点3. InnoDB中索引的推演3.1 索引之前的查找3.1.1 在一个页中的查找3.1.2 在很多页中查找3.2 设计索引3.2.1 一个简单的索引设计方案3.2.2 InnoDB中的索引方案3.3 常见索引概念3.3.1 聚簇索引3.3.2 二级…

UDP协议【网络】

文章目录 UDP协议格式 UDP协议格式 16位源端口号:表示数据从哪里来。16位目的端口号:表示数据要到哪里去。16位UDP长度:表示整个数据报(UDP首部UDP数据)的长度。16位UDP检验和:如果UDP报文的检验和出错&…

centos一些常用命令

文章目录 查看磁盘信息使用 df 命令使用 du 命令 查看磁盘信息 使用 df 命令 df(disk free)命令用于显示文件系统的磁盘空间占用情况。 查看所有挂载点的磁盘使用情况: df -h选项说明: -h 参数表示以人类可读的格式&#xff0…

Windows下Jenkins控制台中文乱码

问题描述 问题情况如下图: 环境信息 Windows 11 家庭中文版java 21.0.4 2024-07-16 LTSJenkins 2.452.3 解决方法 增加系统JAVA_TOOL_OPTIONS,并设置值为-Dfile.encodingGBK。 打开设置方法:桌面上右键点击“此电脑”图标,选…

【黑马点评】使用RabbitMQ实现消息队列——3.使用Jmeter压力测试,导入批量token,测试异步秒杀下单

3 批量获取用户token,使用jmeter压力测试 3 批量获取用户token,使用jmeter压力测试3.1 需求3.2 实现3.2.1 环境配置3.2.2 修改登录接口UserController和实现类3.2.3 测试类 3.3 使用jmeter进行测试3.4 测试结果3.5 将用户登录逻辑修改回去 3 批量获取用户…

力扣16~20题

题16&#xff08;中等&#xff09;&#xff1a; 思路&#xff1a; 双指针法&#xff0c;和15题差不多&#xff0c;就是要排除了&#xff0c;如果total<target则排除了更小的&#xff08;left右移&#xff09;&#xff0c;如果total>target则排除了更大的&#xff08;rig…

三绕组单相电容电动机的瞬态分析(2)定子三角形接法时起动过程及稳态性能分析

1. 引言 2. 定子接三绕组单相电容电动机的数学模型 3.最佳移相电容计算 4. 仿真分析实例 5. 总结 6. 参考文献 1. 引言 目前,三相供电系统在全世界范围内已是非常普遍了。但是,由于架设输电线成本高,受输、配电系统的限制,城市居民用电和大多数农村及边远地区的用电仍…

JavaWeb——Vue路由(概述、介绍、使用、解决bug)

目录 概述 介绍 使用 解决bug 概述 员工管理的页面已经制作完成。其他页面的制作方式一致。 项目中准备了部门管理的页面组件 DeptView &#xff0c;这样就有了员工管理和部门管理两个页面组件。 在系统中&#xff0c;要实现点击部门管理菜单展示部门管理组件&#xff0c…

线性代数入门指南

在数学的广袤领域中&#xff0c;线性代数犹如一座神秘而又充满魅力的殿堂&#xff0c;等待着初学者去探索。当你踏入线性代数的大门&#xff0c;便开启了一段充满挑战与惊喜的知识之旅。 线性代数是什么呢&#xff1f;简单来说&#xff0c;它是一门研究线性方程组、向量空间、线…

Android Automotive(一)

目录 什么是Android Automotive Android Automotive & Android Android Automotive 与 Android Auto 什么是Android Automotive Android Automotive 是一个基础的 Android 平台&#xff0c;它能够运行预装的车载信息娱乐系统&#xff08;IVI&#xff09;应用程序&#…

分治算法(3)_快速选择_数组中的第K个最大元素

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 分治算法(3)_快速排序_数组中的第K个最大元素 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#…

51单片机的自动制冷系统【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块温度传感器继电器LED、按键和蜂鸣器等模块构成。适用于车载便携式自动制冷系统、冰箱制冷、温度控制等相似项目。 可实现功能: 1、LCD1602实时显示当前温度 2、温度传感器DS18B20采集温度 3、按键可设置温度的阈…

双向数据库迁移工具:轻松实现 MySQL 与 SQLite 数据互导

项目概述与作用 该项目的核心是实现 MySQL 和 SQLite 两种数据库之间的数据迁移工具。它能够轻松地将 MySQL 数据库中的数据导出为 SQLite 数据库文件&#xff0c;反过来也可以将 SQLite 数据库中的数据上传到 MySQL 数据库中。这个双向迁移工具非常适用于&#xff1a; 数据库备…