LoginSignup
178
144

More than 3 years have passed since last update.

Kerasでデータ拡張(Data Augmentation)後の画像を表示する

Last updated at Posted at 2018-07-28

2019/07/24更新内容

KerasのImageDataGeneratorの出力を簡単に確認できるGUIツールを作りました。
simulator
https://github.com/takurooo/Keras_DataAugmentationSimulator

概要

KerasのImageDataGeneratorクラスが生成する画像ファイルを表示してみて、設定パラメータによってどんな画像が生成されるのか確認してみる記事。
ImageDataGeneratorはデータ拡張を行うためのクラスで名前の通り画像に関する処理をしてくれる。

データ拡張(Data Augmentation)とは

機械学習を実際にやってみようと思うと学習データ集めに苦労する。学習データが少ないと過学習(Overfitting)が起きてしまい汎化性能(未知のデータに対する性能)がでないと言われている。

この問題を緩和するために使われるのが「データ拡張」。

データ拡張は画像に変換処理(反転、拡大、縮小など)を加えることで、学習データの「水増し」を行う。
水増しされることで同じ画像が学習されることが少なくなるので汎化性能が改善される。

Keras ImageDataGeneratorクラスとは

機械学習のライブラリではデータ拡張をサポートしているものがある。
今回はKerasのImageDataGeneratorクラスを試してみる。

ImageDataGeneratorは様々な変換処理を画像に加えることができるが、今回はそのうち以下のパラメータを使って画像の可視化をしていく。

パラメータ 説明
rotation_range 画像を回転させる角度
width_shift_range 水平にシフトする画像横幅に対する割合
height_shift_range 水平にシフトする画像縦に対する割合
horizontal_flip 水平方向反転
vertical_flip 垂直方向反転
zoom_range 拡大縮小範囲
shear_range シアー強度

今回試したコードの概要

以下コードの説明。
コードの説明後、変換後の画像を見ていきます。

コードは以下のリポジトリに置いてあります。
https://github.com/takurooo/Keras-show_ImageDataGenerator

Import

show_generator.py
import matplotlib.pyplot as plt
from keras.preprocessing import image
from keras.preprocessing.image import ImageDataGenerator
  • keras.preprocessing.imageにデータ拡張に便利な関数が入っている。
  • matplotlibは画像の可視化に使う。

画像の読み込み

show_generator.py
# 画像ファイルをPIL形式でオープン
img = image.load_img(img_path)
# PIL形式をnumpyのndarray形式に変換
x = image.img_to_array(img)
# (height, width, 3) -> (1, height, width, 3)
x = x.reshape((1,) + x.shape)

次にImageDataGeneratorクラスに渡す画像データを用意する。
ImageDataGeneratorクラスがndarray形式の4次元配列を要求するのでその変換もここで行っておく。

ImageDataGenerator生成

show_generator.py
datagen = ImageDataGenerator(
           rotation_range=0,
           width_shift_range=0,
           height_shift_range=0,
           shear_range=0,
           zoom_range=0,
           horizontal_flip=False,
           vertical_flip=False)

ImageDataGeneratorクラスを生成。
生成時に渡すパラメータを色々変えると様々なデータ拡張を行ってくれるので、今回はここを変えてみてどんな変換が起きるか見てみる。
上記設定は何もしない設定になっている。

画像生成、表示

show_generator.py
max_img_num = 16
imgs = []
for d in datagen.flow(x, batch_size=1):
    # このあと画像を表示するためにndarrayをPIL形式に変換して保存する
    imgs.append(image.array_to_img(d[0], scale=True))
    # datagen.flowは無限ループするため必要な枚数取得できたらループを抜ける
    if (len(imgs) % max_img_num) == 0:
        break
show_imgs(imgs, row=4, col=4)

ImageDataGeneratorから変換画像を取得して表示。
表示は以下の関数で行っている。

show_generator.py
def show_imgs(imgs, row, col):
    """Show PILimages as row*col
     # Arguments
            imgs: 1-D array, include PILimages
            row: Int, row for plt.subplot
            col: Int, column for plt.subplot
    """
    if len(imgs) != (row * col):
        raise ValueError("Invalid imgs len:{} col:{} row:{}".format(len(imgs), row, col))

    for i, img in enumerate(imgs):
        plot_num = i+1
        plt.subplot(row, col, plot_num)
        plt.tick_params(labelbottom="off") # x軸の削除
        plt.tick_params(labelleft="off") # y軸の削除
        plt.imshow(img)
    plt.show()

