よちよちpython

独習 python/Qpython/Pydroid3/termux/Linux

Numpyで配列要素の位置を移動させる時のメモ

配列要素の位置の並び替え遊び


配列をつくって、要素の場所を並び替えて遊びます。

二次元配列の要素位置の移動


適当に3×3の行列を作ります。

import numpy as np

# Numpy配列の生成
a = np.arange(1,10).reshape(3,3)
a
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

これを元にします。この数字の並びを覚えておきます。

二次元配列の行の入れ替え


元の行列aをa[[0,1,2], : ]のようにスライスで表すことができますが、リスト内のインデックス番号を入れ替えると行が場所移動する。

print("元の配列\n", a)
# 1行目と3行目を入れ替えるなら
print("\n1行目と3行目の入れ替え\n", a[[2,1,0], : ])
元の配列
 [[1 2 3]
 [4 5 6]
 [7 8 9]]

1行目と3行目の入れ替え
 [[7 8 9]
 [4 5 6]
 [1 2 3]]

一番上と一番下が入れ替わりました。

次は列を入れ替えてみます。

print("元の配列\n", a)
# 列を入れ替えるならこんな感じ
print("\n列を1,2,0で入れ替え\n", a[ : , [1,2,0]])
元の配列
 [[1 2 3]
 [4 5 6]
 [7 8 9]]

列を1,2,0で入れ替え
 [[2 3 1]
 [5 6 4]
 [8 9 7]]

二次元配列の上下反転


スライスで行を逆順に並び替え。ついでに時間を測っときます。

%%time
print("元の配列\n", a)
# 行を逆から
print("\n行で逆順\n", a[::-1])
元の配列
 [[1 2 3]
 [4 5 6]
 [7 8 9]]

行で逆順
 [[7 8 9]
 [4 5 6]
 [1 2 3]]
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 1.8 ms

これと同じことを、Numpyの関数flipud(配列)を使ってできる。
udはupとdownの頭文字らしい。
引数の配列はndarrayじゃなくて単なるリストとかでもOK

%%time
print("元の配列\n", a)
print("\n上下逆順\n", np.flipud(a))
元の配列
 [[1 2 3]
 [4 5 6]
 [7 8 9]]

上下逆順
 [[7 8 9]
 [4 5 6]
 [1 2 3]]
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 2.11 ms



リストでやっとこ。

%%time
lst = [[1,2,3],
       [4,5,6],
       [7,8,9]
]

