深層学習の訓練用画像のラベルをスマホで作成 [紹介]

# DeepLearning用ラベリングAndroidApp

後輩が作成したスマホアプリの紹介です。
[オリジナルの記事はこちら](http://qiita.com/TomoyaFujita2016/items/1b0997e4fc77d89ae5eb) (Qiita)
[アプリのダウンロード先はこちら](https://play.google.com/store/apps/details?id=com.tomoya.yololabelingtool&hl=ja) (Google Play Store)

![img4.png](https://qiita-image-store.s3.amazonaws.com/0/109160/ec2522ae-ca0a-7233-803c-32ff703267be.png)

作者によると

> 1. アノテーションファイル生成を遂にスマホで！
> 2. あの辛いラベル付け作業をスマホでリラックスしながらできる！
> 3. 直感的なタッチ操作！

とのことです。なんだか便利そうですね。

## 活躍する場面

DeepLearningを実際に活用しようとした際には大量のトレーニングデータが必要です。
すでにある大規模なデータセットに含まれているカテゴリなら簡単に学習をすることができますが、存在しないカテゴリにおいてはデータセットを自前で用意しなくてはなりません。
しかしデータセットは一般に大量のデータと正解ラベルが必要となり用意することは大きな負担になります。

今回紹介するのは一般物体認識のタスクで使われるデータセットを自前で用意する際にとても有効なスマホアプリです。

タスクに関連した大量の画像を集めたはいいが集めただけでは正解ラベルはついておらず、手動でラベル付けをしなくてはならなかった作業の負担を大きく軽減します。

画像をスマホに転送して物体の位置をタッチするだけでラベルが生成されます。

## 使い方

### 認識させたい物体が写った画像を用意
学習に使う画像を大量に用意します。
![img1.png](https://qiita-image-store.s3.amazonaws.com/0/109160/d56d65e2-2728-09af-350f-d2df0bb8c189.png)
![img2.png](https://qiita-image-store.s3.amazonaws.com/0/109160/168a3d28-b6f0-0a2b-801a-e30c298bb88c.png)


### スマホでフォーマットしたSDカード(Micro SDなど)に画像を転送
![img3.png](https://qiita-image-store.s3.amazonaws.com/0/109160/303af6db-2427-f01a-b34c-8107b2d5b876.png)


パソコンからスマホに画像を転送します。
SDカードをパソコンに接続し、`Android/data/com.tomoya.yololabelingtool/files/images`に用意した画像を転送します。
転送が完了したらパソコンから取り外してスマホにセットします。


* 現在はSDカード経由での転送にのみ対応しています。
* SDカードはスマホでフォーマットしてください。
* スマホのアプリからデータを読み込むためにAndroidのファイル配置である必要があります。普段からスマホで利用しているSDカードであればフォーマット済であると思います。
* ディレクトリが存在しない場合は作成してください。

### スマホでアプリを起動してひたすらタッチ
画像を転送したSDカードをスマホにセットしたらアプリを起動します。
自動で画像ファイルが読み込まれます。

初期画面です。複雑な機能はありません。
認識したい物体ごとにクラス名を登録する必要があります。
初回にのみ必要な操作です。
左上の歯車アイコンから追加を行ってください。
![img6.png](https://qiita-image-store.s3.amazonaws.com/0/109160/c39a7c72-23e6-41b4-52dd-f203e5bcd998.png)
矩形選択は次のように行います。
画像を読み込んだ状態で表示される黒い十字のカーソルを選択する物体の左上に合わせます。
![img8.png](https://qiita-image-store.s3.amazonaws.com/0/109160/ca1c4c01-1d8d-6494-f09c-e881f427d874.png)
合わせてから左下のCrossを押し、続いて右下に合わせます。
![img9.png](https://qiita-image-store.s3.amazonaws.com/0/109160/d7c98140-a3af-e75b-c2f0-5697034e3d72.png)
![img10.png](https://qiita-image-store.s3.amazonaws.com/0/109160/950e5178-e13a-ed5d-ec8c-cf76ec71981f.png)

## 出力されるデータのフォーマット
データは`Android/data/com.tomoya.yololabelingtool/files/texts/*`に出力されます。
アプリのサムネイルにある説明のイラストが理解しやすいです。
![img5.png](https://qiita-image-store.s3.amazonaws.com/0/109160/fbf3003b-a87a-3468-595f-b2cc1e88e407.png)
[YOLO](https://pjreddie.com/darknet/yolo)にそのまま使えるフォーマットになっています。

## 作成されるラベルのフォーマットを変えたい
現時点ではアプリ内で設定して出力フォーマットを変更することはできません。
フォーマットを変えたい場合はラベルファイルをパソコンに転送して加工しましょう。

出力されるラベルはバウンディングボックスの中心と大きさがそれぞれ全体を1とした比率で比率では扱いにくいので変更したいといった場合には以下のようなコードで変換できます。
変換後はバウンディングボックスの中心と大きさそれぞれがピクセル位置(整数)になります。


* Shellが使える環境なら

```shell-session
$ cat label
0 0.15487 0.554 0.5487 0.3684
1 0.245 0.814 0.4574 0.15144
2 0.488 0.254 0.7841 0.1584
4 0.154 0.455521 0.48454 0.545
$ cat label | awk -v width="320" -v height="240" '{print $1 " " int($2*width) " " int($3*height) " " int($4*width) " " int($5*height)}'
0 49 132 175 88
1 78 195 146 36
2 156 60 250 38
4 49 109 155 130
```

* Pythonが使えるなら

```py3
width, height = 320, 240
f = open('label', 'r')
for line in f.readlines():
    d = [ float(x) for x in line.split() ]
    print("{0} {1} {2} {3} {4}".format(int(d[0]), int(d[1]*width), int(d[2]*height), int(d[3]*width), int(d[4]*height))
```

よくあるバウンディングボックスの左上と右下を記録するフォーマットには以下のように変換します。(たしかSSDとかがこのフォーマットだったかな)

* Shellが使える環境なら

```shell-session
$ cat label
0 0.15487 0.554 0.5487 0.3684
1 0.245 0.814 0.4574 0.15144
2 0.488 0.254 0.7841 0.1584
4 0.154 0.455521 0.48454 0.545
$ cat label | awk -v width="320" -v height="240" '{print $1 " " int($2*width-$4*width/2) " " int($3*height-$5*height/2) " " int($2*width+$4*width/2) " " int($3*height+$5*height/2)}'
0 -38 88 137 177
1 5 177 151 213
2 30 41 281 79
4 -28 43 126 174
```

* Pythonが使えるなら

```py3
width, height = 320, 240
f = open('label', 'r')
for line in f.readlines():
    d = [ float(x) for x in line.split() ]
    print("{0} {1} {2} {3} {4}".format(int(d[0]), int(d[1]*width-d[3]*width/2), int(d[2]*height-d[4]*height/2), int(d[1]*width+d[3]*width/2), int(d[2]*height+d[4]*height/2))
```

## 最後に
これで学習データに対してのラベル付けが捗るようになりますね！
テレビのCMの時間に、電車で移動してる時間に、とスキマ時間を上手に活用してライバルに差をつけよう！！