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

news2024/11/24 17:09:31

一,介绍  

      奇异值分解(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.coloradmin.cn/o/2195570.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【时间盒子】-【9.任务设置项】自定义任务名称、任务时长等设置项组件

Tips: Stage、Link装饰器的使用; 参考我的帖子:https://developer.huawei.com/consumer/cn/forum/topic/0208152234389094513?fid0101587866109860105 一、预览 红色框:任务设置项列表,把它定义为一个组件对象SettingList。绿…

Python 工具库每日推荐【PyPDF2】

文章目录 引言Python PDF 处理库的重要性今日推荐:PyPDF2 工具库主要功能:使用场景:安装与配置快速上手示例代码代码解释实际应用案例案例:PDF文件合并案例分析高级特性加密和解密PDF添加水印扩展阅读与资源优缺点分析优点:缺点:总结【 已更新完 TypeScript 设计模式 专栏…

Vue基础(2)检测数据原理~生命周期

文章目录 检测数据原理1.更新时遇到的问题2.检测数据的原理-对象3. vue.set()的使用 收集表单数据过滤器内置指令1.v-text2.v-html3.v-cloak4.v-once5.v-pre 自定义指令生命周期1.挂载流程2.更新流程3.销毁流程 检测数据原理 1.Vue会监视data中的所有层次的数据 2.如何监测对象…

10月8日星期二今日早报简报微语报早读

10月8日星期二,农历九月初六,早报#微语早读。 1、我国自主研制的300兆瓦级F级重型燃气轮机在上海首次点火成功; 2、2024国庆档超21亿收官:《志愿军:存亡之战》票房8亿夺冠; 3、维克托安布罗斯&#xff0…

STM32工程环境搭建(库函数开发)

目录 1、移植固件库&标准库 2、新建工程 以STM32f401作为例子进行环境搭建 1、移植固件库&标准库 ①桌面创建工程文件夹并且提取内核文件 用户文件:用户自己编写的程序文件 .c .h文件 .c文件:具体函数功能源代码 .h文件:宏定义…

ctf.bugku - bp (弱密码top1000)

题目来源: bp - Bugku CTF 首先,下载top1000 ,弱密码文本: PasswordDic/top1000.txt at master k8gege/PasswordDic GitHub 访问页面,随便输入个密码 发送请求到 intruder 以密码问参数 加载top1000.txt 密码文本&…

springboot开发网站-使用redis数据库定时特征限制指定ip的访问次数

springboot开发网站-使用redis数据库定时特征限制指定ip的访问次数。近期网站经常有人恶意访问,提交了很多垃圾信息。为了屏蔽这类灌水帖,打算屏蔽ip地址,限制24小时内只能访问1次某个接口。下面是测试的案例代码内容。 1:首先&am…

实验三 Web基础-JavaScript

实验三 Web基础-JavaScript 目的: 1、理解和掌握Javascript基本语法 2、掌握JavaScript操作表单对象的方法 3、理解和掌握JavaScript的函数与事件 4、理解JavaScript的内置对象 实验要求: 1、使用JavaScript语言实现实验要求 2、要求提交实验报告&…

HTB:Pennyworth[WriteUP]

目录 连接至HTB服务器并启动靶机 1.What does the acronym CVE stand for? 2.What do the three letters in CIA, referring to the CIA triad in cybersecurity, stand for? 3.What is the version of the service running on port 8080? 4.What version of Jenkins i…

【C++11】可变模板参数

文章目录 可变模板参数的概念递归函数方式展开参数包 STL容器中的empalce相关的接口函数emplace 与 insert / push_back 的区别 可变模板参数的概念 可变参数模板是 C11 引入的一种模板特性,允许定义可以接收任意数量参数的模板,广泛应用于函数和类的设计…

【js逆向学习】极志愿 javascript+python+rpc

JSRPC使用方式 逆向目标逆向过程逆向分析1、什么是 websocket2、websocket的原理3、总体过程3.1 环境说明3.2 python服务端代码3.3 python客户端代码 4、Sekiro-RPC4.1 执行方式4.2 客户端环境4.3 参数说明4.4 SK API4.5 python代码调试4.6 代码注入流程 逆向总结 逆向目标 网…

【STM32开发之寄存器版】(六)-通用定时器中断

一、前言 STM32定时器分类 STM32103ZET6具备8个定时器TIMx(x 1,2,...,8)。其中,TIM1和TIM8为高级定时器,TIM2-TIM6为通用定时器,TIM6和TIM7为基本定时器,本文将以TIM3通用定时器为例,分析STM32定时器工作的底层寄存器…

mysql读写分离的最佳实践

一. 传统的读写分离方式 在 MySQL 中实现读写分离可以通过以下几种方式来达到目的: 1. 主从复制 使用主从复制(Master-Slave Replication)是实现读写分离的常见方式。 主库:处理所有的写入操作(INSERT、UPDATE、DE…

Qt+VS2019+大恒相机相机回调方式总结

一、前言 大恒驱动安装完成后,在安装目录有SDK调用文档,里面有更详细的调用介绍,此文档对近期做的Demo做一个回顾性总结。 二、调用流程概述 三、针对性内容介绍: 1. 在执行相机操作之前,需要先执行此代码&#xff1…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-07

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-07 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-07目录1. Evaluation of Large Language Models for Summarization Tasks in the Medical Domain: A Narrative Review摘要研究…

rust中async/await的使用

在Rust中,async/await 用于编写异步代码。它允许您以同步的方式编写异步代码,使得异步操作更易于理解和编写。 安装依赖: cargo add futures cargo add async-std 使用示例: 示例1: use async_std::task::block_o…

学习MDX

MDX(Markdown JSX)是一种开源的文件格式,它允许你在Markdown文件中使用JavaScript表达式和组件。MDX将Markdown的易用性与React组件的强大功能结合起来,使得你可以在编写文档、博客文章或其他内容时,嵌入可交互的组件…

顶会论文复现:PROVING TEST SET CONTAMINATION IN BLACK BOX LANGUAGE MODELS

文章目录 1 资料2 我的总结3 复现源码首先你需要有gpt的api接口安装:数据集执行指令源码 4 结果 1 资料 我复现的源码:https://github.com/Whiffe/test_set_contamination 官网源码:https://github.com/tatsu-lab/test_set_contamination 论文&#x…

tts(text to speech)使用 pyttsx3 实现文本转语音 - python 实现

文本转语音(Text-to-Speech,TTS)技术是一种将文本信息转换为口语输出的技术。它涉及多个学科,包括声学、语言学、数学信号处理技术和多媒体技术等。TTS技术能够将计算机中的文本信息转换为自然流畅的语音输出,广泛应用…

OJ在线评测系统 后端微服务架构 注册中心 Nacos入门到启动

注册中心 服务架构中的注册中心是一个关键组件,用于管理和协助微服务之间的通信。注册中心的主要职责是服务的注册和发现,确保各个微服务能够相互找到并进行调用。 主要功能: 服务注册:微服务在启动时,将自身信息&am…