リアルタイム物体検出システムdarknetをpythonでサーバ化

  • 5
    Like
  • 0
    Comment

やりたいこと

darknet というリアルタイムで物体検出できるオープンソースがあって、
これがけっこうすごい!
これをpythonでサーバ化して、イメージファイルを送ったら、
とりあえず、オブジェクトの名前とスコアが返ってくるようにしたい

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

上記にチュートリアルとかあるので、まずはそちらをごらんください

前提

  1. darknetが動作すること
  2. python 2系統であること

動作環境

  • Ubuntu 14.04
  • python 2.7.13
  • darknetのリビジョン 1b001a7f58aacc7f8b751332d3a9d6d6d0200a2d そのため、最新のソースではバグが出る可能性はあります

ソースおよび動作方法

ソース

  1. https://github.com/komorin0521/darknet_server

動作方法

  1. darknetのチュートリアルを動作させれるようgit cloneしてmakeする できれば、darknet単独で予測が動くようにしてください (チュートリアルで利用するyolo.weightsを利用します)
  2. ソースって書いてあるソース一式をdarknetのフォルダにコピーしてください (libdarknet.soと同階層にserver.pyなど全てのファイル・フォルダをおいてください)
  3. 必要なモジュールをpipでインストールしてください
    (sudo) pip install -r requirements.txt
    著者はpyenv + pyenv-virtualenv環境を利用してます。
    sudo権限が必要な場合は、つけてください

  4. python server.py -cf ./cfg/yolo.cfg -df ./cfg/coco.data -wf ./yolo.weights -ud ./upload を実行してください
    うまくいけけばdarknetを単独で動作させた場合と同様に
    ネットワークがロードされます

確認方法

curlで以下のように画像ファイルをアップロードしてください

curl -XPOST -F file=@./data/person.jpg http://localhost:8080/detect

jsonで下記のように結果が返ってこればOKです!

{
  "result": [
    {
      "name": "dog",
      "score": 0.8622361421585083
    },
    {
      "name": "person",
      "score": 0.8603283762931824
    },
    {
      "name": "horse",
      "score": 0.8156660199165344
    }
  ],
  "status": "200"
}

いろいろと補足

githubのdarknetのところに、python/detector.pyがあったので、それを参考にしました。
この中身を見てみると、configファイルとweightload_netでロードしていて、load_metaにてメタ情報(といってもこの場合は、クラス名に一致するオブジェクト名(cfg/coco.datanames)を引っ張ってきているようでした。

さらに、ネットワークをロードしておいた上で、detectしている

また、結果を見てみると、N個の物体検出結果の配列で、
個々の検出結果はどうやら名前、スコア、バウンディングボックスの位置になっているっぽい

上記を前提にyolo.pyYoloクラスの初期化メソッドで
ネットワークをロードしておいて、
/detectが呼ばれたらdetectを呼ぶようにすればよいのかと思い、そのようにしています。

なお、サーバからのレスポンスについては、記事を書いた当初(2017年10月9日)では、名前とyoloのスコアを返していましたが、2017年10月11日にバウンディングボックスの値も返すようにしました。

また、記事を書いた当初はHOSTやポートをハードコーディングしていましたが
引数で受け取れるように変更してます。

Flaskも(無駄に?)class化したら、
ちょっとはまったけど、stackoverflowにて解決!
はまったポイントは、FlaskではURIの定義を@app.route('/hoge')で定義するけれど、@self.app.route('/detect')ってしたら、エラーになった。
解決策を探してみると、どうやら'add_url_rule`(初めて知った!)にてURIを定義すればよいとのこと。
めでたしめでたし。

2017/11/1 APIの仕様追加

yolo本家では、確信度はdetectionを行う際に指定していたので、
APIでも指定できるように変更しました。
なお、デフォルト値は、(本家と同様なはずの)0.25にしてます。

curl -XPOST -F thresh=0.1 -F file=@./data/person.jpg http://localhost:8080/detect

と、-Fオプションで指定可能で、値を小さくするとより多くの物体検出結果が帰ってきますが、その分ご認識も多くなるので、ご注意ください。

参考