augmentation

深層学習は大量な画像を必要とする。深層学習では、複数の層からなるニューラルネットワークを使用している。そのようなニューラルネットワークを構築するために、数万以上のパラメーターが必要である。そのため、深層学習では、これらのパラメーターを決めるためには、大量な画像を必要とする。

画像データは(目的に応じて)なるべく様々な環境下で、大量に取得(撮影)しておくことが望ましい。しかし、コストや時間などによって、大量なデータを収取できない場合、画像を水増し(augmentation)することができる。もっともシンプルな augmentation の方法として、既存の画像を左右反転したり、上下反転したり、回転したりするなど方法がある。あるいは、既存の画像にノイズやぼかしなどを加えたりする方法もある。

回転

次のサンプルコードは、1/2 の確率で画像を回転させる例を示している。回転させる角度は、0-90 度の範囲内でランダムに決める。この関数に入力する画像は、OpenCV や skimage などで読み込んだ 3 次元配列である。

import random 
import numpy as np
import skimage

def augmentation_rotation(img):
    r = np.random.rand(1)

    if r > 0.50:
        random_degree = random.uniform(0, 90)
        img = skimage.transform.rotate(img, random_degree, resize=True, cval=0)

    return img

反転

次のサンプルコードは、1/3 の確率で左右反転させ、1/3 の確率で上下反転させる例を示している。

import numpy as np
import skimage

def augmentation_flip(img):
    r = np.random.rand(1)

    if r < 1/3:
        img = img[:, ::-1, :]
    elif r < 2/3:
        img = img[::-1, :, :]

    return img

ノイズ

Python の skimage パッケージには、画像にノイズを加える機能が実装されている。次のサンプルコードは、画像に様々なノイズを加える例を示している。

import numpy as np
import skimage

def augmentation_noise(img):
    r = np.random.rand(1)

    if r < 0.15:
        img = skimage.util.random_noise(img, mode='localvar')
    elif r < 0.30:
        img = skimage.util.random_noise(img, mode='salt')
    elif r < 0.45:
        img = skimage.util.random_noise(img, mode='s&p')
    elif r < 0.60:
        img = skimage.util.random_noise(img, mode='speckle', var=0.01)
    elif r < 0.75:
        img = skimage.util.random_noise(img, mode='poisson')
    elif r < 0.95:
        img = skimage.util.random_noise(img, mode='gaussian', var=0.01)

    img = img * 255
    img = img.astype(np.uint8)

    return img

ランダムに水増し

上で挙げた augmentation の例では、回転、反転、ノイズをそれぞれ単独に行なっていた。これらの augmentataion の操作をランダムに組み合わせることで、さらに多様な画像を作り出すことができる。次のサンプルコードは、上で作成した augmentation_rotation, augmentation_flip, augmentation_noise を順に呼び出して、画像に対して、これらの操作をランダムに施して、100 枚の画像を水増ししている例である。

import numpy as np
import skimage

def augmentation(image_path=None, output_dirpath=None, n=100, output_prefix='augmented_image'):

    img = skimage.io.imread(image_path)

    i = 0
    while i < n:
        i = i + 1

        img_ag = augmentation_rotation(img)
        img_ag = augmentation_flip(img_ag)
        img_ag = augmentation_noise(img_ag)

        new_file_path = os.path.join(output_dirpath, output_prefix + '_' + str(i) + '.png')
        skimage.io.imsave(new_file_path, img_ag)