imgaugを使ってPythonで画像増幅を行う

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

当エントリではPythonで画像増幅を簡単に出来るようにするライブラリimgaugを紹介します。

imgaugとは

imgaugは画像増幅をPythonで行う際に非常に便利なライブラリです。
画像増幅は、画像系の機械学習時にモデルの汎化性能向上や推論精度の底上げを目的に、学習データの画像に対して様々な変換を掛けて画像を増やすことです。

ノイズを加えたり、アフィン変換や反転などなど基本的な変換が行えることに加えて、バウンディングボックスの座標位置を画像の変換と同様に変換することができます。

どんな変換が出来るかはimgaugのリポジトリを見るのが良いです。色々な変換画像が載っています。

使うにはpipでインストールする必要があります。

pip install imgaug

ざっくり機能紹介

いくつかの機能について紹介します。
紹介する内容以外の機能やより詳しく知りたい機能についてはドキュメント をご覧ください。割と内容が充実しているドキュメントなのでおすすめです。

基本的な変換

使い方としては変換器を定義して、画像に対して変換を適用するという流れになります。
試しに、imgaugが用意しているワラビーのサンプル画像に欠落処理を施してみます。

import imgaug as ia
from imgaug import augmenters as iaa
from matplotlib import pyplot as plt


# ワラビーの画像を例として使用
img = ia.quokka()

# 変換器を定義(0.5の確率で欠落させる)
aug = iaa.Dropout(p=0.5)

# 変換に使用する画像の形式はnumpy.ndarray
print(type(img))

# 画像に変換を適用する
aug_img = aug.augment_image(img)

# 描画
plt.subplot(121).imshow(img)
plt.subplot(122).imshow(aug_img)
plt.show()

こんな感じでたった数行で画像を変換することが出来ます。
これから幾つかの変換方法について紹介します。
紹介する変換方法以外にも様々な変換を使うことができます。詳細はドキュメントをご参照ください。

反転

Invertで画像の各ピクセル値を反転させることができます。
per_channelパラメータによってチャネル(RGBなど)毎に対する反転確率を指定できます。
下の例では全画像の内、75%が画像のチャネル毎に50%の確率で反転させ、残りの25%の画像に対して画像全体を50%の確率で反転させます。

import imgaug as ia
from imgaug import augmenters as iaa
from matplotlib import pyplot as plt
import math

# ワラビーの画像を例として使用
img_num = 40
imgs = [ia.quokka() for i in range(img_num)]

# 変換器の設定
aug = iaa.Invert(0.5, per_channel=0.75)

# 描画
fig = plt.figure(dpi = 100)

single_row_plot_num = 5
aug_imgs = aug.augment_images(imgs)
for i, aug_img in enumerate(aug_imgs):
    fig.add_subplot(math.ceil( img_num / single_row_plot_num), single_row_plot_num, i+1).imshow(aug_img)

エッジ検出

EdgeDetectで画像のエッジを検出することができます。
画像からエッジを検出し、そのエッジを黒と白で表現した画像を上から重ねます。
alphaパラメータによって上から重ねるエッジ画像のalpha値(透明度)を変化させます。

import imgaug as ia
from imgaug import augmenters as iaa
from matplotlib import pyplot as plt
import math

# ワラビーの画像を例として使用
img_num = 20
imgs = [ia.quokka() for i in range(img_num)]

# 変換器の設定
aug = iaa.EdgeDetect(alpha=(0.5, 1.0))

# 描画
fig = plt.figure(dpi = 100)

single_row_plot_num = 5
aug_imgs = aug.augment_images(imgs)
for i, aug_img in enumerate(aug_imgs):
    fig.add_subplot(math.ceil( img_num / single_row_plot_num), single_row_plot_num, i+1).imshow(aug_img)

アフィン変換

Affineでアフィン変換を行えます。
アフィン変換は線形変換と平行移動を組み合わせたものです。
今回はx軸とy軸に対する平行移動を紹介します。
translate_pxで各軸の変化量の幅を指定することができます。

import imgaug as ia
from imgaug import augmenters as iaa
from matplotlib import pyplot as plt
import math

# ワラビーの画像を例として使用
img_num = 10
imgs = [ia.quokka() for i in range(img_num)]

# 変換器の設定(x軸とy軸に対してランダムに平行移動させる)
aug_translate = iaa.Affine(translate_px={"x": (-500, 500), "y": (-200, 200)})

# 描画
fig = plt.figure(dpi = 100)

single_row_plot_num = 5
aug_imgs = aug_translate.augment_images(imgs)
for i, aug_img in enumerate(aug_imgs):
    fig.add_subplot(math.ceil( img_num / single_row_plot_num), single_row_plot_num, i+1).imshow(aug_img)

他にも様々なアフィン変換があります。紹介したもの以外の変換例はドキュメントをご参照ください。

ノイズ

AdditiveGaussianNoiseでガウスノイズ(正規分布に従うノイズ)を画像に加えることができます。
以下の例ではscaleでノイズが従う正規分布の分散の幅を指定しています。

import imgaug as ia
from imgaug import augmenters as iaa
from matplotlib import pyplot as plt
import math

