YOLOを使ってドアラ検出〜前編〜

はじめに

手軽に物体検出を試したいなあと思って手を出した次第であります。
そこで今回は某名古屋球団のマスコットである愛らしいドアラの検出をします。

DarkNet

今回の主役「DarkNet」

スクリーンショット 2019-10-20 18.08.53.png

これがDarkNetのサイト。
「なんか厨二くさいサイトは・・・」と思うかもしれませんが、こいつが今回の主役です。

DarkNetでは画像検出に用いるアルゴリズムを楽に動かして画像検出の為のプロセスを最小限に抑えてくれてます。

画像検出アルゴリズム「YOLO」

YOLO(You Only Look Once)とは、深層学習を基礎とした一般検出技術です。一般検出技術にはR-CNNやFast R-CNNなどいくつかあるそうですが、YOLOの強みはやはり速度です。動画からリアルタイムでの物体検出ができます。

YOLOの特徴

YOLOは与えた入力画像から、

  • オブジェクトに近い候補領域を切り出し
  • それぞれの候補領域でのクラス確率を算出

高いクラス確率を出力した候補領域を元に、検出対象を以下のように矩形で囲います。
R-CNNでは上記の二点を順番に実行しますが、YOLOでは同時に実行できることが高速な物体検出の秘訣です。

#画像検出までの道のり
主な作業は7段階です。
一番面倒な作業は「教師データの作成(アノテーション)」です。ここは本当に作業ゲー。
Part1では太字のところまで説明していきます。

DarkNetをInstall

githubを通じて取得できます。
[Darknet]フォルダが生成されるのを確認してください。

$ git clone https://github.com/preddle/darknet.git

アノテーションソフトをInstall

アノテーションソフトとは・・・
教師データを作成する際に、入力画像に付随するメタデータの作成を手助けしてくれます。
ここでのメタデータは画像に対して、対象クラス名(ex. dog, cat etc...)と画像中の選択領域の座標(=検出したいオブジェクトらしい対象領域)のことを指します。

今回はYOLOを用いた画像検出ですので、YOLOに合った教師データを作る必要があります。
以下のように画像の領域を①分類クラス②領域座標に変換してくれます。

今回はアノテーションソフトにLabelImgを使用します。
LabelImgの使い方
takesan.hatenablog.com

$ git clone https://github.com/tzutalin/labelImg.git

$ sudo apt install pyqt5-dev-tools

$ sudo apt install python3-pip

$ sudo pip3 install lxml

$ cd labelImg

$ make qt5py3

Anaconda環境で作業されてる方は、condaコマンドでpyqt5をインストールできないかもしれません。
その場合、pyqt5のインストールについて詳しく書かれているサイト(以下)を参考にされてはいかがでしょうか。
githubja.com

LabelImg/dataの中にあるpredefined_class.txtを修正します。
こちらはデフォルトで20のクラスが登録されているのですが、
自分で新たにクラスを作成する場合には厄介となるので、自分が学習したいクラス名だけ登録しておきます。

predefined_class.txt

dog

ここで一瞬PythonコマンドでlabelImgディレクトリ下にあるlabelImg.pyを実行してやらないといけません(コードは書いていない)。

#current -> ~/labelImg

$ python labelImg.py

LabelImgでアノテーション画面が開けます。
参考サイト

Labelmg導入
qiita.com

LabelImg活用方法
symfoware.blog.fc2.com

Anacondaを用いたPyqt5導入
haitenaipants.hatenablog.com


教師データの作成

教師データ

一般的には教師データはGithubからダウンロードしたDarknet/dataに格納します。
今回はドアラの画像をDarknet/data/doara(適宜変更)に格納しました。

アノテーション

アノテーションについては前回にて参照。
アノテーションはLabelImgを用いて作業していきます。

その前に・・・
オリジナルのクラスに検出させたい時、labelImg/data/predefined_class.txtを全て削除し、オリジナルクラス名(日本語不可)に書き換えます。今回はドアラを検出したいので、クラス名はdoaraとします。

(デフォルトで入力されているクラス名を削除)
-dog
-cat
-airplane
・・・
 
+doara 

アノテーションの流れ

  • 左上の[OpenDir]より、Darknet/data/doaraを選択すると、アノテーションを開始できます。
  • YOLOを用いる場合、「Pascal VOC」→「YOLO」へ設定してください。
  • [Create¥nRectBox]より検出したい領域を矩形で囲む事ができます。
  • AutoSaveモードにすると保存が楽([View]→[Autosave]にチェック)
  • [Save]
  • [Next Image]


スクリーンショット 2020-02-08 16.45.47.png

こんな感じ

アノテーションで、検出オブジェクトらしい領域の座標をtextファイルに出力しました。
ここまでくれば、DarkNetにてアノテーション作業で作成したメタデータ(座標text+クラス名)を読み込ませ、DarkNetでのハイパーパラメータを調節して学習させるだけです。

メタデータには数字の羅列が書き込まれています。

Darknet/data/doara/image01.txt

クラス番号(ex.0,1,2・・・)  矩形の四隅の座標

これを教師データの画像分だけ繰り返します。
アノテーションは面倒ですが、丁寧に数多くやると精度は向上します。

全画像のパスをファイルに書き込む

教師画像(.jpg)と座標データ(.txt)がDarknet/data/doaraには存在しています。
今から教師画像のパスを新たに作成するPATHファイル(.txt)に書き込みます。そしてDarknetはこのPATHファイル(.txt)を通じて教師画像の場所を見つける事になります。

以下のDarknet/data/doara/make_PATH.pyで簡単にPATHファイルを生成できます。
今回は拡張子がjpgの状態の画像を対象としています。
他の拡張子で試される方は、以下のスクリプトの"jpg"の部分を書き換えるといいでしょう。

Darknet/data/doara/make_PATH.py

import glob, os

#現在のディレクトリを取得
current_dir = os.path.dirname(os.path.abspath(__file__))+'/'

#全画像に対してテストデータ(:訓練データ)の比率[%]を設定
percentage_test = 10;

#PATHファイルのファイル名設定
file_train = open('train2020.txt', 'a')  
file_test = open('test2020.txt', 'a')

#教師画像のパスをPATHファイルに書き込み
#画像の拡張子に注意(今回はjpg version)
counter = 1  
index_test = round(100 / percentage_test)  
for pathAndFilename in glob.iglob(os.path.join(current_dir, "*.jpg")):
    #ファイル名からtitleと拡張子を分割  
    title, ext = os.path.splitext(os.path.basename(pathAndFilename))

    if counter == index_test:
        counter = 1
        file_test.write(current_dir + title + '.jpg' + "\n")
    else:
        file_train.write(current_dir + title + '.jpg' + "\n")
        counter = counter + 1

Terminal

#current -> ~/Darknet/data/doara

$ python make_PATH.py

すると教師画像のパスを列挙したPATHファイル(この場合、train2020.txtとtest2020.txt)が生成されます。
上記のmake_PATH.pyをそのまま実行した場合、Darknet/data/doara/train2020.txtとDarknet/data/doara/test2020.txtがきちんと存在しているはずです。

Part1はここでひとまず終わりです。
次回
melheaven.hatenadiary.jp