オリジナルデータで物体検出を試してみたくなり, 久々にYOLOを触ってみることに...
YOLOは, 昨年少し触っていたYOLOv2からYOLOv3にバージョンアップしており, 今回はYOLOv3をPythonから利用する方法について, 少しまとめておく.
関連記事:
・YOLOv2を試してみる(1)
・YOLOv3を試してみる(2)
・YOLOv3を試してみる(3)
YOLOv3をPythonから利用する方法として, 二通り試してみた.
1) ctypesを使う. (darknet/python/darknet.py)
2) keras-yolo3を使う.
1. ctypes[1]
ctypesとは, pythonでC言語のライブラリを操作するためのライブラリである.
darknetのインストールディレクトリ下には, python/darknet.pyなるサンプルコードがあるので, これを使って物体検出を行ってみる.
今回初めてctypesを使うので, darknet.pyを参考に使い方を学ぶ.
1.1 ライブラリのロード
ライブラリをロードするには,
ctypes.CDLL(libname)
を使用する.
from ctypes import * lib = CDLL("libdarknet.so", RTLD_GLOBAL)
1.2 構造体の定義
Cの構造体に対応するクラスをpython側で定義するようだ.
# 矩形の定義 class BOX(Structure): _fields_ = [("x", c_float), ("y", c_float), ("w", c_float), ("h", c_float)] # 画像データの定義 class IMAGE(Structure): _fields_ = [("w", c_int), ("h", c_int), ("c", c_int), ("data", POINTER(c_float))]
1.3 関数の定義
引数や戻り値のない関数はそのまま利用することができるが, 引数や戻り値がある場合はPython側でデータ型を明記する必要があるようだ.
# network *load_network(char *cfg, char *weights, int clear) load_net = lib.load_network load_net.argtypes = [c_char_p, c_char_p, c_int] load_net.restype = c_void_p # image load_image_color(char *filename, int w, int h) load_image = lib.load_image_color load_image.argtypes = [c_char_p, c_int, c_int] load_image.restype = IMAGE
1.4 動作確認[2]
darknet.pyは, python 3系で動かすには若干の修正が必要である.
C関数の引数に文字列を渡す際に, c_char_pに対してstr型の"cfg/yolov3-test.cfg"を渡すようで, これをバイト列にしてやる必要がある.
ここで少しハマった!
if __name__ == "__main__": net = load_net(b"cfg/yolov3-test.cfg", b"backup/yolov3-test_final.weights", 0) meta = load_meta(b"cfg/test.data") r = detect(net, meta, b"test.jpg") for r0 in r: print(r0)
[画像]
[実行結果]
(b'Car', 0.998721182346344, (175.69290161132812, 230.9979248046875, 107.79170227050781, 69.38579559326172)) (b'Car', 0.955277144908905, (44.639244079589844, 235.98455810546875, 94.31153869628906, 41.028072357177734)) (b'Signs', 0.9252675175666809, (570.2070922851562, 146.4308624267578, 19.322128295898438, 16.191734313964844)) (b'Car', 0.8757637739181519, (439.9433898925781, 297.7780456542969, 431.86517333984375, 205.927001953125)) (b'Car', 0.7671501636505127, (108.61651611328125, 230.19583129882812, 78.11087799072266, 39.77518844604492)) (b'Signs', 0.7385135293006897, (349.7156066894531, 123.2014389038086, 22.234079360961914, 22.38388442993164)) (b'Signs', 0.5390903353691101, (610.5639038085938, 145.1051483154297, 18.0130672454834, 17.494369506835938))
2. keras-yoko3[3]
YOLOv3をkerasで動かそうという試みがいくつかある.
https://github.com/qqwweee/keras-yolo3
今回は, 上記を使って, YOLOv3の学習済モデルを試してみた.
2.1 モデル変換
YOLOv3の学習済モデルを利用するにあたり, モデルの重みを変換する必要がある.
python convert.py cfg/yolov3-test.cfg backup/yolov3-test_final.weights model_data/yolov3-test.h5
2.2 動作確認
yolo_video.pyに引数でモデル等のパスを渡せるようになっているが, どうもうまく処理されてないようなので, yolo.py内で定義されているデフォルトを修正する.
class YOLO(object): _defaults = { "model_path": 'model_data/yolov3-test.h5', "anchors_path": 'model_data/yolo_anchors.txt', "classes_path": 'model_data/test.names', "score" : 0.3, "iou" : 0.45, "model_image_size" : (416, 416), "gpu_num" : 1, }
[実行結果]
Input image filename:test.jpg (416, 416, 3) Found 9 boxes for img Signs 0.39 (602, 136) (620, 155) Signs 0.60 (339, 112) (361, 134) Signs 0.64 (561, 138) (580, 155) Truck 0.56 (149, 173) (314, 273) Car 0.78 (183, 188) (316, 278) Car 0.84 (69, 210) (147, 250) Car 0.93 (213, 191) (663, 402) Car 0.96 (0, 216) (92, 256) Car 1.00 (122, 196) (230, 266) 2.0341595780000716
YOLOv3をいろいろと試すためには, pythonから使えた方が便利と思い二通りの方法を試してみたが, 物体検出の結果が若干異なるようだ.
画像の前処理とか何か少し異なるのかな?
keras-yolo3も一応学習を行う仕組みもあるようなので, keras-yolo3で学習すればそういったズレもなくなるかも...
細かいことはさておき, まずはいろいろと試してみよう!!
----
[1] 16.16. ctypes — Pythonのための外部関数ライブラリ — Python 3.6.5ドキュメント
[2] darknet yolo v3をpython3(.5.2)で試す
[3] qqwweee/keras-yolo3: A Keras implementation of YOLOv3 (Tensorflow backend)
|
|
|
|