print("元の配列\n", lst)
print("配列の型", type(lst))
print("\n変形後の配列\n", lst[::-1])
元の配列
 [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
配列の型 <class 'list'>

変形後の配列
 [[7, 8, 9], [4, 5, 6], [1, 2, 3]]
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 1.17 ms



リストをflipud()で上下反転させる。

%%time
print("元のリスト型二次元配列\n", lst)
print("\nリストを上下反転\n", np.flipud(lst))
元のリスト型二次元配列
 [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

リストを上下反転
 [[7 8 9]
 [4 5 6]
 [1 2 3]]
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 1.47 ms



リストをndarrayに変換してnp.flipud()で上下反転させる。

%%time
print("元のリスト型二次元配列\n", lst)
print("\nリストをndarrayに変換\n", np.array(lst))
print("\nndarrayを上下反転\n", np.flipud(np.array(lst)))
元のリスト型二次元配列
 [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

リストをndarrayに変換
 [[1 2 3]
 [4 5 6]
 [7 8 9]]

ndarrayを上下反転
 [[7 8 9]
 [4 5 6]
 [1 2 3]]
CPU times: user 0 ns, sys: 10 ms, total: 10 ms
Wall time: 2.81 ms

時間の単位

  • msはミリセカンド、1/1000秒。
  • μsはマイクロセカンド、msの更に1/1000。

処理時間を比較する為に、上下逆順を次の3パターンでやってみたところ(出力省略)、

  • ndarrayをスライス : 63.7μs=0.063ms
  • ndarrayをflipud() : 127μs=0.127ms
  • リストをflipud() : 1.3ms

リストでやるとndarrayのスライスより桁が2つも違うほど遅い。



「Numpy配列にしただけで全然早い !」
ということで。



二次元配列の左右反転


今度は左右を反転させる。
まずはスライスで。

%%time
# 二次元目(列)を逆から並び替え
a[ : , ::-1]
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 23.6 µs





array([[3, 2, 1],
       [6, 5, 4],
       [9, 8, 7]])

今度は同じ事をNumpyの関数np.fliplr(配列)で行います。
flipud()は上下逆順でしたが、これを使うと、leftright方向つまり左右方向に逆順で列を並び替える。

%%time
# 左右反転
np.fliplr(a)
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 45.3 µs





array([[3, 2, 1],
       [6, 5, 4],
       [9, 8, 7]])

これも関数よりスライスを使う方法が倍早い。

上下反転させてから左右反転


上下反転から左右反転と、左右反転させて上下反転させた形は、順序は違うが同じ形になる。

# 上下反転させたものを左右反転
np.fliplr(np.flipud(a))
array([[9, 8, 7],
       [6, 5, 4],
       [3, 2, 1]])
# 左右反転して上下反転
np.flipud(np.fliplr(a))
array([[9, 8, 7],
       [6, 5, 4],
       [3, 2, 1]])

二次元配列の回転


np.rot90(配列, 指定回数)を使うと配列を回転させることができる。
多次元でもできるが、二次元の行列を見ていく。
指定回数が1毎に左回り(反時計回り)に90度回転する。2を指定で180度、3なら270度、4なら元通り。
マイナスをつけると右回りに90度回転、という具合。

配列を左回り(反時計回り)に90度。

print("元の行列\n", a)
print("\n90度左回転\n", np.rot90(a, 1))
元の行列
 [[1 2 3]
 [4 5 6]
 [7 8 9]]

90度左回転
 [[3 6 9]
 [2 5 8]
 [1 4 7]]

左回りに90度回転してるのが分かります。

ちなみに、元の行列を転置して上下逆順に並び替えればこの形になる。試してみる。

print("元の行列\n", a)
# 転置して上下逆順
print("\n転置して上下逆順\n", a.T[::-1])
# 90度左回転
print("\n元の行列を90度左回転\n", np.rot90(a, 1))
元の行列
 [[1 2 3]
 [4 5 6]
 [7 8 9]]

転置して上下逆順
 [[3 6 9]
 [2 5 8]
 [1 4 7]]

元の行列を90度左回転
 [[3 6 9]
 [2 5 8]
 [1 4 7]]

下2つが同じ形になりました。(転置とは二次元の場合は行と列を入れ替える操作です。)

180度回転も見ておこう。

print("元の行列\n",a)
# 左90度回転を2回
print("\n元の行列を180度回転\n", np.rot90(a, 2))
元の行列
 [[1 2 3]
 [4 5 6]
 [7 8 9]]

元の行列を180度回転
 [[9 8 7]
 [6 5 4]
 [3 2 1]]

上の行列をよく見ると、[9,8,7,6,5,4,3,2,1]をreshape(3,3)で3行3列に変形したものともおなじ形じゃないですか?
という事は、

  • 元の行列a=[[1,2,3],[4,5,6],[7,8,9]]
  • ナントカ行1列に変形し
  • スライスで逆順に並び替え
  • 3行3列に変形

させれば良さそうです。

a.reshape(-1, 1)[::-1].reshape(3, 3)
array([[9, 8, 7],
       [6, 5, 4],
       [3, 2, 1]])

ちゃんと180度回転した行列と同じ形になってますね。
先ほど上でやった、上下と左右の反転重ね技もこの形。



正方行列以外を回転させるとどんな風になるかを見ておこう。適当に行列作ってrot90()で回します。

# 2行5列を生成と表示
a_2_5 = np.arange(10).reshape(2, 5)
print("回転前\n",a_2_5)

# 90度回転を表示
print("\n90度左回転後\n",np.rot90(a_2_5, 1))
回転前
 [[0 1 2 3 4]
 [5 6 7 8 9]]

90度左回転後
 [[4 9]
 [3 8]
 [2 7]
 [1 6]
 [0 5]]

今度は180度回転。回転の向きは左でも右でも同じ。

# 2行5列を生成と表示
a_2_5 = np.arange(10).reshape(2, 5)
print("回転前\n",a_2_5)

# 180度左回転を表示
print("\n180度回転後\n",np.rot90(a_2_5, 2))
回転前
 [[0 1 2 3 4]
 [5 6 7 8 9]]

180度回転後
 [[9 8 7 6 5]
 [4 3 2 1 0]]

やはり180度回転させると、9,8,7,6,5,4,3,2,1,0になって、元の逆順に並ぶ。shapeは同じ。

  • 生成した元の配列を
  • ナントカ行1列に変形し
  • 逆順にし
  • 元の行列の形状と同じ形に変形

したものになってますかね。スライスで行います。

a_2_5.reshape(-1, 1)[::-1].reshape(2, 5)
array([[9, 8, 7, 6, 5],
       [4, 3, 2, 1, 0]])



これまで二次元配列でやってきましたが、画像をNumpy配列に変換すると、色チャンネルの情報がついている為に次元が増えて三次元配列になります。
三次元目は色の情報としてRGBやRGBAに対応する値の配列が要素数3つまたは4つで入っており、5以上になることはない。

画像を回転させるなどの為に配列を回転させてる訳ですが、多次元配列の形状をいじる際はあとで画像に戻すことを考慮して変形させないと「三次元目の要素数が多すぎなんですけど?」みたいなエラーが出る。特に次で見る転置をさせる場合だとかは要注意です。



転置


転置は配列の次元の軸を入れ替えます。配列.Tを使う。使うのは簡単。だが注意が必要です。

  • 二次元の転置 : 行(0軸)と列(1軸)を入れ替え

  • 三次元の転置 : 0軸と2軸を入れ替え

  • 多次元の転置 : 軸の順序が逆順で入れ替え

二次元配列の転置


二次元配列を転置させると行と列が入れ替わります。

# 元の行列を表示(二次元)
print("元の行列\n",a)

# 転置(行と列の入れ替え)
print("\n転置後\n",a.T)
元の行列
 [[1 2 3]
 [4 5 6]
 [7 8 9]]

転置後
 [[1 4 7]
 [2 5 8]
 [3 6 9]]

二次元の転置は、左上から右下に流れる対角線を回転軸にして、平面をクルリンパと回したような形に入れ替わる。
上の例では[1,5,9]の場所は変化していません。

転置後って、元の行列を左回りに90度回転したものを上下で逆順させた形と等しいっぽくない?
確認してみる。

# 二次元配列の転置実験

print("元の行列\n",a)
print("\n元を90度回転\n",np.rot90(a,1))
print("\n元を90度回転させ上下逆順\n",np.rot90(a,1)[::-1])
print("\n元を転置\n",a.T)
元の行列
 [[1 2 3]
 [4 5 6]
 [7 8 9]]

元を90度回転
 [[3 6 9]
 [2 5 8]
 [1 4 7]]

元を90度回転させ上下逆順
 [[1 4 7]
 [2 5 8]
 [3 6 9]]

元を転置
 [[1 4 7]
 [2 5 8]
 [3 6 9]]

ちゃんと上の転置行列と同じ形になってますね。
別の形の二次元配列もやってみよう。面倒くさいんで関数作ってからやります。



実験用の自作関数定義(二次元用)

# 二次元配列の転置実験用関数の定義

def tenchi(array):
    print("元の行列\n",array)
    print("\n元を90度回転\n",np.rot90(array,1))
    print("\n元を90度回転させ上下逆順\n",np.rot90(array,1)[::-1])
    print("\n元を転置\n",array.T)



二次元配列生成 サンプル1
(3行4列)

# 二次元配列サンプル1生成
array_sample1 = np.arange(12).reshape(3,4)



配列サンプル1を自作関数に代入

# 自作関数に代入(サンプル1)
tenchi(array_sample1)
元の行列
 [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

元を90度回転
 [[ 3  7 11]
 [ 2  6 10]
 [ 1  5  9]
 [ 0  4  8]]

元を90度回転させ上下逆順
 [[ 0  4  8]
 [ 1  5  9]
 [ 2  6 10]
 [ 3  7 11]]

元を転置
 [[ 0  4  8]
 [ 1  5  9]
 [ 2  6 10]
 [ 3  7 11]]

同じになってます。

サンプル2
(5行3列)

# 二次元配列生成 サンプル2
array_sample2 = np.arange(15).reshape(5,3)

# 自作関数に代入
tenchi(array_sample2)
元の行列
 [[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]
 [12 13 14]]

元を90度回転
 [[ 2  5  8 11 14]
 [ 1  4  7 10 13]
 [ 0  3  6  9 12]]

元を90度回転させ上下逆順
 [[ 0  3  6  9 12]
 [ 1  4  7 10 13]
 [ 2  5  8 11 14]]

元を転置
 [[ 0  3  6  9 12]
 [ 1  4  7 10 13]
 [ 2  5  8 11 14]]

90度回転して上下反転させると、元の行列の転置と等しくなっているっぽいことが分かった所で、次元を増やしてみますか。

三次元配列の変形


まずは三次元配列ってどんな風に表示されるかを見ておこう。
画像を配列化した形状は(150,120,4)みたいな感じになっているので真似します。
数値を減らして(5,2,4)で行きましょ。

# 三次元配列生成
array_3d = np.arange(40).reshape(5,2,4)
# 表示
array_3d
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]],

       [[16, 17, 18, 19],
        [20, 21, 22, 23]],

       [[24, 25, 26, 27],
        [28, 29, 30, 31]],

       [[32, 33, 34, 35],
        [36, 37, 38, 39]]])

