Numpy - 用RGB图像来理解Numpy中的transpose操作

作者 Mingjiang Shi 日期 2019-07-07
Numpy - 用RGB图像来理解Numpy中的transpose操作

网上关于numpy中tranpose的解释都是在说结果是怎么计算出来的,但是np.transpose实际的意义是什么却很少有说明。本文就从RGB图片的角度来说明一下np.transpose的意义。

首先,我们生成一张2x2的RGB图片,每个像素有三个值分别是RGB的值,用numpy表示该图就有12个元素。下面是生成该图的代码:

arr = np.array([255,255,255, 255,0,0, 0,255,0, 0,0,255]).reshape(2,2,-1)

# output
array([[[255, 255, 255], # 白色块
[255, 0, 0]], # 红色块

[[ 0, 255, 0], # 绿色块
[ 0, 0, 255]]])# 蓝色块

对应的图片如下:

这个3维数组中,第0维有两个元素,分别表示图片的2行。第1维中也有两个元素,分别表示每行的2列。第二维中有3个元素,表示每个像素的RGB值。熟悉RGB图片的话,应该应该知道[255,255,255]表示白色,[255,0,0]表示红色,等。

好,以上就是相关背景。由于上述数组是3维的,因此np.transpose总共有6种可能,分别是:

  • np.transpose(arr, (0, 1, 2))
  • np.transpose(arr, (0, 2, 1))
  • np.transpose(arr, (1, 0, 2))
  • np.transpose(arr, (1, 2, 0))
  • np.transpose(arr, (2, 0, 1))
  • np.transpose(arr, (2, 1, 0))

下面我们来看看原图经过transpose以后分别是什么意思?np.transpose(arr, (0, 1, 2))就是原始数组,所以略过。

a2=np.transpose(arr, (0, 2, 1))

这里是将第1和2维(数组的维度从0开始计算)交换,因此:

  • tranpose后的数组的第0维依然表示原始图片的行。
  • tranpose后的数组的第1维数据是从原始图片中的第2维中取得,因此它获取到的是原始图片中的RGB分量,因此这个操作是将第三维中的RGB分别提取出来并组合在一起形成了第1维。
  • tranpose后的数组的第2维数据是从原始图片中的第1维中取得。

结果如下:

array([[[255, 255],  -> 255表示原始图片中白色块的R分量,255表示红色块的R分量。
[255, 0], -> 255表示原始图片中白色块的G分量,0表示红色块的G分量。
[255, 0]], -> 255表示原始图片中白色块的B分量,0表示红色块的B分量。

[[ 0, 0], -> 0表示原始图片中绿色块的R分量, 0表示蓝色块的R分量。
[255, 0], -> 255表示原始图片中绿色块的G分量,0表示蓝色块的G分量。
[ 0, 255]]])-> 0表示原始图片中绿色块的B分量, 255表示蓝色块的B分量。

a3=np.transpose(arr, (1, 0, 2))

这个操作中RGB分量的位置保持不变,只是对行列进行交换,直观上来讲就是将二维图片进行转置。转换后的图片如下,可见红绿块交换了位置:

a4=np.transpose(arr, (1, 2, 0))

这个操作三个维度都发生了变化,转换后的数组a4的

  • 第0维是从原始数组中的第1维获取数据,因此a4的第0维表示原始图片中的列
  • 第1维是从原始数组中的第2维获取数据,因此是将RGB分量分别提取出来,合并在一起形成第1维
  • 第2位是从原始数据中的第0维获取数据,因此是原始图片中的行。

结果如下:

array([[[255,   0], -> 255表示原始图片中白色块的R分量,0表示绿色块的R分量。
[255, 255], -> 255表示原始图片中白色块的G分量,255表示绿色块的G分量。
[255, 0]],-> 255表示原始图片中白色块的B分量,0表示绿色块的B分量。

[[255, 0], -> 255表示原始图片中红色块的R分量,0表示蓝色块的R分量。
[ 0, 0], -> 255表示原始图片中红色块的G分量,0表示蓝色块的G分量。
[ 0, 255]]]) -> 255表示原始图片中红色块的B分量,255表示蓝色块的B分量。

可以推演一下,上面6个数字组成的3x2的数组表示原始图片的第0列的数据。这个3x2的数组的行分别表示RGB分量,列表示原始图片中的行。

a5=np.transpose(arr, (2, 0, 1))

这个操作是将RGB分量交换到了第0维,行列关系不变

array([[[255, 255], # 分别表示4个像素的R分量
[ 0, 0]],

[[255, 0], # 分别表示4个像素的G分量
[255, 0]],

[[255, 0], # 分别表示4个像素的B分量
[ 0, 255]]])

如果我们将其excel中的sheet来理解的话,它是将RGB分别组织成了3个sheet,每个sheet中只包含RGB中的一种。每个sheet内的table就分别表示原始图像对于位置的颜色分量。

a6=np.transpose(arr, (2, 1, 0))

这个操作是将RGB分量交换到了第0维,同时行列关系交换,结果就是在上面结果的基础上对每个子数据做转置。

array([[[255,   0], # 分别表示4个像素的R分量,但是行列关系交换
[255, 0]],

[[255, 255],
[ 0, 0]],

[[255, 0],
[ 0, 255]]])

最后,试图总结一下transpose的一般理解,假设transpose的axes参数(x,y,z),那么transpose后的结果的第0维的数据就是从原始数组的第x维去取数据,它的作用就是将原始数组的x维的数据进行了分组。比如上面的(2,1,0)就是将原始图片中的RGB分量分别提取出来放到了一起。这些数据的内部组织方式就是由后面两个参数觉得的。

更一般的来讲,多维数组从低维到高维是逐渐细化数据的一个过程。RGB图片的第0维是按行来组织数据,然后再按列来组织数据,然后是按RGB分量来组织数据。transpose是调整了组织数据的次序。

这个transpose操作不是很好理解,我只是将我的思考记录下来,可能我也没有表达清楚。如果说我希望你能从本文得到什么的话,就是要从数组的实际意义中去理解tranpose后的结果,这样会比从纯数学上去理解会容易一些。