7
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[画像認識] 自動アノテーションした結果をVoTTで読み込む方法

Last updated at Posted at 2020-05-27

はじめに

機械学習で一番大事だけど面倒なのがアノテーション(教師ラベル作成)です。
画像認識だとVoTTなどのアノテーションツールが出ていますが、マウスでポチポチするのはやはり面倒。
ある程度ラベルを自動的に作成し、おかしいところだけ修正するようにできれば楽できそうです。

Active Learning機能 (VoTT)

そういう要望を叶えてくれる機能が実は世の中にはあって、例えばVoTTのActive Learning機能などがそうです。
VoTTのActiveLearning機能の紹介 - Qiita

ただし使用できる学習済みモデルは決まっていて、タスクによっては使えないこともあります。
私などはマルフク看板をアノテーションしたかったりするのですが、既存の物体検出用のモデルではさっぱりです。というか、だから自分でモデルを学習しようとしているのに。

というわけで、自分で好きなロジックやモデルを使って作成したラベルを、アノテーションツールで読み込めるように変換する方法をご紹介します。
例えば、OpenCVで作った以下のようなラベルをアノテーションツールで読み込み、必要なところだけ修正して深層学習に使うという方法も可能になります。

image.png
OpenCV shape detection - PyImageSearch

検証環境

  • Windows 10 Home (1903)
  • Python 3.6.8
    • pillow==7.1.2 (pipからインストール)
  • VoTT 1.7.2

記事を書いた2020年5月の時点で VoTT 2.1.0 がリリースされていますが、高機能になりすぎてプロジェクトの構造が複雑で、自分で作ったアノテーションを読み込ませるのが難しそうでした。
そのため、今回は古いバージョンである 1.7.2 で読み込みます。

手順

VoTTのインストール

VoTT 1.7.2を使います。vott-win.exe をダウンロードして、インストールしてください。
Release 1.7.2 · microsoft/VoTT

データの準備

適当な場所にフォルダを作成し、その直下にアノテーションしたい画像 (JPG or PNG) をまとめます。
ここではフォルダのフルパスを C:\foo\bar\myproj とします。
VoTT 1.7.2の場合、対応するプロジェクトファイルの名前は C:\foo\bar\myproj.json となります。

自動アノテーション結果の作成

make_vott_project.py
import sys
import json
import hashlib
import urllib
from pathlib import Path
from PIL import Image # pillow 7.1.2

imgdir = Path(sys.argv[1]).resolve()
projfile = imgdir.with_suffix(".json")

if projfile.exists():
    # 既存のプロジェクトを読み込む
    f = open(projfile, "r+")
    data = json.load(f)
else:
    # プロジェクトを新規作成する
    f = open(projfile, "w")
    data = {
        "frames": {},
        "framerate": "1",
        "inputTags": "mrfk", # タグリスト(カンマ区切り)
        "suggestionType": "track",
        "scd": False,
        "visitedFrames": [],
        "tag_colors": ["#0cc7ff"] # 領域の色(任意)
    }

with f:
    for imgfile in imgdir.glob("*.*"):
        if imgfile.suffix.lower() in [".jpg", ".png"]:
            if imgfile.name in data["frames"]:
                # エントリがある場合はスキップ
                continue
            else:
                # エントリがない場合、新規作成
                frame = []
                data["frames"][imgfile.name] = frame

            # 画像のサイズを取得
            img = Image.open(imgfile)
            w, h = img.size
            img.close()

            # 自分で検出した領域を列挙する(仮)
            points = [ # 頂点を辺でつながっている順に列挙する
                {"x": 0.0, "y": 0.0},
                {"x": w,   "y": 0.0},
                {"x": w,   "y": h},
                {"x": 0.0, "y": h}
            ]
            box = {  # 外接長方形
                "x1": min(p["x"] for p in points),
                "y1": min(p["y"] for p in points),
                "x2": max(p["x"] for p in points),
                "y2": max(p["y"] for p in points)
            }
            region = box.copy()
            region.update({
                "width": w,
                "height": h,
                "box": box,
                "points": points,
                "type": "rect",
                "tags": ["mrfk"], # 領域に付与するタグリスト
            })
            frame.append(region)

    # プロジェクトを保存
    f.seek(0)
    json.dump(data, f)

