NumPy配列ndarrayを上下左右に反転するnp.flip, np.flipud, np.fliplr

Posted: | Tags: Python, NumPy

numpy.flip()を使うとNumPy配列ndarrayを上下左右に反転できる。上下反転に特化したnumpy.flipud()、左右反転に特化したnumpy.fliplr()もある。

ここでは以下の内容について説明する。

  • 配列ndarrayを上下反転: np.flipud()
  • 配列ndarrayを左右反転: np.fliplr()
  • 配列ndarrayを任意の軸(次元)で反転: np.flip()
    • デフォルトの処理
    • 反転する軸を指定: 引数axis
  • 画像を上下左右に反転

適宜説明するが、これらの関数を使わずに、スライス::-1で反転させることも可能。

配列ndarrayを上下反転: np.flipud()

配列ndarrayを上下反転するにはnumpy.flipud()を使う。udUp / Downの意味。

numpy.flipud()が返すのはビュー(参照)。元の配列とメモリを共有するため、いずれか一方の値を変更するともう一方の値も変わる。

import numpy as np

a_2d = np.arange(6).reshape(2, 3)
print(a_2d)
# [[0 1 2]
#  [3 4 5]]

a_2d_flipud = np.flipud(a_2d)
print(a_2d_flipud)
# [[3 4 5]
#  [0 1 2]]

print(np.shares_memory(a_2d, a_2d_flipud))
# True

別々のデータとして処理したい場合はcopy()を使う。

a_2d_flipud_copy = np.flipud(a_2d).copy()
print(a_2d_flipud_copy)
# [[3 4 5]
#  [0 1 2]]

print(np.shares_memory(a_2d, a_2d_flipud_copy))
# False

numpy.flipud()はスライス[::-1]と同等。最初の軸(次元)が反転する。

print(a_2d[::-1])
# [[3 4 5]
#  [0 1 2]]

一次元配列や三次元以上の多次元配列に対しても同様。最初の軸が反転する。特に一次元配列の場合は「上下反転」というイメージと異なる結果なので注意。

a_1d = np.arange(3)
print(a_1d)
# [0 1 2]

print(np.flipud(a_1d))
# [2 1 0]

print(a_1d[::-1])
# [2 1 0]
a_3d = np.arange(24).reshape(2, 3, 4)
print(a_3d)
# [[[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]
# 
#  [[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]]

print(np.flipud(a_3d))
# [[[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]
# 
#  [[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]]

print(a_3d[::-1])
# [[[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]
# 
#  [[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]]

三次元以上の多次元配列で任意の軸を反転させたい場合は後述のnumpy.flip()を使う。

配列ndarrayを左右反転: np.fliplr()

配列ndarrayを左右反転するにはnumpy.fliplr()を使う。lrLeft / Rightの意味。

numpy.fliplr()が返すのはビュー(参照)。別々のデータとして処理したい場合はnumpy.flipud()の例と同様にcopy()を使えばよい。

import numpy as np

a_2d = np.arange(6).reshape(2, 3)
print(a_2d)
# [[0 1 2]
#  [3 4 5]]

a_2d_fliplr = np.fliplr(a_2d)
print(a_2d_fliplr)
# [[2 1 0]
#  [5 4 3]]

print(np.shares_memory(a_2d, a_2d_fliplr))
# True

numpy.fliplr()はスライス[:, ::-1]と同等。二番目の軸(次元)が反転する。

print(a_2d[:, ::-1])
# [[2 1 0]
#  [5 4 3]]

一次元配列や三次元以上の多次元配列に対しても同様。二番目の軸が反転する。一次元配列の場合は二番目の軸が存在しないためエラーになるので注意。

a_1d = np.arange(3)
print(a_1d)
# [0 1 2]

# print(np.fliplr(a_1d))
# ValueError: Input must be >= 2-d.
a_3d = np.arange(24).reshape(2, 3, 4)
print(a_3d)
# [[[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]
# 
#  [[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]]

print(np.fliplr(a_3d))
# [[[ 8  9 10 11]
#   [ 4  5  6  7]
#   [ 0  1  2  3]]
# 
#  [[20 21 22 23]
#   [16 17 18 19]
#   [12 13 14 15]]]

print(a_3d[:, ::-1])
# [[[ 8  9 10 11]
#   [ 4  5  6  7]
#   [ 0  1  2  3]]
# 
#  [[20 21 22 23]
#   [16 17 18 19]
#   [12 13 14 15]]]

配列ndarrayを任意の軸(次元)で反転: np.flip()

配列ndarrayを上下左右を含む任意の軸(次元)で反転するにはnumpy.flip()を使う。複数の軸で同時に反転することも可能。

デフォルトの処理

デフォルトではすべての軸が反転する。二次元配列の場合、上下左右に反転する。

numpy.flip()が返すのはビュー(参照)。別々のデータとして処理したい場合はnumpy.flipud()の例と同様にcopy()を使えばよい。

import numpy as np

a_2d = np.arange(6).reshape(2, 3)
print(a_2d)
# [[0 1 2]
#  [3 4 5]]

