NumPy 之: 多维数组中的线性代数
简介
本文将会以图表的形式为大家讲解怎么在 NumPy 中进行多维数据的线性代数运算。
多维数据的线性代数通常被用在图像处理的图形变换中,本文将会使用一个图像的例子进行说明。
图形加载和说明
熟悉颜色的朋友应该都知道,一个颜色可以用 R,G,B 来表示,如果更高级一点,那么还有一个 A 表示透明度。通常我们用一个四个属性的数组来表示。
对于一个二维的图像来说,其分辨率可以看做是一个 X*Y 的矩阵,矩阵中的每个点的颜色都可以用(R,G,B)来表示。
有了上面的知识,我们就可以对图像的颜色进行分解了。
首先需要加载一个图像,我们使用 imageio.imread 方法来加载一个本地图像,如下所示:
上面的代码从本地读取图片到 img 对象中,使用 type 可以查看 img 的类型,从运行结果,我们可以看到 img 的类型是一个数组。
通过 img.shape 可以得到 img 是一个(80, 170, 4)的三维数组,也就是说这个图像的分辨率是 80*170,每个像素是一个(R,B,G,A)的数组。
最后将图像画出来如下所示:
图形的灰度
对于三维数组来说,我们可以分别得到三种颜色的数组如下所示:
有了三个颜色之后我们可以使用下面的公式对其进行灰度变换:
上图中 Y 表示的是灰度。
怎么使用矩阵的乘法呢?使用 @ 就可以了:
现在 img 是一个 80 * 170 的矩阵。
现在使用 cmap=”gray”作图:
可以得到下面的灰度图像:
灰度图像的压缩
灰度图像是对图像的颜色进行变换,如果要对图像进行压缩该怎么处理呢?
矩阵运算中有一个概念叫做奇异值和特征值。
设 A 为 n 阶矩阵,若存在常数λ及 n 维非零向量 x,使得 Ax=λx,则称λ是矩阵 A 的特征值,x 是 A 属于特征值λ的特征向量。
一个矩阵的一组特征向量是一组正交向量。
即特征向量被施以线性变换 A 只会使向量伸长或缩短而其方向不被改变。
特征分解(Eigendecomposition),又称谱分解(Spectral decomposition)是将矩阵分解为由其特征值和特征向量表示的矩阵之积的方法。
假如 A 是 m * n 阶矩阵,q=min(m,n),A*A 的 q 个非负特征值的算术平方根叫作 A 的奇异值。
特征值分解可以方便的提取矩阵的特征,但是前提是这个矩阵是一个方阵。如果是非方阵的情况下,就需要用到奇异值分解了。先看下奇异值分解的定义:
A=UΣV^TA=UΣVT
其中 A 是目标要分解的 m * n 的矩阵,U 是一个 m * m 的方阵,Σ 是一个 m * n 的矩阵,其非对角线上的元素都是 0。V^TVT 是 V 的转置,也是一个 n * n 的矩阵。
奇异值跟特征值类似,在矩阵Σ中也是从大到小排列,而且奇异值的减少特别的快,在很多情况下,前 10%甚至 1%的奇异值的和就占了全部的奇异值之和的 99%以上了。也就是说,我们也可以用前 r 大的奇异值来近似描述矩阵。r 是一个远小于 m、n 的数,这样就可以进行压缩矩阵。
通过奇异值分解,我们可以通过更加少量的数据来近似替代原矩阵。
要想使用奇异值分解 svd 可以直接调用 linalg.svd 如下所示:
其中 U 是一个 m * m 矩阵,Vt 是一个 n * n 矩阵。
在上述的图像中,U 是一个(80, 80)的矩阵,而 Vt 是一个(170, 170) 的矩阵。而 s 是一个 80 的数组,s 包含了 img 中的奇异值。
如果将 s 用图像来表示,我们可以看到大部分的奇异值都集中在前的部分:
这也就意味着,我们可以取 s 中前面的部分值来进行图像的重构。
使用 s 对图像进行重构,需要将 s 还原成 80 * 170 的矩阵:
使用 U @ Sigma @ Vt 即可重建原来的矩阵,可以通过计算 linalg.norm 来比较一下原矩阵和重建的矩阵之间的差异。
或者使用 np.allclose 来比较两个矩阵的不同:
或者只取 s 数组的前 10 个元素,进行重新绘图,比较一下和原图的区别:
可以看到,差异并不是很大:
原始图像的压缩
上一节我们讲到了如何进行灰度图像的压缩,那么如何对原始图像进行压缩呢?
同样可以使用 linalg.svd 对矩阵进行分解。
但是在使用前需要进行一些处理,因为原始图像的 img_array 是一个(80, 170, 3)的矩阵–这里我们将透明度去掉了,只保留了 R,B,G 三个属性。
在进行转换之前,我们需要把不需要变换的轴放到最前面,也就是说将 index=2,换到 index=0 的位置,然后进行 svd 操作:
同样的,现在 s 是一个(3, 80)的矩阵,还是少了一维,如果重建图像,需要将其进行填充和处理,最后将重建的图像输出:
当然,也可以选择前面的 K 个特征值对图像进行压缩:
重新构建的图像如下:
对比可以发现,虽然损失了部分精度,但是图像还是可以分辨的。
总结
图像的变化会涉及到很多线性运算,大家可以以此文为例,仔细研究。
本文已收录于 http://www.flydean.com/08-python-numpy-linear-algebra/
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
版权声明: 本文为 InfoQ 作者【程序那些事】的原创文章。
原文链接:【http://xie.infoq.cn/article/e6cb8fb11f27288bb4910a139】。文章转载请联系作者。
评论