rotation_range

rotation_rangeは画像を回転させるパラメータ。
設定は整数で何度回転させていか設定可能。
例えば90度と設定すると、Kerasの中で「-90〜90」の中でランダムに1つ数字を選んで回転処理するようになっている。
以下変換後の画像。

rotation_range=90
rotation_range_90.png
回転させることで元の画像にない領域がでてくる。
これはImageDataGenerator生成時に設定するfill_modeでどの画素で埋めるかを指定可能。
fill_modeには、constant,nearest,reflect,wrapがあり上記例ではfill_mode=nearestになっている。

fill_mode=constant(cvalで埋める色を変えられます)
rotation_range_90_constant.png

fill_mode=reflect
rotation_range_90_reflect.png

fill_mode=wrap
rotation_range_90_wrap.png

width_shift_range / height_shift_range

画像をシフトさせます。
少しややこしいのがこの変数は3つの型でシフトを指定できる。

意味
int シフトさせる画素数
1-D array シフトさせる画素数
float シフトさせる割合(元画像の解像度に対して)

int型の場合、width_shift_range=128と設定すると、「-127〜127」の数字の中からランダムに選択して、選択した画素数シフトする。

1-D array型の場合、基本的にはintと同じだがランダムに選ばれる数字を限定することができる。例えば、width_shift_range=[128,256]と設定すると「-256,-128,128,256」の中からランダムにシフトする画素数が選択される。

float型の場合、画像の幅に対する割合で表現するので、元画像が水平480でwidth_shift_range=0.5とするとシフト量は「-240〜240」画素シフトする。

画素数で指定するのは面倒くさいのでfloatで設定するのが楽。
シフトしてできた元画像にない部分はfill_modeで指定可能。

width_shift_range=0.5
widht_0.5.png

width_shift_range=0.2
widht_0.2.png

height_shift_range=0.5
height_0.5.png

horizontal_flip / vertical_flip

ランダムに反転。

horizontal_flip=True
horizontal_flip.png

vertical_flip=True
vertical_flip.png

zoom_range

拡大したり縮小したり。
こちらもシフトと同じで複数の型で指定可能。

意味
1-D array 拡大縮小させる範囲 [lower, upper]
float 拡大縮小させる範囲 [lower, upper] = [1-zoom_range, 1+zoom_range]

lower〜upperの範囲で乱数を2つ取り、それぞれx軸とy軸の拡大率にする。
kerasの中では具体的には以下のようなことをしている。

sample.py
x, y = np.random.uniform(lower, upper, 2)

ややこしいですが、
x > 1の場合、画像内の物体が縮小されたように見える。
0 < x < 1の場合、画像内の物体が拡大されたように見える。
マイナスの場合はさらに反転が加わる。

zoom_range=[1,1.5]
zoom_1_1.5.png

zoom_range=[0.5,1]
zoom_0.5_1.png

zoom_range=[-1.5,-1]
zoom_-1.5_-1.png

zoom_range=[-1,-0.5]
zoom_-1_-0.5.png

shear_range

シアー強度というもので画像変換を行う。
せん断写像というらしいが、いまいちわかっていないので実験した画像だけのせておく。

shear_range=40
shear_40.png

shear_range=90
shear_90.png

まとめ

今回は画像の可視化のためにImageDataGeneratorクラスを使ってみたが、KerasではImageDataGeneratorクラスをモデル学習時に渡すことで、これまで見てきた変換をランダムに適用したミニバッチは作ってくれるようになっているので、学習プロセスに簡単にデータ拡張を組み込めるようになっている。

データ拡張を便利だが、変換を強くかけすぎると現実には存在しないような画像になってしまい、意味のないデータになってしまう(shear_range=90とか)。なので今回のように変換パラメータを色々試して、実際に画像を確認してから使用することが効果的だと思う。

参考

最後に

Kerasの他の記事も公開しているのでKerasを勉強し始めの方は参考にしてみてください。

178
144
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
178
144