# ワラビーの画像を例として使用
img_num = 10
imgs = [ia.quokka() for i in range(img_num)]

# 変換器の設定(正規分布(0,scale)に従うノイズを画像に加える)
aug_translate = iaa.AdditiveGaussianNoise(scale=[0, 255])

# 描画
fig = plt.figure(dpi = 100)

single_row_plot_num = 5
aug_imgs = aug_translate.augment_images(imgs)
for i, aug_img in enumerate(aug_imgs):
    fig.add_subplot(math.ceil( img_num / single_row_plot_num), single_row_plot_num, i+1).imshow(aug_img)

複数の変換を組み合わせる

連続

Sequentialを使うことで、複数の変換処理を連続して加えることができます。
この機能を使うことで、複雑な変換処理を簡単に作成することができます。
以下の例ではノイズと回転を同時に加えています。

import imgaug as ia
from imgaug import augmenters as iaa
from matplotlib import pyplot as plt
import math

# ワラビーの画像を例として使用
img_num = 10
imgs = [ia.quokka() for i in range(img_num)]

# 変換器の設定(ノイズと回転を同時に加える)
seq_aug = iaa.Sequential([
    iaa.AdditiveGaussianNoise(scale=[0, 0.25*255]),
    iaa.Affine(rotate=(0,180))
])

# 描画
fig = plt.figure(dpi = 100)

single_row_plot_num = 5
aug_imgs = seq_aug.augment_images(imgs)
for i, aug_img in enumerate(aug_imgs):
    fig.add_subplot(math.ceil( img_num / single_row_plot_num), single_row_plot_num, i+1).imshow(aug_img)

ランダム選択

SomeOfを使うことで複数の変換方法からランダムで指定した数だけ選択して、変換を施します。
画像の増幅方法により幅を持たせたい場合にはかなり便利な方法です。
以下の例ではノイズや回転、反転、エッジ検出などから二つの変換を行います。

import imgaug as ia
from imgaug import augmenters as iaa
from matplotlib import pyplot as plt
import math

# ワラビーの画像を例として使用
img_num = 10
imgs = [ia.quokka() for i in range(img_num)]

# 変換器の設定(以下で定義する変換処理の内ランダムに二つの処理を選択)
some_aug = iaa.SomeOf(2, [
    iaa.AdditiveGaussianNoise(scale=[0, 0.25*255]), # ノイズ
    iaa.Affine(rotate=(0,180)), # 回転
    iaa.Invert(0.5, per_channel=0.5), # 反転
    iaa.EdgeDetect(alpha=(0, 0.5)), #エッジ検出
    iaa.CoarseSaltAndPepper(0.2, size_percent=(0.05, 0.1)), # 白と黒のノイズ
])

# 描画
fig = plt.figure(dpi = 100)

single_row_plot_num = 5
aug_imgs = some_aug.augment_images(imgs)
for i, aug_img in enumerate(aug_imgs):
    fig.add_subplot(math.ceil( img_num / single_row_plot_num), single_row_plot_num, i+1).imshow(aug_img)

バウンディングボックス

imgaugではバウンディングボックスを定義し、バンディングボックスにも画像と同様の変換を施すことができます。なので、アノテーションを行なった画像を増幅させた時に、変換を施した後のバウンディングボックスデータからラベルデータを作成することができます。(ラベルデータを作成する処理は別で必要にはなりますが...)

以下の例ではバウンディングボックスを定義し、画像とバウンディングボックスに対して変換を施し、その後変換前後の画像とバウンディングボックスを描画します。

import imgaug as ia
from imgaug import augmenters as iaa
from matplotlib import pyplot as plt


# 例としてビーバーの画像を使用
image = ia.quokka(size=(256, 256))

# バウンディングボックスを定義
bb = ia.BoundingBoxesOnImage([
    ia.BoundingBox(x1=55, y1=50, x2=110, y2=150),
], shape=image.shape)

# アフィン変換を定義(右上に平行移動)
aug = iaa.Affine(translate_px={"x": 100, "y": -40})

# 画像とバウンディングボックスを変換
aug_img = aug.augment_image(image)
aug_bb = aug.augment_bounding_boxes([bb])[0]

# バウンディングボックスと画像を重ねる
image_before = bb.draw_on_image(img, thickness=2, color=[255, 0,0])
image_after = aug_bb.draw_on_image(aug_img, thickness=2, color=[0, 255, 0])

# 変換前後の画像を描画
fig = plt.figure()
fig.add_subplot(121).imshow(image_before)
fig.add_subplot(122).imshow(image_after)

plt.show()

画像増幅の例

上で説明したような処理を使って、画像増幅を行う処理のノートブックを作成しました。
用途としてはAmazon SageMakerの組み込みアルゴリズムである物体検出に使う画像の増幅です。
内容をこちらに載せると長くなるので、GitHubに置いています。ご興味をお持ちの方は以下のリンクよりご覧ください。

さいごに

今回はPythonのライブラリであるimgaugを使った画像増幅の方法について紹介しました。
簡単に様々な効果を画像に及ぼしたり、バウンディングボックスの変換を行えるなど、教師データの作成の手間をかなり減らすことができます。

今後、触ってみようと思っている方の参考になれば幸いです。

参考