python旋转矩阵90°_NumPy矩阵的旋转

13. NumPy矩阵的旋转

在用Python的数字图像处理、CNN或者深度学习里,对图像的处理:形变(缩放)处理常将图像数据读取到NumPy的array数据里,然后对图像数据进行形变处理。NumPy提供了很多的对array数组的操作:tile、rot90等。本章除了了解rot90的基本使用外,自己也想写点程序实现旋转的功能。

13.1 rot90函数实现矩阵旋转

从NumPy的官方完整查到rot90函数语法格式如下:

rot90(m, k=1, axes=(0, 1)

m是要旋转的数组(矩阵),k是旋转的次数,默认旋转1次,那是顺时针还是逆时针呢?正数表示逆时针,而k为负数时则是对数组进行顺时针方向的旋转。

import numpy as np

mat = np.array([[1,3,5],

[2,4,6],

[7,8,9]

])

print mat, "# orignal"

mat90 = np.rot90(mat, 1)

print mat90, "# rorate 90 anti-clockwise"

mat90 = np.rot90(mat, -1)

print mat90, "# rorate 90 clockwise"

mat180 = np.rot90(mat, 2)

print mat180, "# rorate 180 anti-clockwise"

mat270 = np.rot90(mat, 3)

print mat270, "# rorate 270 anti-clockwise"

执行结果:

[[1 3 5]

[2 4 6]

[7 8 9]] # orignal

[[5 6 9]

[3 4 8]

[1 2 7]] # rorate 90 anti-clockwise

[[7 2 1]

[8 4 3]

[9 6 5]] # rorate 90 clockwise

[[9 8 7]

[6 4 2]

[5 3 1]] # rorate 180 anti-clockwise

[[7 2 1]

[8 4 3]

[9 6 5]] # rorate 270 anti-clockwise

可见逆时针旋转$270^{\ \circ}$等价于顺时针旋转$90^{\ \circ}$。

13.2 Python实现方阵的旋转

下面自己编写旋转功能。根据矩阵理论,

$\bigotimes\ $对方阵$A_{n \times n}$左乘一个负对角线上均是1、其余都是0的方阵(记作:$E^{-1}$)实现方阵$A_{n \times n}$的行的互换。

$\bigotimes\ $对方阵$A_{n \times n}$右乘一个负对角线上均是1、其余都是0的方阵而实现对方阵$A_{n \times n}$的列的互换。

$\bigotimes\ $对方阵$A_{n \times n}$的转置$A_{n\times n}^{T}$左乘一个负对角线上均是1、其余都是0的方阵$A_{n \times n}$实现向左(逆时针)90$^{\ \circ}$旋转。

$\bigotimes\ $对方阵$A_{n \times n}$的转置$A_{n\times n}^{T}$右乘一个负对角线上均是1、其余都是0的方阵$A_{n \times n}$实现向右(顺时针)90$^{\ \circ}$旋转。

$\bigotimes\ $对方阵$A_{n \times n}$左右各乘一个负对角线上均是1、其余都是0的方阵而实现对方阵$A_{n \times n}$的180$^{\ \circ}$旋转。

显然要想自己实现对方阵的旋转,得先有一个负对角线上都是1的方阵$E^{-1}$,NumPy里没有这样的函数能直接生成$E^{-1}$,但提供了eye函数(矩阵形状为$n \times m$且主对角线上是1,A$_{i,i } = 1$)和identity函数(方阵$n\times n$的)均可创建主对角线上为1,其余为0的矩阵。可以基于eye或者identity函数产生的结果进行变化得到负对角线上都是1的$E^{-1}$方阵。

import numpy as np

print np.eye(4,5)

print np.eye(5,3)

print np.identity(4)

13.2.1 创建负对角线为1的方阵

$\circ$那么如何得到负对角线上是1而其余为0的矩阵呢?

可以利用numpy的eye、identity函数产生主对角线全一的方阵,然后利用矩阵切片来得到负对角线上都是1的方阵$E^{-1}$。

import numpy as np

print np.eye(4,5)[:,::-1]

print np.eye(5,3)[:,::-1]

print np.identity(4)[:,::-1]

这样负对角线上是1的矩阵就创建好了。为了后续论述方便,这里将负对角线上都是1,其余为0的方阵符号计为$E^{-1}$。

13.2.2 方阵的行交换

如果想对一个方阵$A_{n \times n}$实现行交换,可以对方阵$A_{n \times n}$左乘一个$E^{-1}$,即可实现上下互换。如果要讨论意义的话,可以以图片A为例,行交换图片的数据,得到的新图片是原图的垂直镜像,或人和其水中倒影的关系。

$$

A_\updownarrow = E_{n\times n}^{-1}A_{n \times n}

$$

import numpy as np

a = np.array([[3,3,2,1],

[0,0,1,5],

[3,1,2,0],

[5,3,1,0]])

e_1 = np.identity(a.shape[0], dtype=np.int8)[:,::-1]

print a,"# a"

a_rows = e_1.dot(a)

print a_rows, "# rows"

print e_1, "# e_1"

程序执行结果:

[[3 3 2 1]

[0 0 1 5]

[3 1 2 0]

[5 3 1 0]] # a

[[5 3 1 0]

[3 1 2 0]

[0 0 1 5]

[3 3 2 1]] # rows

[[0 0 0 1]

[0 0 1 0]

[0 1 0 0]

[1 0 0 0]] # e_1

13.2.3 方阵的列交换

如果想对一个方阵$A_{n \times n}$实现列交换,可以对方阵$A_{n \times n}$右乘一个$E^{-1}$,即可实现上下互换。如果要通俗其意义的话,类似于站在镜子前的人和镜子里的影子一样,水平镜像关系。

$$

A_\leftrightarrow = A_{n \times n}E_{n\times n}^{-1}

$$

import numpy as np

a = np.array([[3,3,2,1],

[0,0,1,5],

[3,1,2,0],

[5,3,1,0]])

e_1 = np.identity(a.shape[0], dtype=np.int8)[:,::-1]

print a,"# a"

a_rows = a.dot(e_1)

print a_rows, "# columns"

print e_1, "#e_1"

程序执行结果:

[[3 3 2 1]

[0 0 1 5]

[3 1 2 0]

[5 3 1 0]] # a

[[1 2 3 3]

[5 1 0 0]

[0 2 1 3]

[0 1 3 5]] # columns

[[0 0 0 1]

[0 0 1 0]

[0 1 0 0]

[1 0 0 0]] # e_1

13.2.4 方阵逆时针旋转90度

如果想对一个方阵$A_{n \times n}$实现逆时针旋转90度,可以对方阵$A_{n \times n}$的转置$A_{n \times n}^{T}$左乘一个$E^{-1}$,即可实现对方阵$A_{n \times n}$的逆时针旋转90度。

$$

A_{\curvearrowleft} = E_{n\times n}^{-1}A_{n \times n}^{T}

$$

import numpy as np

a = np.array([[3,3,2,1],

[0,0,1,5],

[3,1,2,0],

[5,3,1,0]])

e_1 = np.identity(a.shape[0], dtype=np.int8)[:,::-1]

print a,"# a"

a_left90 = e_1.dot(a.T)

print a_left90, "# anti-clockwise 90"

print np.rot90(a), "# anti-clockwise 90"

print e_1, "#e_1"

执行结果:

[[3 3 2 1]

[0 0 1 5]

[3 1 2 0]

[5 3 1 0]] # a

[[1 5 0 0]

[2 1 2 1]

[3 0 1 3]

[3 0 3 5]] # anti-clockwise 90

[[1 5 0 0]

[2 1 2 1]

[3 0 1 3]

[3 0 3 5]] # anti-clockwise 90

[[0 0 0 1]

[0 0 1 0]

[0 1 0 0]

[1 0 0 0]] # e_1

13.2.5 方阵顺时针旋转90度

如果想对方阵$A_{n \times n}$实现顺时针旋转90度,可以对方阵$A_{n \times n}$的转置$A_{n \times n}^{T}$右乘一个$E^{-1}$,即可实现对$A_{n \times n}$的顺时针旋转90度变换。

$$

A_{\curvearrowright} = A_{n \times n}^{T}E_{n\times n}^{-1}

$$

import numpy as np

a = np.array([[3,3,2,1],

[0,0,1,5],

[3,1,2,0],

[5,3,1,0]])

e_1 = np.identity(a.shape[0], dtype=np.int8)[:,::-1]

print a,"# a"

a_right90 = (a.T).dot(e_1)

print a_right90, "# clockwise 90"

print np.rot90(a, -1), "# clockwise 90"

print e_1, "# e_1"

执行结果:

[[3 3 2 1]

[0 0 1 5]

[3 1 2 0]

[5 3 1 0]] # a

[[5 3 0 3]

[3 1 0 3]

[1 2 1 2]

[0 0 5 1]] # clockwise 90

[[5 3 0 3]

[3 1 0 3]

[1 2 1 2]

[0 0 5 1]] # clockwise 90

[[0 0 0 1]

[0 0 1 0]

[0 1 0 0]

[1 0 0 0]] # e_1

13.2.6 方阵旋转180度

如果想对方阵$A_{n \times n}$实现旋转180度变换,可以对方阵$A_{n \times n}$左右各乘一个$E^{-1}$,即可实现对方阵$A_{n \times n}$旋转180度的变换。

$$

A_{\circlearrowleft} = E_{n\times n}^{-1}A_{n \times n}E_{n\times n}^{-1}

$$

import numpy as np

a = np.array([[3,3,2,1],

[0,0,1,5],

[3,1,2,0],

[5,3,1,0]])

e_1 = np.identity(a.shape[0], dtype=np.int8)[:,::-1]

print a,"# a"

a_rorate90 = e_1.dot(a).dot(e_1)

print a_rorate90, "# rorate 180"

print np.rot90(a, 2), "# rorate 180"

print e_1, "# e_1"

执行结果:

[[3 3 2 1]

[0 0 1 5]

[3 1 2 0]

[5 3 1 0]] # a

[[0 1 3 5]

[0 2 1 3]

[5 1 0 0]

[1 2 3 3]] # rorate 180

[[0 1 3 5]

[0 2 1 3]

[5 1 0 0]

[1 2 3 3]] # rorate 180

[[0 0 0 1]

[0 0 1 0]

[0 1 0 0]

[1 0 0 0]] # e_1

13.2.7 负对角线镜像

方阵$A_{n\times n}$主对角的镜像,是方阵$A_{n\times n}$的转置$A_{n\times n}^{T}$。那么,方阵$A_{n\times n}$关于负对角线的镜像$A_{n\times n}^{-T} $是什么样子?怎样得到?

$$

A_{n\times n}^{-T} = E_{n\times n}^{-1}A_{n \times n}^{T}E_{n\times n}^{-1}

$$

即对方阵$A_{n \times n}$的转置$A^{T}$左右各乘一个$E^{-1}$得到方阵$A_{n\times n}$关于负对角线的镜像。

import numpy as np

a = np.array([[3,3,2,1],

[0,0,1,5],

[3,1,2,0],

[5,3,1,0]])

e_1 = np.identity(a.shape[0], dtype=np.int8)[:,::-1]

print a,"# a"

print a.T, "# a.T"

a_mirror = e_1.dot(a.T).dot(e_1)

print a_mirror, "# mirror E-1"

print e_1, "# e_1"

执行结果:

[[3 3 2 1]

[0 0 1 5]

[3 1 2 0]

[5 3 1 0]] # a

[[3 0 3 5]

[3 0 1 3]

[2 1 2 1]

[1 5 0 0]] # a.T

[[0 0 5 1]

[1 2 1 2]

[3 1 0 3]

[5 3 0 3]] # mirror E-1

[[0 0 0 1]

[0 0 1 0]

[0 1 0 0]

[1 0 0 0]] # e_1

13.3 Python实现矩阵的旋转

以上展示的是对方阵$A_{n\times n}$的旋转处理,那么对于一般的矩阵$A_{m\times n}$怎么旋转呢?这里可以先将矩阵$A_{m\times n}$扩展成一个方阵$A_{n\times n}^{'}$(假设$n \geq m$,0填充),然后根据旋转的角度左或者右乘$E^{-1}$,得到方阵$A_{n\times n}^{'}$的旋转结果,最后通过切片技术切出方阵$A_{n\times n}^{'}$的$n \times m$的这部分数据即是矩阵$A_{m\times n}$的旋转结果。研究这个的意义可以理解如何对一张$1024\times 768$的图片进行90度旋转变化得到$768 \times 1024$的图。

$\circ\ $下面以对$A_{n\times m}$ 矩阵逆时针选择90度为例(假设$n \geq m$,0填充):

$$

A_{m\times n} \Longrightarrow A_{n\times n}^{'} \Longrightarrow E^{-1}A_{n\times n}^{'} \Longrightarrow A_{n\times n}^{'}[:n,:m] \Longrightarrow A_{n\times m \curvearrowleft}

$$

程序如下:

#coding:utf-8

import numpy as np

a = np.array([[1,2,8],[3,4, 9]])

print a, "# orignal"

# 获得a的行和列数

r, c = a.shape

#print n, r, c

zs = np.zeros((max(a.shape) - min(a.shape), max(a.shape)))

#print zs

# 0填充,将a变成一个方阵

a_1 = np.vstack([a, zs])

#print a_1

# 构建一个负对角线上均是1,其余为0的方阵

e_1 = np.identity(max(a.shape), dtype=np.int8)[:,::-1]

#print e_1

# 逆时针旋转90度

a_1_left90 = e_1.dot(a_1.T)

#print a_1_left9

# 切片切出rxc的矩阵a的左旋90度的结果

print a_1_left90[:c,:r], "# anti-clockwise 90"

执行结果:

[[1 2 8]

[3 4 9]] # orignal

[[8. 9.]

[2. 4.]

[1. 3.]] # anti-clockwise 90

13.4 矩阵旋转的意义

本章主要介绍的是矩阵的旋转,用处很大,后续图像处理有形变问题,例如图片的镜像、旋转。会用到这部分知识。

你可能感兴趣的:(python旋转矩阵90°)