Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

やりたいこと

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

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

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

前提

  1. darknetが動作すること
  2. python 2系統であること -> python3系統であること(18/08/11)

動作環境

  • Ubuntu 14.04 -> Ubuntu 16.04.4(18/08/11)
  • python 2.7.13 -> python 3.5.2
  • darknetのリビジョン 1b001a7f58aacc7f8b751332d3a9d6d6d0200a2d
    -> 9a4b19c4158b064a164e34a83ec8a16401580850

    最新のソースではバグが出る可能性はあります

ソースおよび動作方法

ソース

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

動作方法

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

  4. PYTHONPATH=${darknetPATH}/python python3 darknet_server.py -cf ./cfg/yolov3.cfg -df ./cfg/coco.data -wf ./yolov3.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/darknet.pyがあったので、それを参考にしました。
この中身を見てみると、configファイルとweightload_netでロードしていて、load_metaにてメタ情報(といってもこの場合は、クラス名に一致するオブジェクト名(cfg/coco.datanames)を引っ張ってきているようでした。

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

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

上記を前提にyolo.pydarknet.pyの中に定義したYoloクラスの初期化メソッドで
ネットワークをロードしておいて、
/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オプションで指定可能で、値を小さくするとより多くの物体検出結果が帰ってきますが、その分ご認識も多くなるので、ご注意ください。

# 2018/08/11 更新
1. python3対応しました。python2とpython3で、ctypesの定義が変わっていたことに気づきました。参考:darknet yolo v3をpython3(.5.2)で試す
2. yolov3対応.darknet側が更新されたので、現時点で最新版で動作することを確認しました。
3. 予測埋め込み画像の更新しました。完璧ではないですが、予測結果画像を少しyolo本家に似せるように修正しました。
20180811_180947_person_pred.jpg

参考

komorin0521
1989年(平成)生まれの 好きな言語: Python フォローされてない方からのコメントも大歓迎です! なお、投稿した記事は個人としてのものであり、所属する団体とは関係ございません。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away