DarkNetで高速検出をPythonで書いてみる
はじめに
久しぶりに物体検出向けフレームワークであるDarkNetを触ってみました。
DarkNetそのものはC言語で記述されており、C言語でバリバリ書けるぜと言う方にはオススメしない記事です。
PythonでDarkNetでのテスト画像の物体検出ができるのか試してみました。
コマンドでの検出(detector.c)
検出したいテスト画像単体を指定する場合は以下のコマンドで実行できます。
この場合だとC言語のプログラム(./examples/detector.c)が動作しますので、あらかじめmakeしておく必要があります。
OPTIONが動作しない場合は(./examples/darknet.c)を開いて使用できる引数コマンドを確認してみてください。
$ ./darknet detector test <data> <cfg> <weights> data/test.jpg(検出したい画像) [OPTION]
複数枚の画像を一括で検出したい場合は以下のコマンドです。
input.txtには複数枚の画像を格納したパスを列挙したtxtを指定します。
$ ./darkent detector test <data> <cfg> <weights> [OPTION] < input.txt
input.txt
data/obj/1.jpg data/obj/2.jpg . .
Pythonでの検出
コードを動作させる上で以下のファイルが必要です。「from ctypes import *」「lib = CDLL("darknet/libdarknet.so", RTLD_GLOBAL)」で、libdarknet.soをロードし、Python3でDarkNetを利用できるようになっています。
- libdarknet.so
- backupフォルダに格納されたweightsファイル(backup/yolov2-voc_50000.weights")
- cfg/obj.data(クラスが列挙されたファイル)
- cfg/yolov2.cfg(YOLOネットワークの情報を記載したファイル)
- ./result/output/*.jpg(対象画像)
詳しいコードは上記にて載せています。今回はクラス個数=1としていますが、クラス数≥2の場合も後日記述したいと思います。
以下のdetect関数内で検出領域で最も確率が高いオブジェクトが検出領域の座標と共にが返されています。
def detect(net, meta, image, thresh=.1, hier_thresh=.5, nms=.45): ・・・ res.append((meta.names[i], dets[j].prob[i], (b.x, b.y, b.w, b.h))) ・・・
各検出領域に対して”出力クラス+領域の座標”の情報が配列として格納されています。
こちらでは入力した検出対象の画像(.jpg)と検出領域を可視化した画像(.jpeg)で出力できるようにしています。
for _img in imglist: _resultimg = _img.replace("jpg","jpeg") img = imread(_img) _h,_w,_ = img.shape r = detect(net, meta, img) for i in r: x, y, w, h = i[2][0], i[2][1], i[2][2], i[2][3] xmin, ymin, xmax, ymax = convertBack(float(x), float(y), float(w), float(h)) class = i[0] # 出力クラス pt1 = (xmin, ymin) pt2 = (xmax, ymax) cv2.rectangle(img, pt1, pt2, (0, 255, 0), 2) print("{:.6f} {:.6f} {:.6f} {:.6f}".format(x/_w, y/_h, w/_w, h/_h)) # AnnotationFIleを生成したい方は出力情報をtxtファイルに書込+保存 cv2.imwrite(_resultimg, img)