ディープラーニングの学習用データセットを用意するときに、画像検索から引っ張ってきた画像だけではどうしても枚数が足りない。なので回転してデータセットを水増ししたい。
さくっと回転させてみる
OpenCVは画像の回転も可能です。やり方は以下のエントリーを参考にしました。
とりあえずレナさんを45°回転させてみる。
コード
import cv2
# 画像の読み込み。0:グレースケール、1:カラー
img = cv2.imread("Lenna.png", 1)
# 画像のサイズを取得、表示
h, w, _ = img.shape[:3]
# 画像の中心を計算
cw = w // 2
ch = h // 2
center = (cw,ch)
# 画像を回転
#getRotationMatrix2D関数を使用
trans = cv2.getRotationMatrix2D(center, 45.0, 1.0)
#アフィン変換
img2 = cv2.warpAffine(img, trans, (w,h))
cv2.imshow('window', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
実行結果
回転はちゃんとできてるけど、黒い部分が出る。これはまあ当たり前で、画像そのもののサイズは変わらないわけだから回転させれば足りない部分は出てきます。その部分が黒として補間されている様子。
でも、学習させる上でこの黒い部分はノイズでしかない。解消する方法として思いつくのは、トリミングするか、下敷きを作るか。。。
トリミングすると画像のサイズが変わってしまうので、できれば避けたい。なので、元の画像を下敷きにするという方法を取ることにしました。
考え方
黒が出た部分というのは値が[0, 0, 0]になっているはず。なので、forループで左上から総当たり的に[0, 0, 0]の部分を探し、合致したら元の画像の同じ場所の値をコピペしてやればいい。
コード自体はとても単純。
コード
for i in range(0, w):
for j in range(0, h):
if (img2[i,j] == [0, 0, 0]).all() :
img2[i,j] = img[i, j]
配列を条件式に使うとき、最初は素直にif img2[i,j] == [0, 0, 0]:
と書いていたら、The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
というエラーが出て怒られました。
要約すると「配列のときは部分一致なのか完全一致なのか決めてね」ということらしい。ので、今回は完全一致にしました。
ともあれこれで、穴埋めは上手くいっているはずなので、表示させて確認してみます。
cv2.imshow('window', image2)
cv2.waitKey(0)
cv2.destroyAllWindows()
実行結果
穴埋めは想定通りに行きましたが、回転した画像の端っこに、黒縁が出てしまいました。解決方法としては[0, 0, 0]の値を変えて、それより下なら~という風に指定してやるか…ですがこれも今度は他の部分が破たんしそう。まあ、これくらいなら許容範囲かな、ということで今回は妥協することにしました。