yiskw note

機械学習やプログラミングについて気まぐれで書きます

【numpy】opencvで読み込んだ画像を縦・横方向にシフトさせる


概要

opencvで読み込んだ画像を縦・横方向に移動させる方法について調べたので,こちらにメモを残しておきます.
またその際に,はみ出た部分については無視するような処理についても検討してみました.
これを行うことでCutMixのような前処理を実装することが可能です.
あまり綺麗な方法ではないため,より良い実装がございましたら,ご教授いただけると幸いです.

numpy配列をシフトさせる方法

numpy配列をシフトさせる関数として,np.rollという関数が提供されています.
これを用いることで容易に配列のシフトが可能です.

a = np.arange(10)
print(a)  # [0 1 2 3 4 5 6 7 8 9]

res1 = np.roll(a, shift=5)
print(res1)  # [5 6 7 8 9 0 1 2 3 4]

res2 = np.roll(a, shift=2)
print(res2)  # [2 3 4 5 6 7 8 9 0 1]

こちらは多次元配列にも適用できます.

a = np.zeros((3, 3), dtype=np.uint8)
a[1, 1] = 1
print(a)

# [[0 0 0]
#  [0 1 0]
#  [0 0 0]]

print(np.roll(a, shift=(1, 1), axis=(0, 1)))

# [[0 0 0]
#  [0 0 0]
#  [0 0 1]]

opencvで読み込んだ画像をシフトさせる

opencvで読み込んだ画像はnumpy配列となるので,上記と同じ手順でシフトさせることができます.
まず画像を読み込みます.

# 画像の読み込み
img_path = "cat.jpg"
img = cv2.imread(img_path)

f:id:yiskw713:20211228160018j:plain:w600
K LによるPixabayからの画像

次に画像をシフトさせてみます.

# どれだけ画像をシフトさせるか
x_diff = 150
y_diff = -100

# 画像をシフト
shifted_img = np.roll(img, shift=(y_diff, x_diff), axis=(0, 1))

結果

f:id:yiskw713:20211228160058j:plain:w600

画像を縦・横方向にシフトさせることができました.

次にこのシフトの際に,はみ出た部分を削除してみます.
こちらは配列のスライスで実装可能です.

# はみ出た部分を削除 (黒塗り)

if x_diff >= 0:
    shifted_img[:, :x_diff] = 0
else:
    shifted_img[:, w + x_diff:] = 0

if y_diff >= 0:
    shifted_img[:y_diff] = 0
else:
    shifted_img[h + y_diff:] = 0

結果

f:id:yiskw713:20211228160451j:plain:w600

CutMixで作られるような画像を生成する

最後にこのシフトした画像と,下の画像を用いて,CutMixを実装してみます.

f:id:yiskw713:20211228160752j:plain:w600
Szabolcs MolnarによるPixabayからの画像

img_path2 = "dog.jpg"
img2 = cv2.imread(img_path2)

# 黒塗りになっているインデックスを取得
bg_inds = np.where(shifted_img == 0)

# 黒塗りの部分に,別の画像を埋め込む
shifted_img[bg_inds] = img2[bg_inds]

結果

f:id:yiskw713:20211228160914j:plain:w600

このように画像のシフトを使用することで,CutMixのような画像処理も実装できました!
CutMixで必要となるラベルも,二つの画像の面積比から簡単に算出することができます.

参考