a_2d_flip = np.flip(a_2d)
print(a_2d_flip)
# [[5 4 3]
#  [2 1 0]]

print(np.shares_memory(a_2d, a_2d_flip))
# True

スライスですべての軸を反転するのと同等。

print(a_2d[::-1, ::-1])
# [[5 4 3]
#  [2 1 0]]

一次元配列や三次元以上の多次元配列に対しても同様。デフォルトではすべての軸が反転する。

a_1d = np.arange(3)
print(a_1d)
# [0 1 2]

print(np.flip(a_1d))
# [2 1 0]

print(a_1d[::-1])
# [2 1 0]
a_3d = np.arange(24).reshape(2, 3, 4)
print(a_3d)
# [[[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]
# 
#  [[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]]

print(np.flip(a_3d))
# [[[23 22 21 20]
#   [19 18 17 16]
#   [15 14 13 12]]
# 
#  [[11 10  9  8]
#   [ 7  6  5  4]
#   [ 3  2  1  0]]]

print(a_3d[::-1, ::-1, ::-1])
# [[[23 22 21 20]
#   [19 18 17 16]
#   [15 14 13 12]]
# 
#  [[11 10  9  8]
#   [ 7  6  5  4]
#   [ 3  2  1  0]]]

反転する軸を指定: 引数axis

反転する軸を第二引数axisで指定可能。axis=0flipud()axis=1fliplr()と同等。

print(np.flip(a_3d, 0))
# [[[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]
# 
#  [[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]]

print(a_3d[::-1])
# [[[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]
# 
#  [[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]]

print(np.flipud(a_3d))
# [[[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]
# 
#  [[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]]
print(np.flip(a_3d, 1))
# [[[ 8  9 10 11]
#   [ 4  5  6  7]
#   [ 0  1  2  3]]
# 
#  [[20 21 22 23]
#   [16 17 18 19]
#   [12 13 14 15]]]

print(a_3d[:, ::-1])
# [[[ 8  9 10 11]
#   [ 4  5  6  7]
#   [ 0  1  2  3]]
# 
#  [[20 21 22 23]
#   [16 17 18 19]
#   [12 13 14 15]]]

print(np.fliplr(a_3d))
# [[[ 8  9 10 11]
#   [ 4  5  6  7]
#   [ 0  1  2  3]]
# 
#  [[20 21 22 23]
#   [16 17 18 19]
#   [12 13 14 15]]]
print(np.flip(a_3d, 2))
# [[[ 3  2  1  0]
#   [ 7  6  5  4]
#   [11 10  9  8]]
# 
#  [[15 14 13 12]
#   [19 18 17 16]
#   [23 22 21 20]]]

print(a_3d[:, :, ::-1])
# [[[ 3  2  1  0]
#   [ 7  6  5  4]
#   [11 10  9  8]]
# 
#  [[15 14 13 12]
#   [19 18 17 16]
#   [23 22 21 20]]]

axisにはタプルやリストで複数の軸を指定することもできる。

print(np.flip(a_3d, (1, 2)))
# [[[11 10  9  8]
#   [ 7  6  5  4]
#   [ 3  2  1  0]]
# 
#  [[23 22 21 20]
#   [19 18 17 16]
#   [15 14 13 12]]]

print(a_3d[:, ::-1, ::-1])
# [[[11 10  9  8]
#   [ 7  6  5  4]
#   [ 3  2  1  0]]
# 
#  [[23 22 21 20]
#   [19 18 17 16]
#   [15 14 13 12]]]

まとめると以下のようになる。公式ドキュメントより引用。

flip(m, 0) is equivalent to flipud(m).
flip(m, 1) is equivalent to fliplr(m).
flip(m, n) corresponds to m[...,::-1,...] with ::-1 at position n.
flip(m) corresponds to m[::-1,::-1,...,::-1] with ::-1 at all positions.
flip(m, (0, 1)) corresponds to m[::-1,::-1,...] with ::-1 at position 0 and position 1.
numpy.flip — NumPy v1.16 Manual

画像を上下左右に反転

Pillow(PIL)やOpenCVなどのライブラリを利用して、画像ファイルをNumPy配列ndarrayとして読み込むことができる。

numpy.flip()などを使うと画像を上下左右に反転させることが可能。例はカラー画像(三次元配列)だが、白黒画像(二次元配列)でも特に引数の指定は変わらない。

以下の画像を例とする。

lena

サンプルコードと結果は以下の通り。

import numpy as np
from PIL import Image

img = np.array(Image.open('data/src/lena.jpg'))
print(type(img))
# <class 'numpy.ndarray'>

print(img.shape)
# (225, 400, 3)

Image.fromarray(np.flipud(img)).save('data/dst/lena_np_flipud.jpg')

Image.fromarray(np.fliplr(img)).save('data/dst/lena_np_fliplr.jpg')

Image.fromarray(np.flip(img, (0, 1))).save('data/dst/lena_np_flip_ud_lr.jpg')

nupmy flipud image

nupmy fliplr image

nupmy flip image

OpenCVの関数で反転することもできる。

関連カテゴリー

関連記事