AnnoFabを使って物体検出の評価を試みる ～機械学習名古屋 第20回勉強会～

# 自己紹介
* not 機械学習エンジニア
* not データサイエンティスト
* not Web開発者
* not アノテータ（教師データ作成者）
* アノテーションの効率化などを考えるエンジニア？
    * アノテーションの生産性や品質
    * アノテーションルール
    * アノテーションツール

---
# AnnoFabとは？
* 来栖川電算が提供するアノテーションツール
* チーム作業効率化や品質管理の機能を備え、カンタンにカスタマイズができる
* **無料**で利用可能

https://annofab.com/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/0eb474e1-9e07-7fa6-0e12-5037084a70bd.png)


---
## AnnoFabの特徴
1. 開始までたった3分
2. 高品質データをサクサク作成
3. きめ細やかな作業管理
4. 自動的な計測と可視化
5. 徹底的な自動化支援（WebAPI）

https://annofab.com/ 参照


---
# はじめに

---
## 発表するモチベーション
* AnnoFabを使って機械学習っぽいことをしてみたい
    * 業務ではAnnoFabを使っているが、機械学習している訳ではない（not 機械学習エンジニア）
* AnnoFabは無料なので、いろんな人に遊んでもらいたい（ステマじゃないよ♬）


---
## AnnoFabを使って何をするか？
既存の物体検出モデルが検出した結果と、私がアノテーションした結果を比較して評価します。
アノテーション作業を減らすため、今回は「飛行機」のみをアノテーションします。

* アノテーションデータで学習しない理由：アノテーションデータの作成や、学習に時間がかかるから
* 飛行機を選んだ理由：アノテーションルールが単純になると思ったから（本当？）

---
## 発表内容
アノテーション結果と物体検出結果を比較するまでに実施した作業を、簡単に説明します。

1. 物体検出について
2. AnnoFabを使ってアノテーションデータを作成する
3. アノテーション結果と物体検出モデルが検出した結果を比較する


---
# 物体検出について

---
## 評価する物体検出のモデル
COCO Datasetで学習されたYOLO v3モデルを評価します。

---
### YOLOとは？
物体検出アルゴリズムの一つです。

>You only look once (YOLO) is a state-of-the-art, real-time object detection system

https://pjreddie.com/darknet/yolo/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/6f09f848-8b3d-191a-4266-275b1d1a8bc4.png)

---
### COCO Datasetとは？
物体検出やセグメンテーションなどのデータセットです。

>COCO is a large-scale object detection, segmentation, and captioning dataset. COCO has several features:

http://cocodataset.org/#home

物体のカテゴリは80種あります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/88c920e3-3f13-ae70-f527-bb5ba6e0ae46.png)

---
#### COCO Datasetの飛行機
http://cocodataset.org/#explore
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/bb6dec38-38c3-9016-df3b-ab919ebb6170.png)


---
# AnnoFabを使ってアノテーションデータを作成する

