Reputation: 61485
I'm trying to understand a single 90 degree rotation of a 3D numpy array and find it very hard to visualize (and thus to understand the rotation process itself).
For a 2D case, it seems to be easy to do so. As an example, consider the below snippet of code which does a 90 degree anti-clockwise rotation to the 2D array:
In [222]: m = np.arange(6).reshape((2,3))
In [223]: m
Out[223]:
array([[0, 1, 2],
[3, 4, 5]])
90° transformation for a 2D array
<--------\
array([[0, 1, 2],\ # anti-clockwise
[3, 4, 5]])\ # rotation
\
||
In [224]: np.rot90(m)
Out[224]:
array([[2, 5],
[1, 4],
[0, 3]])
But things get complicated for 3D and higher dimensional arrays. Again, as an example, let's consider a simple 3D array:
In [219]: m = np.arange(12).reshape((2,2,3))
In [220]: m
Out[220]:
array([[[ 0, 1, 2],
[ 3, 4, 5]],
[[ 6, 7, 8],
[ 9, 10, 11]]])
In [221]: np.rot90(m)
Out[221]:
array([[[ 3, 4, 5],
[ 9, 10, 11]],
[[ 0, 1, 2],
[ 6, 7, 8]]])
Looking at the above output, I couldn't make much sense out of about how the rotation does what it does to the array. Is there a streamlined process to understand such a transformation? I also looked at the shape and it's pretty much the same, which makes it even more harder to understand.
In [227]: np.rot90(m).shape
Out[227]: (2, 2, 3)
I'm specifically interested in understanding this transformation since it always returns a new "view" of the original array buffer, which would be very useful for writing performant code both in terms of memory and time. Please do share if you have any thoughts regarding this!
Upvotes: 1
Views: 1271
Reputation: 231665
Expressing your 2d case in terms of transpose and flip:
In [182]: m = np.arange(6).reshape((2,3))
In [183]: m
Out[183]:
array([[0, 1, 2],
[3, 4, 5]])
In [184]: m.transpose(1,0)
Out[184]:
array([[0, 3],
[1, 4],
[2, 5]])
In [185]: m.transpose(1,0)[::-1, :]
Out[185]:
array([[2, 5],
[1, 4],
[0, 3]])
In the 3d case, it appears to do the same thing - with the 3rd axis tagging along:
In [188]: m.transpose(1,0,2)[::-1, :]
Out[188]:
array([[[ 3, 4, 5],
[ 9, 10, 11]],
[[ 0, 1, 2],
[ 6, 7, 8]]])
If I specify the 2nd pair of axes, it does the same thing, but with the 1st going along for the ride:
In [189]: np.rot90(m, axes=(1,2))
Out[189]:
array([[[ 2, 5],
[ 1, 4],
[ 0, 3]],
[[ 8, 11],
[ 7, 10],
[ 6, 9]]])
In [190]: _.shape
Out[190]: (2, 3, 2)
In [191]: m.transpose(0,2,1)[:,::-1, :]
Out[191]:
array([[[ 2, 5],
[ 1, 4],
[ 0, 3]],
[[ 8, 11],
[ 7, 10],
[ 6, 9]]])
Different k
requires different strategies. For example with 2 I bet it just does a flip.
===
The Out[188]
display doesn't help us visualize the rotation because it involves the 1st dimension planes, and 2nd dimension rows. But if we pick a 3rd dimension column, and compare the original and rotation, we can see the same 2d rotation:
In [192]: m[:,:,0]
Out[192]:
array([[0, 3],
[6, 9]])
In [193]: Out[188][:,:,0]
Out[193]:
array([[3, 9],
[0, 6]])
A 3d array doesn't always represent a 3d rectangular prism. It could instead be a 2d image with 3 color channels. This m
rotation then rotates the image without altering the colors. The default 'plane/row/column' display doesn't help us visualize such an image.
Upvotes: 1