矩阵实验
- 矩阵
- 工程应用:图像平滑
- 看待矩阵的四种视角:数据、系统、变换、空间
- 线性变换
- 工程应用:图形变化
- 矩阵变化的推导
- 总结
矩阵
在线性代数里,用的最多的概念是【矩阵】。
一个具体的矩阵:
一个抽象的矩阵:
矩阵,是把数字按照横竖排起来。
- 您看上图,前一个是 行 列 (),后一个是 行 列 ()。
来源:向量的扩展,向量是横着的一排数字,每个数字代表一个维度的分量。
- 比方说,学生的考试科目,是有
那在年纪成绩评比时,通常是按所有维度算的 ->
而评比单科王是按一个维度算的 ->
还有一些可能只是按基础算 ->
,可以用来计算和某个候选人的相似性。
每一个评比的要求都是一个向量,而又有这么多评比,所以就有了 。
这么多向量如果把它们放在一起,该怎么排列呢?
如同所示,这种把向量按照横竖排起来的摆放方式,是很自然的结果,只不过数学家给它取了一个名字:矩阵
,并且发现了一系列相应的计算
。
所以说,矩阵就是把向量按照横竖排起来的摆放方式而得来的,矩阵不是原因,而是结果,矩阵产生的原因就是向量的扩展。
作用,是将以前的单个计算
(俩个元素的加减乘除)变成了批处理
(俩个矩阵的加减乘除)。
如:
- 俩个元素之间的计算:
- 俩个矩阵之间的批处理:
正是这种计算方式,将以前的单个计算
(俩个元素的加减乘除)变成了批处理
(俩个矩阵的加减乘除)。
这种批处理的计算,与计算机搭配起来,简直是绝配 — 所以,线性代数对于我们来说,生活和工作都能用上。
运算:矩阵加法、矩阵数乘、矩阵乘法。
- 矩阵加法:,前提是俩个相加的矩阵的行列相同
- 矩阵数乘:
- 矩阵乘法:
第一个矩阵的形状是 ,第二个矩阵的形状是 ,俩俩相乘的矩阵是 ,中间的 被划掉了 ---- 因此俩个矩阵相乘需要满足一个条件,乘号前的矩阵的 列数 要等于后面矩阵的 行数。
矩阵乘法很重要吧,我在编程时经常听别人说起,况且那时候并没有学工程数学。
- 先确定生成矩阵的尺寸,乘号前的矩阵的 列数 要等于后面矩阵的 行数;
- 生成矩阵的第 行第 列的值为:前面矩阵第 行 和 后面矩阵第
矩阵乘法就
- 矩阵卷积(二维):矩阵 以某个步长在 矩阵 表面 滑动加权求和。
演示一下卷积过程,
接着矩阵 从矩阵 的 左上角 准备滑动,如下图:
黄色区域的元素相乘,得到 个 ,相加值为 。
假设设定的滑动步长为
继续滑动,对应位置相乘再求和得到 ,如下图:
继续滑动,对应位置相乘再求和得到 2,如下图:
…,最终矩阵卷积生成的矩阵,对比 矩阵
矩阵 (小矩阵),也被称为“卷积核”、“滤波器”;矩阵卷积也是卷积神经网络的原理。
工程应用:图像平滑
上面所说的矩阵卷积是二维的,因此我们以灰色图为例,彩色图是三维的。
图片是由很多
- 如果像素是 ,那像素即黑色;
- 如果像素是 ,那像素即白色;
而矩阵正好有行、列,我们可以把图片转为矩阵,通过操控矩阵来改变图片。
图片平滑:让一张清晰的图片变模糊
。
因为图片的像素值反应了一个图片的亮度,如果我们把图片中的像素值和周围的像素值相似,那整个图片的色调就差不多,也变模糊了。
而图片平滑的过程和矩阵卷积的过程是一样的,最核心的地方就是设计卷积核。
图像平滑算法:
- 设计一个卷积核,使得图像矩阵的每一个像素值尽可能的与周围的像素值接近,这张图片每部分就会差不多;
- 积核尺寸、滑动步长、周边范围等超参数设计,以需求而定;
- 需要考虑一个细节,矩阵卷积生成的矩阵会缩小一圈,图片也会变小一圈;解决方法是在矩阵A最外围补一圈零。
# 运行:在命令行输入 python 当前源文件.py
import numpy as np
from PIL import Image # 图片处理模块
from scipy import signal
# 1.读取一张图片
filename = "./demo.png"
img_rgb = Image.open(filename)
img_rgb.show()
# 2.将彩色图片转为灰度图
img_gray = img_rgb.convert('L')
img_gray.show()
# 3.将灰度图转为像素矩阵
matrix = np.asarray(img_gray)
print("matrix.shape=", matrix.shape)
# 4.定义卷积核(均值滤波器)
filter_3x3 = np.array([[ 1/9, 1/9, 1/9 ],
[ 1/9, 1/9, 1/9 ],
[ 1/9, 1/9, 1/9 ]])
print("filter_3x3=", filter_3x3.shape) # 采用的 3*3 的过滤器
print(np.around(filter_3x3, decimals=2)) # 打印图片的像素值
# 5.开始卷积(图像平滑)
result = signal.convolve2d(matrix, filter_3x3, mode='same')
print("result.shape=", result.shape)
print(np.around(result, decimals=0))
# 6.把像素矩阵转回图片
img_rlt = Image.fromarray(result)
img_rlt.show()
读取的图片 demo.png
:
简单起见,转为黑白图片(二维):
调用图像平滑算法:
有些模糊了,但 可能不太明显,可以改为
- filter_3x3 改为 filter_7x7
# 7x7的,均值是 1/49
filter_7x7 = np.ones((7,7)) / (7*7)
除此之外,卷积核还可以改进,一般采用高斯分布(在保留细节方面,图片平滑效果最好),因此也称为 “高斯滤波器”。
二维高斯分布:
在 的 矩阵
# 7x7 高斯滤波器
gaussian_filter_7x7 = np.array([ [ 0.00000067, 0.00002292, 0.00019117, 0.00038771, 0.00019117, 0.00002292, 0.00000067],
[ 0.00002292, 0.00078633, 0.00655965, 0.01330373, 0.00655965, 0.00078633, 0.00002292],
[ 0.00019117, 0.00655965, 0.05472157, 0.11098164, 0.05472157, 0.00655965, 0.00019117],
[ 0.00038771, 0.01330373, 0.11098164, 0.22508352, 0.11098164, 0.01330373, 0.00038771],
[ 0.00019117, 0.00655965, 0.05472157, 0.11098164, 0.05472157, 0.00655965, 0.00019117],
[ 0.00002292, 0.00078633, 0.00655965, 0.01330373, 0.00655965, 0.00078633, 0.00002292],
[ 0.00000067, 0.00002292, 0.00019117, 0.00038771, 0.00019117, 0.00002292, 0.00000067] ])
# 调用的时候,将 filter_3x3 改为 gaussian_filter_7x7。
除此之外,还可以实现图片的边缘检测(应用在自动驾驶的车道检测、计算机视觉基础等等)。
# 第 4 步,定义卷积核改为定义算子
sobel = np.array([[ -1, -2, -1 ],
[ 0, 0, 0 ],
[ 1, 2, 1 ]])
# 调用语句 result = signal.convolve2d(matrix, filter_3x3, mode='same')
result = signal.convolve2d(matrix, sobel, mode='same')
左边是原图,右边是效果图(边缘检测算法):
看待矩阵的四种视角:数据、系统、变换、空间
学线代时,可能比较注重具体的计算,但学完了却发现对线代的理解还是不够深刻。
一个可能的原因是,没有特别深刻的理解,我们在代数中的这些符号,比如说 矩阵,这个 矩阵
代数,是用字母代表数,但我们到底代表的是哪些数…在更加抽象的数学里,我们的代数代表的不仅仅是数,而是一个对象。
那么,代表的这个对象是什么?
这个就是我们要明确的。
看待矩阵的四种视角:
- 数据:把矩阵看成数据,行列,每一行代表一个样本,每一列代表一个特征,多用于数据科学;
- 系统:把矩阵看成线性系统(中学的多元一次方程组),那求解那些线性方程组就可以用矩阵运算,多用于计算线性代数的线性方程组;
- 变换:把矩阵看成对向量的一个函数,或者说是一种变换,因为一个矩阵和一个向量相乘,得到结果依然是向量,可以把矩阵看成输入一个向量,输出一个向量的函数,多用于图形学的图像图形的变化;
- 空间:把矩阵看成一个空间,这样看一个矩阵乘一个向量,就是向量在矩阵所表示的空间中所对应的位置是哪里,多用于线性代数的向量空间。
线性变换
矩阵可不仅仅是只能处理图片的数字表格,试着换一种角度看矩阵:变换。
- 矩阵乘法:,画在几何。
(红色) 经过 得到 另一个向量(绿色),
只不过,在线性代数里,我们称
若我们把矩阵看做一个变换,图形变换就会十分方便。
图形变换:图形的缩放、旋转、仿射等等,也用于游戏开发、动漫制作等等。
工程应用:图形变化
或许您应该有一个疑问,矩阵,是怎样实现图形变换的 ???
图形的变化:
- 图形旋转
- 图形平移
- 图形放大
- 图形缩小
- 图形翻转
- 图形剪切(正体 变斜体)
- … …
比如,这个是怎么做到的:
经过旋转:
先考虑一个小问题吧,怎么使得一个图形绕
其实,黄色的梯形是由 个点组成,经历 个点的坐标,也就是
首先,我们让 翻转,翻转后也就是 。
现在我们改为以矩阵的形式翻转:
我们需要做的就是找到一个能使其转换完成的 ,因为输入的矩阵和输出的矩阵都是同行同列(2行, 1列),根据矩阵乘法的要求,
得到一个式子:
- 令 则有:
我们确定好
- 因为 ,推出 ;
- 因为 , 推出 ;
所以,矩阵 。
可这个翻转计算只是针对 ,为了提高计算效率(批处理),我们把
矩阵
以上是图形的左右翻转(绕
图形的上下翻转(绕
线性变换,也可以实现图形的水平剪切。
剪切:把 正体字 变成 斜体字,就是一个剪切。
图形的水平剪切如上图,纵坐标不变,横坐标运动。
结合矩阵:,有一个控制系数 .
根据矩阵乘法 ,令 则有:
通过对比系数,,当 时,往右剪切;当
图形的竖直剪切如下图,纵坐标运动,横坐标不变。
变换矩阵:,注意
完整代码:
# 运行:在命令行输入 python 当前源文件.py
import numpy as np
import matplotlib.pyplot as plt
# 1.定义变换矩阵A,用于图形平移(竖直平移)
A = np.array([[1,0],[0,-1]])
# 1.定义变换矩阵A,用于图形剪切
# k = -0.8
# A = np.array([[1,0],[k,1]])
# 1.定义变换矩阵A,图形旋转
# theta = -(3.14/4)
# A = np.array([[np.cos(theta),np.sin(theta)],[-np.sin(theta),np.cos(theta)]])
# 1.定义变换矩阵A,图形整体放大 1 倍
# A = np.array([[2,0],[0,-2]])
# 1.定义变换矩阵A,图形整体缩小 0.75 倍
# A = np.array([[0.5,0],[0,0.5]])
# 2. 定义输入矩阵(即输入图形)
B = np.array([[0, 1, 1, 0, 0],[1, 1, 0, 0, 1]])
# 3. 计算输出矩阵(矩阵乘法)
Y = np.dot(A,B)
# 4. 绘制图形
plt.axis([-3,3,-3,3])
plt.axvline(x=0, color='#A9A9A9')
plt.axhline(y=0, color='#A9A9A9')
plt.grid(True)
plt.plot(B[0],B[1],'-yo',lw=2) # 绘制输入图形
plt.plot(Y[0],Y[1],'-go',lw=2) # 绘制输入图形
plt.show()
具体用法,请往下看。
图形平移:
- 竖直平移的变换矩阵是:,水平平移的变换矩阵是:。
# 1.定义变换矩阵A,用于图形平移(竖直平移)
A = np.array([[1,0],[0,-1]])
图形剪切:
- 水平剪切的变换矩阵是:,竖直剪切的变换矩阵是:, 会影响方向。
# 1.定义变换矩阵A,用于图形剪切
k = -0.8
A = np.array([[1,0],[k,1]])
图形放大:
水平放大的矩阵是:,竖直放大的变换矩阵是:
# 1.定义变换矩阵A,图形整体放大 1 倍
A = np.array([[2,0],[0,2]])
图形缩小同理。
图形旋转:
- 逆时针旋转的变换矩阵是:,顺时针旋转的变换矩阵是:。
# 1.定义变换矩阵A,图形旋转
theta = -(3.14/4)
A = np.array([[np.cos(theta),np.sin(theta)],[-np.sin(theta),np.cos(theta)]])
旋转的角度最复杂,我们可能不太清楚这个角度是怎么来的。
矩阵变化的推导
我们推导一下,图形旋转的变化过程。
推导的前置知识:高中的三角函数。
不一定要每一步都弄明白,但要知道我们可以把矩阵看成一种对向量的变换(函数),这个很重要,理解的越深刻越好。
我们看最简单的情况,如下图。
蓝色的向量旋转 度角得到红线 ,如果我们设这个变换的矩阵为 ,则有这样一个式子:
- 令 ,则有:。
因为是经过旋转得到的,因此新的坐标和原来的坐标一定是有联系的,这个联系就是角度 。
推导过程:
- 设向量(蓝色)的模为 ,由三角关系式得到:,即 ;,即 。
- 向量(红色)由于仅有旋转没有伸缩,因此红色向量的模依然是 :,即 ;,即
- ,
- ,比对系数确定
- ,一步步化简得到最后的。
- ,这个结果就是变换 矩阵
图形旋转角度就是这么推导过来的,在《数学女孩 4》的矩阵 — 线性变换一节,里面就有其TA图形变换的推导过程。
总结
第一部分,介绍了矩阵、来源、运算,工程应用是矩阵卷积,趁热打铁去搞定卷积网络吧。
第二部分,介绍了看待矩阵的四种视角,我们选的是变换,工程应用是图形图像处理。
归根结底,是函数表示变换。任意函数都是从输入到输出的变换。矩阵可以看做是向量的函数:)
这种变换,还可以扩展到三维空间,比如说电视成像、转播。
电视机成像的原理大概是,通过一把电子枪,把电子打到屏幕上:
不过对于这样的彩色图片一把电子枪是不够的:
可以把这幅图片以 红色、绿色、蓝色 为基,分为三张图片:
用三把电子枪分别把 红色、绿色、蓝色
电视转播则不同,信号不是以 红色、绿色、蓝色
不是靠三原色 传递,而是通过 、
- ,采用亮度-色差来描述颜色的颜色空间
彩色电视机背后有 、 接口,完整地插入 、
- 若是接入 ,可产生黑白图像;
- 若是再接入 、
将 转换为 、,这个过程也是矩阵函数的一个实例:
加油:)