2行4列が5個のカタマリで出来ているように見える。

  1. 一次元配列を作ると横にx個並ぶ。1個行ができる。
  2. 二次元配列にすると縦にy個行が並ぶ。
  3. 三次元配列にすると、高さにz個のx-y行列が並ぶ。

三次元配列を3次元座標的にみるなら、配列形状(5,2,4)は(z,y,x)の順番で軸になっているという事のようだ。



三次元配列の転置は0軸と2軸の交換だそうです。
先に転置後の形状を見ておこう。

# 元の三次元配列の形状
print("元の形状",array_3d.shape)
# 転置後の形状
print("転置後の形状",array_3d.T.shape)
元の形状 (5, 2, 4)
転置後の形状 (4, 2, 5)

もしこんな配列を画像に変換しようとしたら多分エラーがでますね。色チャンネルは5個もパラメータ無いんで。

生の配列を見比べる。

# 元の三次元配列
print("元の配列\n",array_3d)
# 転置後の形状
print("\n転置後の形状\n",array_3d.T)
元の配列
 [[[ 0  1  2  3]
  [ 4  5  6  7]]

 [[ 8  9 10 11]
  [12 13 14 15]]

 [[16 17 18 19]
  [20 21 22 23]]

 [[24 25 26 27]
  [28 29 30 31]]

 [[32 33 34 35]
  [36 37 38 39]]]

