AutoML Vision で物体検出モデルを作成する為の学習データセットをVoTTで作成してみた


## はじめに

以前、[AutoML Vision EdgeでTensorFlow.js用のモデルをexportしてみた](https://qiita.com/yasuaki9973/items/6ff55e1272ada294ba82)というタイトルで、サンプルデータを利用したモデルの作成とEdgeデバイス向けにモデルをエクスポートするところまで試したので、今回はAutoML Vision用の学習データセットを自分で作成してみようと思います。

## VoTTのインストール

画像に対するラベル付けについては、GCPのWeb画面上で操作出来るツールがありますが、やはりローカルで作業出来た方が良いと思ったので、今回はVoTT(マイクロソフト社製のアノテーションツール)を利用することにしました。※[こちら](https://github.com/Microsoft/VoTT/releases)からダウンロード出来ますので、ご利用の環境に合ったものをインストールしてください。

## VoTTでラベル付きのデータを作成する

ラベル付け作業は[VoTTの公式ドキュメント](https://github.com/microsoft/VoTT)に記載されている手順で実施し、作業が完了したらCSV形式でエクスポートしてください。※VoTTでエクスポート出来るフォーマットの中にAutoML Visionでそのまま読み込めるものがない為、以降の手順でフォーマットを変換します。

## GCSにバケットを作成する

VoTTでエクスポートした画像データを格納する、GCSのバケット(+ディレクトリ)を作成します。

## フォーマットを変換するスクリプトを実行する

以下に記載したスクリプトを実行すると、スクリプトを実行したディレクトリに[AutoML Visionフォーマット](https://cloud.google.com/vision/automl/object-detection/docs/csv-format?hl=ja)のCSVファイルが出力されます。※スクリプトを作成するにあたり、[こちら](https://gist.github.com/leigh-johnson/293f3380f15c496934e2846ec7f9ad16)の情報を参考にさせて頂きました。

以下の定数は環境に合わせて適宜書き換えてください。
GCS_IMAGE_DIR_PATH ： 画像データを格納するGCSのディレクトリパス
EXPORT_DIR_PATH ： VoTTでエクスポートしたデータが格納されているディレクトリパス
EXPORT_FILE_NAME ： VoTTでエクスポートしたCSVファイル名
CONVERT_FILE_NAME ： 出力されるCSVファイル名

```python

import pandas as pd
import cv2

# Google Cloud Storage の画像を格納するディレクトリのパス
GCS_IMAGE_DIR_PATH = 'gs://***/'

# VoTTのエクスポートしたデータの情報
EXPORT_DIR_PATH = '/***/'
EXPORT_FILE_NAME = '***.csv'

# AutoML Vision用に変換したCSVファイルのファイル名
CONVERT_FILE_NAME = '***.csv'

# AutoML Vision のフォーマット
COLUMNS_LIST = [
    'set',
    'path',
    'label',
    'x_min',
    'y_min',
    'x_max_not_used',
    'y_min_not_used',
    'x_max',
    'y_max',
    'x_min_not_used',
    'y_max_not_used'
]


# OpenCVの機能を利用して、画像の高さと幅を取得する
def get_height_and_width(image_path):

    file_name = image_path.split('/')[-1]
    img = cv2.imread(EXPORT_DIR_PATH + file_name)

    height, width, _ = img.shape

    return pd.Series([height, width])


if __name__ == "__main__":

    # VoTTで出力したCSVファイルの読み込み
    df = pd.read_csv(EXPORT_DIR_PATH + EXPORT_FILE_NAME)

    # AutoML Vision のフォーマットだと、座標はwidth, heightを1とした相対値にする必要があるので
    # OpenCVでwidth, heightを取得して、それぞれ計算する
    df[['height', 'width']] = df['image'].apply(get_height_and_width)
    df['x_min'] = df['xmin'] / df['width']
    df['y_min'] = df['ymin'] / df['height']
    df['x_max'] = df['xmax'] / df['width']
    df['y_max'] = df['ymax'] / df['height']

    # TRAINING、VALIDATION、TEST、UNASSIGNEDから選択可能、GCP側で自動で割り振って欲しいのでUNASSIGNEDを選択する
    df['set'] = 'UNASSIGNED'

    # バウンディングボックスを構成する頂点4つの内、対角線上にある2点を指定すれば良いので、残りはNULLで埋める
    df['x_max_not_used'] = None
    df['y_min_not_used'] = None
    df['x_min_not_used'] = None
    df['y_max_not_used'] = None

    # 画像のファイルパスを、GCSに格納された時のファイルパスに変換する(カラム名も公式ドキュメントに合わせて変更する)
    df['path'] = df['image'].apply(lambda x: GCS_IMAGE_DIR_PATH + x.split('/')[-1])

    # AutoML Vision のフォーマット(並び順も含めて)に合わせて、CSV形式で出力する
    df[COLUMNS_LIST].to_csv(CONVERT_FILE_NAME, header=False, index=False)

```

## GCSのバケットに学習データセットをアップロードする

ここまでの作業で、学習用の画像データとバウンディングボックスの情報などが記載された[AutoML Visionフォーマット](https://cloud.google.com/vision/automl/object-detection/docs/csv-format?hl=ja)のCSVファイルが用意出来ているはずなので、データセット一式を先ほど作成したGCSのバケット(GCS_IMAGE_DIR_PATHに記載したパス)にアップロードします。


## AutoML Vision からインポートする

以降の手順については、[こちら](https://cloud.google.com/vision/automl/object-detection/docs/create-datasets?hl=ja)を参考にすれば問題なくAutoML Visionにデータをインポート出来ると思います。