Reputation: 75
Numpy's rot90 function promises to rotate a 2d or higher array by 90 degrees, taking an axes parameter. The method:
numpy.rot90(m, k=1, axes=(0, 1))[source]
Rotate an array by 90 degrees in the plane specified by axes.
Rotation direction is from the first towards the second axis.
I'm very confused about the axes part. An object can be rotated around the x, y, or z axis. Typically, this is defined by something such as a Vector3f, with 3 floats defining the axis value (ex, (0, 0, 1) to rotate around z axis.) I do not understand how these two numbers can be used to rotate a 3d object, shouldn't it be 3 like a Vector3f? Can anyone help me understand what these two axes mean, and what two numbers would be used for, respectively, rotation around the x, y, and z axis? I've tried many different combinations of numbers and they all have various results (I can't put in two of the same numbers), but I have no idea how it's possible to have enough information with two numbers (k represents amount of times to rotate.)
Upvotes: 5
Views: 3305
Reputation: 231335
I like to work with a sample array with distinct values and dimensions, such as np.arange(24).reshape(2,3,4)
.
In this case I also looked at the code. After some preliminaries to make sure axes
and k
are right it does different things depending on the 4 possible values of k
.
axes
define a "plane". With a 3d array, axes=(0,1)
can be thought of as rotation about the third axes (2), imagining a "vector" perpendicular to that "plane". But it's these axes values that used in the code. While I suspect we could construct equivalent operations with trig based rotation matrices, this code does not do any calculations. (Note that integers are not changed to floats.)
k=0
changes nothing:
In [104]: np.rot90(m,k=0, axes=(0,1))
Out[104]:
array([[[ 0, 1, 2, 3], # shape (2,3,4)
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
k=1
involves a flip followed by a transpose
In [105]: np.rot90(m,k=1, axes=(0,1))
Out[105]:
array([[[ 8, 9, 10, 11], # shape (3,2,4)
[20, 21, 22, 23]],
[[ 4, 5, 6, 7],
[16, 17, 18, 19]],
[[ 0, 1, 2, 3],
[12, 13, 14, 15]]])
k=2
is simpler - just a flip on both axes. This is easy to visualize. Last dimension is unchanged (across rows), but planes and rows are reversed:
In [106]: np.rot90(m,k=2, axes=(0,1))
Out[106]:
array([[[20, 21, 22, 23],
[16, 17, 18, 19],
[12, 13, 14, 15]],
[[ 8, 9, 10, 11],
[ 4, 5, 6, 7],
[ 0, 1, 2, 3]]])
k=3
does the flip first, then the transpose
In [107]: np.rot90(m,k=3, axes=(0,1))
Out[107]:
array([[[12, 13, 14, 15], # again (3,2,4)
[ 0, 1, 2, 3]],
[[16, 17, 18, 19],
[ 4, 5, 6, 7]],
[[20, 21, 22, 23],
[ 8, 9, 10, 11]]])
Looking at the strides:
In [111]: m.strides
Out[111]: (96, 32, 8)
In [112]: np.rot90(m,k=2, axes=(0,1)).strides
Out[112]: (-96, -32, 8) # the double flip
The transpose switches the order, while the flip again changes the sign:
In [113]: np.rot90(m,k=1, axes=(0,1)).strides
Out[113]: (-32, 96, 8)
In [114]: np.rot90(m,k=3, axes=(0,1)).strides
Out[114]: (32, -96, 8)
Because it just uses flip
and transpose
the result is a view
.
It may be easier to visualize in an array that represents values in one plane, a (3,4) array:
In [120]: m = np.arange(12).reshape(1,3,4)
In [121]: m
Out[121]:
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]]])
In [122]: np.rot90(m,k=2, axes=(1,2))
Out[122]:
array([[[11, 10, 9, 8],
[ 7, 6, 5, 4],
[ 3, 2, 1, 0]]])
In [123]: np.rot90(m,k=1, axes=(1,2)) # visualize a counterclockwise rotation
Out[123]:
array([[[ 3, 7, 11],
[ 2, 6, 10],
[ 1, 5, 9],
[ 0, 4, 8]]])
In [124]: np.rot90(m,k=3, axes=(1,2)) # clockwise
Out[124]:
array([[[ 8, 4, 0],
[ 9, 5, 1],
[10, 6, 2],
[11, 7, 3]]])
k=3
can also be visualized as successive counterclockwise rotations through 1 and 2.
Upvotes: 4