転置後の形状
 [[[ 0  8 16 24 32]
  [ 4 12 20 28 36]]

 [[ 1  9 17 25 33]
  [ 5 13 21 29 37]]

 [[ 2 10 18 26 34]
  [ 6 14 22 30 38]]

 [[ 3 11 19 27 35]
  [ 7 15 23 31 39]]]

元の配列の左端を縦に下まで見ていったとき、(0,4)(8,12),(16,20)…の5つのペアが、転置後は一番上のカタマリに横に並んでいる。
二次元配列の転置と同じだと見えないこともない。

三次元配列の上下逆順


関数とスライスを使って上下を逆順に並び替えてみる。

# 三次元配列の上下反転
array_3d_ud = np.flipud(array_3d)

print("元の配列\n", array_3d)
print("\n上下反転\n", array_3d_ud)
print("\n元の形状", array_3d.shape)
print("変形後の形状", array_3d_ud.shape)
元の配列
 [[[ 0  1  2  3]
  [ 4  5  6  7]]

 [[ 8  9 10 11]
  [12 13 14 15]]

 [[16 17 18 19]
  [20 21 22 23]]

 [[24 25 26 27]
  [28 29 30 31]]

 [[32 33 34 35]
  [36 37 38 39]]]

上下反転
 [[[32 33 34 35]
  [36 37 38 39]]

 [[24 25 26 27]
  [28 29 30 31]]

 [[16 17 18 19]
  [20 21 22 23]]

 [[ 8  9 10 11]
  [12 13 14 15]]

 [[ 0  1  2  3]
  [ 4  5  6  7]]]

