こうさくきろく

つくるのたのしい

imgaug を使って Object Detection の学習データを拡張する

TL;DR

  • Object Detection 用学習データの拡張を自動化した
  • 拡張したデータが学習に与えた影響については未検証

github.com

Object Detection で用いる学習データ

今回、Object Detection のモデル構築には SSD のコードを Keras にポーティングした下記のコードを使用しており、このコードで使用できる学習データを生成することを目標としています。

github.com

学習に使うデータは画像に加えてアノテーション(画像内のオブジェクトの座標とラベル)が必要になります。 例えば、meat というオブジェクトを学習させる場合は、下記のように水平な矩形内にオブジェクトが収まるように指定した座標と、そのオブジェクトを識別するラベルを付与します。

f:id:mukopikmin:20181203233144p:plain

ラベル付けには labelImg を使用しました。

github.com

labelImg では Pascal VOC と Yolo の形式でアノテーションデータを生成できますが、 ssd_keras では Pascal VOC の形式が使用されているため、Pascal VOC の形式で出力します。

上記の肉画像のアノテーションは下記のようになります。

<annotation>
    <folder>bounding-box-augmentation</folder>
    <filename>pic.jpg</filename>
    <path>/Users/mukopikmin/Development/bounding-box-augmentation/pic.jpg</path>
    <source>
        <database>Unknown</database>
    </source>
    <size>
        <width>500</width>
        <height>281</height>
        <depth>3</depth>
    </size>
    <segmented>0</segmented>
    <object>
        <name>meat</name>
        <pose>Unspecified</pose>
        <truncated>0</truncated>
        <difficult>0</difficult>
        <bndbox>
            <xmin>76</xmin>
            <ymin>61</ymin>
            <xmax>463</xmax>
            <ymax>242</ymax>
        </bndbox>
    </object>
</annotation>

学習データ(画像+アノテーション)の拡張

認識対象にもよりますが、ある程度のボリューム(数百〜数千)で学習データを用意する必要があります。 ただ、画像をたくさん用意することができなかったり、人手でラベル付けをするのはつらかったりするかと思います。

そこで、画像データとアノテーションデータをセットで拡張することを考えます。 ここでいう画像データの拡張は下記のような操作で似た画像データを複数生成する方法を指します。

  • 変形させる(回転、移動、歪みなど)
  • ノイズを付加する(ぼかし、欠損など)
  • 色の変更(反転、グレースケールなど)

このような操作は Keras*1ImageDataGenerator でも実現できますがアノテーションデータまでは拡張できないため、imgaug を使って画像データとアノテーションデータをセットで自動生成します。

github.com

このライブラリでは画像が回転したり歪んだりしても、画像に与えた操作からオブジェクトの座標を再計算してくれます。

例えば画像とオブジェクトの座標をセットでそのまま回転するとこのようになります。

f:id:mukopikmin:20181204001842p:plain

imgaug では to_deterministic() を使うことで画像に加えた操作と同様の操作をアノテーションにも加え、座標で囲まれる範囲を水平な形に補正してくれます。

from imgaug import augmenters as iaa
import cv2

images = [cv2.imread('path/to/file')]
seq = iaa.Sequential([...])

seq_det = seq.to_deterministic()
images_aug = seq_det.augment_images(images)

f:id:mukopikmin:20181204233730p:plain

ただし、ドキュメント*2にも記載されているように、回転にはあまり強くなく想定した範囲よりも広い範囲を囲んでしまうようです。 上記の結果も肉の範囲よりも若干広い範囲が指定されています。

また、オプションを指定することで画像からはみ出てしまったオブジェクトの座標を画像内におさまる範囲の座標にすることもできます。 (画像外に完全に出てしまった座標は削除されます)

bbs_aug = []
for bb in seq_det.augment_bounding_boxes(bbs):
    _bb = bb.remove_out_of_image().cut_out_of_image()
    bbs_aug.append(_bb)

画像を加工した結果、画像内にオブジェクトが存在しない場合もあります。 このようなアノテーションデータは別途検査して取り除く必要があります。 (ssd_keras ではオブジェクトのないアノテーションデータを読み込むとエラーとなります)

まとめ

  • 学習データを画像とアノテーションのセットで自動的に拡張することができた
  • ノイズが入りすぎてオブジェクトを目視で認識できない場合もアノテーションは残ってしまうので、このようなデータは手動で取り除く必要がある
  • SSD は内部的には画像の拡張を行っているらしく、今回の方法で得たデータが学習にどれだけの効果を発揮するかはわからない*3

実装はほぼサンプルコード通りですが、ここで公開しています。

github.com