ImageDataGeneratorでデータ拡張してみた
ImageDataGeneratorを使って画像拡張を色々試してみます。使う画像は実家のワンコ(小次郎君)の写真です。
1.画像の水増し
① 回転(rotation_range)
datagen = ImageDataGenerator( rotation_range=90, ) g = datagen.flow(x, batch_size=x.shape[0], shuffle=False) itr=3 generated_imgs = [] for i in range(itr): generated_img = g.next() generated_imgs.extend(generated_img)
- 入力画像はx。x.shape=(1, 1478, 1108, 3)=(画像1枚、縦幅1478ピクセル、横幅1108ピクセル、カラー画像)。
- 出力画像はgenerated_imgs。generated_imgs.shape=(3, 1478, 1108, 3)=(画像3枚、縦幅1478ピクセル、横幅1108ピクセル、カラー画像)。
拡張された画像を確認します。
generated_imgs = np.array(generated_imgs) fig = plt.figure(figsize=(15,5)) fig.add_subplot(1,itr+1,1) plt.title("original img") plt.imshow(x[0]) for i,img in enumerate(generated_imgs): fig.add_subplot(1,itr+1,i+2) plt.title("aug img {}".format(i)) plt.imshow(img) plt.show()
② 横にずらす(width_shift_range)
datagen = ImageDataGenerator(
width_shift_range=0.5,
)
※コードは 「① 回転」とほぼ同じなので重複分は省略。
③ 縦にずらす(height_shift_range)
datagen = ImageDataGenerator(
height_shift_range=0.5,
)
※コードは 「① 回転」とほぼ同じなので重複分は省略。
④ 明るさを変える(brightness_range)
datagen = ImageDataGenerator( brightness_range=[0.5,1.5], )
※コードは 「① 回転」とほぼ同じなので重複分は省略。
⑦ RGB各チャネルに0~指定した値をランダムに加算または減算(channel_shift_range)
datagen = ImageDataGenerator(
channel_shift_range=100,
)
※コードは 「① 回転」とほぼ同じなので重複分は省略。
⑧ 水平方向に反転(horizontal_flip)
datagen = ImageDataGenerator(
horizontal_flip=True,
)
※コードは 「① 回転」とほぼ同じなので重複分は省略。
⑨ 垂直方向に反転(vertical_flip)
datagen = ImageDataGenerator(
vertical_flip=True,
)
※コードは 「① 回転」とほぼ同じなので重複分は省略。
参考:余白の埋め方(fill_mode, cval)
画像のずらしたりするときに、画像に余白ができることがあります。その処理の仕方が複数用意されているので、それぞれ試してみます。cvalの値によって、塗りつぶしの色が変わります。色は白(0)~黒(255)です。
① constant, cval
余白を単色で塗りつぶす。
datagen = ImageDataGenerator( width_shift_range=0.5, fill_mode='constant', cval=0.0, #ココの値で色を変える )
※コードは 「① 回転」とほぼ同じなので重複分は省略。
② nearest
隣接しているピクセルの色をコピーして余白を埋めます。ちなみにfill_modeのデフォルトはnearestです。
datagen = ImageDataGenerator( width_shift_range=0.5, fill_mode='nearest', )
※コードは 「① 回転」とほぼ同じなので重複分は省略。
③ reflect
画像を反転させて余白を埋めます。
datagen = ImageDataGenerator( width_shift_range=0.5, fill_mode='reflect', )
※コードは 「① 回転」とほぼ同じなので重複分は省略。
④ wrap
画像を複製して余白を埋めます。
datagen = ImageDataGenerator( width_shift_range=0.5, fill_mode='wrap', )
※コードは 「① 回転」とほぼ同じなので重複分は省略。
2.正規化
2.1.画像単位に正規化
① 平均を0にする(samplewise_center)
datagen = ImageDataGenerator(
samplewise_center=True,
)
画像のデータの平均が0になるように正規化します。以下を見てもらえれば分かると思いますが、全データに対して平均値を減算しています。
2.2.データセット単位に正規化
① 平均を0にする(featurewise_center)
実装する上での注意点ですが、データセット単位に正規化する場合はImageDataGenerator.fit()を呼び出す必要があります。fit()でデータセット全体の統計量を計算しているようです。
datagen = ImageDataGenerator( featurewise_center=True, ) datagen.fit(x) g = datagen.flow(x, batch_size=x.shape[0], shuffle=False)
画像のデータをデータセット全体の平均値で正規化します。イメージは以下の通りです。samplewizseのときはチャネル関係なく全データの平均を使って平均していましたが、featurewiseの方はチャネル毎に平均を取って正規化しているようです。何故そのような仕様になっているのかは分からないです。分かる方いらっしゃったらコメントいただけると嬉しいです。
※上記の数式はあくまでイメージです。雑な表現ではありますが、ご容赦ください。
※微妙に計算合わないですが、端数処理ですかね…?
② 標準偏差で正規化(featurewise_std_normalization)
datagen = ImageDataGenerator( featurewise_std_normalization=True, ) datagen.fit(x) g = datagen.flow(x, batch_size=x.shape[0], shuffle=False)
こちらもチャネル毎に正規化しているようです。イメージは以下の通り。
※こちらも雑な表現ご容赦ください。
※同じく、微妙に計算が合わない。
③ ZCA白色化(zca_whitening)
ZCA白色化は大量にメモリを食うようです。1280×960の画像でZCA白色化を実施しようとしたところ、メモリ49.4TiB必要だって怒られました。しょうがないので、めちゃめちゃ画像を縮小させました。
datagen = ImageDataGenerator( zca_whitening=True, zca_epsilon=1e-06, ) datagen.fit(x) g = datagen.flow(x, batch_size=x.shape[0], shuffle=False)
共分散行列が単位行列になるように変換しているようです。ZCAイプシロンがどう使われていて、どのような影響を及ぼすのかは正直分からないです。ZCAイプシロンをデフォルトの1e-06としたときに以下のように画像データが変換されていました。