---
## アノテーション画像の用意
[google-images-download](https://co.bsnws.net/article/295)で、Googleから飛行機の画像を一括でダウンロードします。

```
$ googleimagesdownload --keywords "飛行機"
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/c3f169b9-1ae0-8e0d-2b3c-2fb28147d60c.png)

実在しない飛行機の画像もあります。

---
## アノテーション画像をAnnoFabに登録
登録後の入力データ画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/ee09e08e-de7d-c8ba-a262-20fc5b974074.png)


---
## タスク（アノテーション作業）の作成
「タスク」はアノテーションの作業単位です。1つのタスクには複数の画像が含まれています。
今回は1タスクを5枚にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/ba764961-ec0e-ec71-6ba8-dfd327d1d62c.png)

---
## アノテーションルールを決める
アノテーションするにはルールが必要です。今回は以下のルールでアノテーションします。

```plain:アノテーションルール
# 飛行機の囲い方
* 飛行機を矩形で囲む
* 囲む場合
    * 他の物体に隠れている
    * 画像外にはみ出している
* 囲まない場合
    * おもちゃの飛行機
    * イラストの飛行機
```

---
### 必要になりそうな属性もルールに追加する
物体検出モデルとの単純な比較であれば、アノテーションデータは矩形だけあれば十分ですが、比較した結果を考察する場合、属性情報があると便利なときがあります。
今回は、必要になりそうな属性を追加しました。本当に必要かどうかは分かりません。

```plain:アノテーションルール
# 飛行機の属性
## 隠れチェックボックス
飛行機全体の1/4以上が他の物体に隠れているとき、ONにする。

## 画像外はみ出しチェックボックス
飛行機全体の1/4以上が画像外にはみ出ているとき、ONにする。

## 位置ラジオボタン
* 空：飛行機が空にいる
* 地上：飛行機が地上にいる。または着陸直後、離陸直後。

# 画像全体の属性
## おもちゃチェックボックス
画像におもちゃの飛行機が映っていればONにする

## イラストチェックボックス
画像にイラストの飛行機が映っていればONにする
```

---
## アノテーション仕様の設定
先ほど決めたアノテーションルールに従って、アノテーション仕様を設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/f2d06251-5242-be9d-5d4b-5ae449d0cb23.png)


---
## アノテーションデータの作成
40枚の画像（8タスク）に対して、アノテーションします。

![sample3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/edfbb0bb-94bb-670c-b17d-fc296d07d815.gif)

---
## アノテーションの検査
自分が作ったアノテーションを自分で検査します。
※本来は、他者が作成したアノテーションを検査するための機能です。


---
## アノテーション一覧画面で確認する
アノテーション一覧画面で、作成したアノテーションの一覧を確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/bc4b1ed6-de8f-c127-38dd-4225d2c17af0.png)

---
### アノテーションの統計情報を算出
アノテーション一覧画面に表示されているアノテーションの個数を集計します。
モデル学習する前に、データ全体を俯瞰することは大事な作業です。


| 画像に映っているもの | 画像枚数 |
|----------------------|----------|
| 実物に近い飛行機     | 36       |
| おもちゃの飛行機     | 2        |
| イラストの飛行機     | 2        |
| 合計                 | 40       |


| 飛行機の状態           | 物体の数 |
|------------------------|----------|
| 飛行機                 | 58       |
| 隠れている             | 2       |
| 画像外にはみ出している | 18       |
| 地上にいる             | 33       |
| 空にいる               | 25       |



---
# アノテーション結果と物体検出モデルが検出した結果を比較する

---
## アノテーションデータをダウンロードする
AnnoFabからアノテーションデータをダウンロードします。
ダウンロードしたzipファイルの中には、画像枚数分だけJSONファイルが格納されています。
1つのJSONファイルが、1枚の画像に付与されたアノテーションデータに対応します。

```
$ tree annotation-data/
annotation-data/
├── 1.2f05b75878f20c5d6a5de64b37ebeb98_m.jpg.json
├── 10.IMG_5144.jpg.json
├── 11.yd_jal1.jpg.json
```

---
## アノテーションデータの中身


```json
{
    "project_id": "c142e7c4-f48e-42c7-800d-cf7e52584847",
    "annotation_format_version": "1.0.0",
    "task_id": "airplane_19",
    "task_phase": "acceptance",
    "task_status": "complete",
    "input_data_id": "f4db8775-dff0-4a3b-bbae-6c1395c03a64",
    "input_data_name": "飛行機.zip/ФЄНsЛ@/96.AS20180522003209_commL.jpg",
    "details": [
        {
            "label": "airplane",
            "annotation_id": "fed2054f-17f8-4a63-93c6-70e5f0a361ce",
            "data": {
                "left_top": {
                    "x": 120,
                    "y": 11
                },
                "right_bottom": {
                    "x": 278,
                    "y": 130
                },
                "_type": "BoundingBox"
            },
            "attributes": {
                "occluded": false,
                "position": "sky",
                "truncated": false
            }
        },
        {
            "label": "scene",
            "annotation_id": "e2b11cf1-2b88-483a-8a0e-02078206d547",
            "data": null,
            "attributes": {
                "illustration": false,
                "toy": false
            }
        }
    ]
}
```



---
## 物体検出モデルが検出した結果を描画する
Kerasで実装されたYolo v3を利用して、物体検出を行います。
https://github.com/qqwweee/keras-yolo3

https://qiita.com/shinmura0/items/dc0d02dc1e716b912932 を参考にしました。

今回はtinyモデルを利用します。

---
## 検出した結果とアノテーション結果の両方を画像に描画する
[keras-yolo3](https://github.com/qqwweee/keras-yolo3)を修正して、検出結果とアノテーション結果の両方を画像に描画します。
以下のようなスクリプトを追加しました。

```python
import json
from pathlib import Path

import PIL.Image
import PIL.ImageDraw

def draw_groud_truth(image: PIL.Image, image_filename:str, annotation_dir: str):
    """
    Ground Trutheを描画する
    :param image: PillowのImage
    :param image_filename: 画像のファイル名
    :param annotation_dir: アノテーションディレクトリのパス
    """
    json_path = Path(annotation_dir) / Path(f"{image_filename}.json")

    with open(str(json_path)) as f:
        json_data = json.load(f)

    if json_data["task_status"] != "complete":
        print("アノテーション作成が完了していない画像なので、Ground Truthを描画しないスキップする")
        return

    # airplaneのアノテーション情報を取得
    airplane_annotation_list = [annotation for annotation in json_data["details"] if annotation["label"] == "airplane"]
    draw_rectangle(image, airplane_annotation_list)

    return image


def draw_rectangle(image: PIL.Image, annotation_list):
    draw = PIL.ImageDraw.Draw(image)
    for annotation in annotation_list:
        data = annotation["data"]
        xy = (data["left_top"]["x"], data["left_top"]["y"], data["right_bottom"]["x"], data["right_bottom"]["y"])
        draw.rectangle(xy, outline=(255,0,0))

    return draw
```

---
### 描画後の画像
* 赤い矩形：アノテーション結果
* オレンジの矩形：検出結果（数値はスコア）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/b6b987a1-9bb1-8dd6-7c8d-cddee7296949.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/6266061e-ee09-cbc2-6995-563e9601a8d0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/93bb60d0-387c-0547-8a3f-7db436a35bcd.png)

物体検出モデルは、アノテーション結果に比べて、横幅が狭く検出されているように見えました（確認していない）。


---
## IoU(Intersection over union)、mPA(mean Average Precision)を算出

余力がないので、今回は省略します。
以下のツールを利用すれば、簡単にIoU, mPAを算出できるかも？（使っていない）
https://github.com/rafaelpadilla/Object-Detection-Metrics


---
# まとめ

* AnnoFabを使ってアノテーションを作成した
    * 飛行機を矩形で囲う
* YOLO v3の物体検出モデルで検出された結果と、アノテーション結果を画像に描画した

機械学習名古屋 第22回で、AnnoFabのハンズオンを実施します！



---
# 補足

---
## keras-yolo3を利用するのに必要なPythonパッケージ

```plain:Pipfile
[packages]
keras = "==2.1.5"
tensorflow = "==1.6.0"
h5py = "*"
pillow = "*"
matplotlib = "*"
opencv-python = "*"
```

tensorflowのバージョンが古いです…


---
## AnnoFabで作業時間などの統計情報を確認する
完了したタスク数や、作業時間を確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/091794a8-efa6-bd39-116f-244a1c06e63a.png)


---
## AnnoFabのWeb API
https://annofab.com/docs/api/

* [OpenAPI Spec v3で記載されたファイル](https://annofab.com/docs/api/swagger.yaml)が公開されています。
* [Pythonのクライアントライブラリ](https://pypi.org/project/annofabapi/)が公開されています



---
## 実行環境
* Xubuntu 18.04
* Python 3.6.8
* AnnoFab v0.53.1