元の形状 (5, 2, 4)
変形後の形状 (5, 2, 4)
# 同じく。スライスで
array_3d_ud_slice = array_3d[::-1]

print("元の配列\n", array_3d)
print("\n上下反転\n", array_3d_ud_slice)
print("\n元の形状", array_3d.shape)
print("変形後の形状", array_3d_ud_slice.shape)
元の配列
 [[[ 0  1  2  3]
  [ 4  5  6  7]]

 [[ 8  9 10 11]
  [12 13 14 15]]

 [[16 17 18 19]
  [20 21 22 23]]

 [[24 25 26 27]
  [28 29 30 31]]

 [[32 33 34 35]
  [36 37 38 39]]]

上下反転
 [[[32 33 34 35]
  [36 37 38 39]]

 [[24 25 26 27]
  [28 29 30 31]]

 [[16 17 18 19]
  [20 21 22 23]]

 [[ 8  9 10 11]
  [12 13 14 15]]

 [[ 0  1  2  3]
  [ 4  5  6  7]]]

元の形状 (5, 2, 4)
変形後の形状 (5, 2, 4)

array_3d[::-1]の形は形状の左端(z軸)のみを逆順にしている。
y軸とx軸でそれぞれ逆順にするとどうなるかも見ておこう。

# スライスでy軸逆順
array_3d_ud_slice_y = array_3d[ : , ::-1]

print("元の配列\n", array_3d)
print("\ny軸上下反転\n", array_3d_ud_slice_y)
print("\n元の形状", array_3d.shape)
print("変形後の形状", array_3d_ud_slice_y.shape)
元の配列
 [[[ 0  1  2  3]
  [ 4  5  6  7]]

 [[ 8  9 10 11]
  [12 13 14 15]]

 [[16 17 18 19]
  [20 21 22 23]]

 [[24 25 26 27]
  [28 29 30 31]]

 [[32 33 34 35]
  [36 37 38 39]]]

y軸上下反転
 [[[ 4  5  6  7]
  [ 0  1  2  3]]

 [[12 13 14 15]
  [ 8  9 10 11]]

 [[20 21 22 23]
  [16 17 18 19]]

 [[28 29 30 31]
  [24 25 26 27]]

 [[36 37 38 39]
  [32 33 34 35]]]

元の形状 (5, 2, 4)
変形後の形状 (5, 2, 4)
# スライスでx軸逆順
array_3d_ud_slice_x = array_3d[ : , : , ::-1]

print("元の配列\n", array_3d)
print("\nx軸上下反転\n", array_3d_ud_slice_x)
print("\n元の形状", array_3d.shape)
print("変形後の形状", array_3d_ud_slice_x.shape)
元の配列
 [[[ 0  1  2  3]
  [ 4  5  6  7]]

 [[ 8  9 10 11]
  [12 13 14 15]]

 [[16 17 18 19]
  [20 21 22 23]]

 [[24 25 26 27]
  [28 29 30 31]]

 [[32 33 34 35]
  [36 37 38 39]]]