コマンドプロンプトから以下のように実行すると、各画像の全領域に mrfk というタグが付与されます。

python make_vott_project.py C:\foo\bar\myproj

VoTTでの編集方法

VoTT 1.7.2 を起動し、画像のアイコンをクリックし、C:\foo\bar\myproj フォルダを選択します。
プロジェクトのファイル名はフォルダ名から自動的に決まることにご注意ください。
image.png

以下の画面はそのまま Continue でOK
image.png

ラベルが画像全体に対してついています。左向き三角2個・右向き三角2個のボタンで画像を切り替えられます。
image.png

ラベルの修正をしたい場合は、左上の Regions Manipulation を選択してから、領域の四隅をドラッグ&ドロップします。
image.png

メニューの File → Save で上書き保存できます。
更新されたjsonファイルを読み込んで、適当に学習データを作ればよいですね。

カスタマイズ

OpenCVなど外部で作ったアノテーションを読み込ませる

# 自分で検出した領域を列挙する(仮)

の部分で、points に検出結果を入れてください。
領域の各頂点の座標を、辺でつながっている順番に指定していきます。

例えば以下のチュートリアルのコードを流用するなら
OpenCV shape detection - PyImageSearch

frame = []
# loop over the contours
for c in cnts:
    ()
    points = [{"x": p[0], "y": p[1]} for p in c]
    ()
    frame.append(region)

のようにすれば作れます。

多角形の領域を指定する

長方形ではない複雑な領域を指定したい場合は

            region.update({
                "width": w,
                "height": h,
                "box": box,
                "points": points,
                "type": "rect",
                "tags": ["mrfk"], # 領域に付与するタグリスト
            })

この部分を

            region.update({
                "width": w,
                "height": h,
                "box": box,
                "points": points,
                "type": "polygon", # ここを変更
                "tags": ["mrfk"], # 領域に付与するタグリスト
            })

に変更するだけです。
こうすると、1つの頂点を動かしたときに他の頂点が動かなくなります。以下のように、長方形ではない形状を作れます。
image.png

タグを複数作る

まず、以下の inputTags のところに名前をカンマ区切り文字列で指定して

    data = {
        "frames": {},
        "framerate": "1",
        "inputTags": "mrfk,chst,wide", # タグリスト(カンマ区切り)
        "suggestionType": "track",
        "scd": False,
        "visitedFrames": [],
        "tag_colors": ["#0cc7ff"] # 領域の色(任意)
    }

各領域の tags にはタグのリスト(カンマ区切り文字列ではなく、Pythonのリスト)を指定します。

            region.update({
                "width": w,
                "height": h,
                "box": box,
                "points": points,
                "type": "rect",
                "tags": ["mrfk", "chst"], # 領域に付与するタグリスト
            })

ご覧のように、ウィンドウ左下と画像のツールチップに反映されています。
image.png

既存の物体検出結果のクラスをさらに細分化したいといった場合には、inputTags だけを増やしておいて、各領域のクラス(タグ)はVoTTで編集するという使い方も可能です。

タグの色を変える

領域の色や左下のタグリストの文字色を変えたい場合は、以下の tag_colors に色のリストを指定すればOKです。

    data = {
        "frames": {},
        "framerate": "1",
        "inputTags": "mrfk,chst,wide", # タグリスト(カンマ区切り)
        "suggestionType": "track",
        "scd": False,
        "visitedFrames": [],
        "tag_colors": ["#ff4040", "#ffff40", "#008000"] # 領域の色(任意)
    }

以下のように好きな色で出せるようになります。(画像は自分でアノテーションを編集した後のものです)
image.png

7
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?