x軸上下反転
 [[[ 3  2  1  0]
  [ 7  6  5  4]]

 [[11 10  9  8]
  [15 14 13 12]]

 [[19 18 17 16]
  [23 22 21 20]]

 [[27 26 25 24]
  [31 30 29 28]]

 [[35 34 33 32]
  [39 38 37 36]]]

元の形状 (5, 2, 4)
変形後の形状 (5, 2, 4)

ここまでは三次元の変形が二次元配列の変形のように見える。だが次…

三次元配列の左右逆順


同じく左右逆順を関数とスライスで行う。

# 三次元配列の左右反転
array_3d_lr = np.fliplr(array_3d)

print("元の配列\n", array_3d)
print("\n左右反転後\n", array_3d_lr)
print("\n元の形状", array_3d.shape)
print("左右反転後の形状", array_3d_lr.shape)
元の配列
 [[[ 0  1  2  3]
  [ 4  5  6  7]]

 [[ 8  9 10 11]
  [12 13 14 15]]

 [[16 17 18 19]
  [20 21 22 23]]

 [[24 25 26 27]
  [28 29 30 31]]

 [[32 33 34 35]
  [36 37 38 39]]]

左右反転後
 [[[ 4  5  6  7]
  [ 0  1  2  3]]

 [[12 13 14 15]
  [ 8  9 10 11]]

 [[20 21 22 23]
  [16 17 18 19]]

 [[28 29 30 31]
  [24 25 26 27]]

 [[36 37 38 39]
  [32 33 34 35]]]

元の形状 (5, 2, 4)
左右反転後の形状 (5, 2, 4)

もはや二次元配列的な位置移動ではなくなった。2つ上でやったy軸逆順と同じ形になってますね。
画像の左右反転をさせる場合はy軸(真ん中の1軸)を動かせば良いのですな。

配列の見た目に囚われてはいけない気がしてきた。

三次元配列の回転


rot90()を使って三次元配列を90度回転させる。画像の配列にこれを施すとちゃんと画像が回る。

array_3d_90 = np.rot90(array_3d, 1)

print("元の配列\n", array_3d)
print("\n90度回転後の配列\n", array_3d_90)
print("\n元の形状", array_3d.shape)
print("回転後の形状", array_3d_90.shape)
元の配列
 [[[ 0  1  2  3]
  [ 4  5  6  7]]

 [[ 8  9 10 11]
  [12 13 14 15]]

 [[16 17 18 19]
  [20 21 22 23]]

 [[24 25 26 27]
  [28 29 30 31]]

 [[32 33 34 35]
  [36 37 38 39]]]

90度回転後の配列
 [[[ 4  5  6  7]
  [12 13 14 15]
  [20 21 22 23]
  [28 29 30 31]
  [36 37 38 39]]

 [[ 0  1  2  3]
  [ 8  9 10 11]
  [16 17 18 19]
  [24 25 26 27]
  [32 33 34 35]]]

元の形状 (5, 2, 4)
回転後の形状 (2, 5, 4)

カタマリが2つになってしまった。配列は完全に二次元配列的に見ることは出来ない。
このような配列の変換の具合を見て画像が回転してることが分かる人って宇宙人かなんか。



画像を見るときはy-z平面を垂直に見ている筈。従って本来は

R = array_3d[:,:,0]
R
array([[ 0,  4],
       [ 8, 12],
       [16, 20],
       [24, 28],
       [32, 36]])

↑のこの面を一番手前に見ている。x軸のインデックス0番で織り成すy-z座標平面。言うなればRGBAの赤色の平面。

そしてその一つ奥にxインデックス1番の緑色平面

G = array_3d[:,:,1]
G
array([[ 1,  5],
       [ 9, 13],
       [17, 21],
       [25, 29],
       [33, 37]])

更に奥にx2番の青色平面

B = array_3d[:,:,2]
B
array([[ 2,  6],
       [10, 14],
       [18, 22],
       [26, 30],
       [34, 38]])

更に奥に最後は透明度平面

A = array_3d[:,:,3]
A
array([[ 3,  7],
       [11, 15],
       [19, 23],
       [27, 31],
       [35, 39]])

という感じにy-z平面が合計4枚重なる三次元空間みたいになっていると思う、知らんけど。

しかしNumpyの配列はこの色平面の重なり具合を横から見た形で表示する。
人間が画面で見ている画像平面の座標軸とNumpyが表示する座標が違うので混乱してしまう。
人間が見る画像の横軸は常にy軸(1軸)。Numpyが表示する配列の横軸は常にx軸(2軸)。

さて、
で、この見えてる平面を90度回転させるので

print("R平面\n",np.rot90(R,1))
print("\nG平面\n",np.rot90(G,1))
print("\nB平面\n",np.rot90(B,1))
print("\nA平面\n",np.rot90(A,1))
R平面
 [[ 4 12 20 28 36]
 [ 0  8 16 24 32]]

G平面
 [[ 5 13 21 29 37]
 [ 1  9 17 25 33]]

B平面
 [[ 6 14 22 30 38]
 [ 2 10 18 26 34]]

A平面
 [[ 7 15 23 31 39]
 [ 3 11 19 27 35]]

のようになる。ラザニアの表面を見るが如く画面を見ていて、色平面が上から順にR-G-B-Aと合計4枚重なっているんですよ。たぶん。

Numpyは、各・色平面の各行を縦軸、重ねてできる奥行きを横軸とする平面を表示する。

R_u = np.rot90(R,1)[0]
G_u = np.rot90(G,1)[0]
B_u = np.rot90(B,1)[0]
A_u = np.rot90(A,1)[0]

x_y_90_u = np.array([R_u, G_u, B_u, A_u])
print("上側\n",x_y_90_u.T)

R_d = np.rot90(R,1)[1]
G_d = np.rot90(G,1)[1]
B_d = np.rot90(B,1)[1]
A_d = np.rot90(A,1)[1]

x_y_90_d = np.array([R_d, G_d, B_d, A_d])
print("\n下側\n",x_y_90_d.T)
上側
 [[ 4  5  6  7]
 [12 13 14 15]
 [20 21 22 23]
 [28 29 30 31]
 [36 37 38 39]]

下側
 [[ 0  1  2  3]
 [ 8  9 10 11]
 [16 17 18 19]
 [24 25 26 27]
 [32 33 34 35]]

結局、Numpyが表示する配列は画像の見た目とかけ離れているので、その表示を見ても画像処理時の何の参考にもならないんじゃないかと思う。



更に90度回転させる。元の配列の180度回転。

array_3d_180 = np.rot90(array_3d, 2)

print("元の配列\n", array_3d)
print("\n180度回転後の配列\n", array_3d_180)
print("\n元の形状", array_3d.shape)
print("回転後の形状", array_3d_180.shape)
元の配列
 [[[ 0  1  2  3]
  [ 4  5  6  7]]

 [[ 8  9 10 11]
  [12 13 14 15]]

 [[16 17 18 19]
  [20 21 22 23]]

 [[24 25 26 27]
  [28 29 30 31]]

 [[32 33 34 35]
  [36 37 38 39]]]

180度回転後の配列
 [[[36 37 38 39]
  [32 33 34 35]]

 [[28 29 30 31]
  [24 25 26 27]]

 [[20 21 22 23]
  [16 17 18 19]]

 [[12 13 14 15]
  [ 8  9 10 11]]

 [[ 4  5  6  7]
  [ 0  1  2  3]]]

元の形状 (5, 2, 4)
回転後の形状 (5, 2, 4)

形状が元に戻りました。元の配列の5つのカタマリのそれぞれで上下を入れ替えた後に全体を上下逆順させた形か。