#はじめに
YOLOv3をPythonから呼び出してみようと思います。
YOLOv3(darknet)をpythonから呼び出すサンプルであるdarknet.pyは、呼び出しにctypesを使っています。ctypesはpythonからCを呼び出す標準のライブラリです。
Windowsからdarknetを使用するには、yolo_cpp_dll.dll
を準備しなければいけません。
ここでは、その準備と、実際にpythonから呼び出してみることをやってみます。
なぜ、Windowsを使っているかというのは、WindowsのデスクトップアイコンをYOLOv3で識別する実験をしているからです。
#前提
「Yolo v3+Windows 10でデスクトップのアイコンを識別してみる その1」などに従ってWindowsでYOLOv3をビルドすることができている(やり方を理解できている)ことを前提としています。
#環境
- Windows10 Pro
- Visual Studio 2017
- CUDA 10.0
- cuDNN 7.3.0.29
- OpenCV 4.1.1
#DLLをビルドする
最初に、VSのソリューションを開きます。
ソリューションは、下記にあります。
[配置先]\darknet\build\darknet\yolo_cpp_dll.sln
ソリューションプラットホームをReleaseとx64に変更して、前記事と同様に、CUDAとOpenCVのインクルードディレクトリを追加します。
ビルドすると、yolo_cpp_dll.dll
が出来上がります。
[配置先]\darknet\build\darknet\x64
まで移動して、以下のコマンドを実行してみましょう。
python darknet.py
#解説
####ctypes
ctypesはC言語と互換性のあるデータ型を提供し、動的リンク/共有ライブラリをPythonでラップすることができるようにするPython標準の外部関数ライブラリです。
呼び出し方には、標準 cdecl 呼び出し規約を用いて関数をエクスポートしているライブラリをロードするCDLL
と、stdcall 呼び出し規約を用いる関数を呼び出すWinDLL
の2種類があります。
cdeclとstdcallの違いについては、ここでは詳しく言及しません。ざっくりいうとメモリの確保と解放を呼び出し元、呼び出し先どちらでするかの規約です。
darknet.pyでは以下のようにDLLを呼び出しています。
from ctypes import *
...
...
winGPUdll = os.path.join(cwd, "yolo_cpp_dll.dll")
...
...
lib = CDLL(winGPUdll, RTLD_GLOBAL)
CDLL
を使ってるので、cdecl規約で呼び出しています。ソリューションで、そのような設定になっているかを確認してみましょう。
確かにcdeclになっていますね。
それから、CDLL
で読み込んだlib
をつかって、Cを呼び出しています。
lib.network_width.argtypes = [c_void_p]
lib.network_width.restype = c_int
def network_width(net):
return lib.network_width(net)
ここで呼び出されているnetwork_width
は、Cでは、以下の通り定義されています。
LIB_API int network_width(network *net);
これを見るとわかるように、Pythonからctypesを使う際は、まず、argtypes
とrestype
でそれぞれ、引数の型と戻り値の型を指定し、それから、関数を呼び出す、という手順を踏みます。
引数の型にc_void_p
を、戻り値にc_int
を指定しています。
####darknet.py
下記の関数がまず呼ばれます。
def performDetect(imagePath="data/dog.jpg", thresh= 0.25, configPath = "./cfg/yolov3.cfg", weightPath = "yolov3.weights", metaPath= "./cfg/coco.data", showImage= True, makeImageOnly = False, initOnly= False):
上のほうで動作させたのはすべてデフォルトのパラメータです。
この関数では最初にパラメータのチェックをしています。チェックに成功したら、次の関数を呼び出して認識を行ってます。
detections = detect(netMain, metaMain, imagePath.encode("ascii"), thresh)
この関数の中で何をやっているかというと、
def detect(net, meta, image, thresh=.5, hier_thresh=.5, nms=.45, debug= False):
im = load_image(image, 0, 0)
if debug: print("Loaded image")
ret = detect_image(net, meta, im, thresh, hier_thresh, nms, debug)
free_image(im)
if debug: print("freed image")
return ret
画像を読み込んで、detect_image
を呼び出しています。
この関数は何をしているかというと、
predict_image(net, im)
predict_image
を呼び出しています。ここでやっと、Cの関数が呼び出されます。predict_image
は以下の通り定義されいます。
predict_image = lib.network_predict_image
predict_image.argtypes = [c_void_p, IMAGE]
predict_image.restype = POINTER(c_float)
やっとこさ、ctypesでの呼び出しが出てきました。ついでにCの実装を見ておきましょう。
float *network_predict_image(network *net, image im)
{
//image imr = letterbox_image(im, net->w, net->h);
float *p;
if(net->batch != 1) set_batch_network(net, 1);
if (im.w == net->w && im.h == net->h) {
// Input image is the same size as our net, predict on that image
p = network_predict(*net, im.data);
}
else {
// Need to resize image to the desired size for the net
image imr = resize_image(im, net->w, net->h);
p = network_predict(*net, imr.data);
free_image(imr);
}
return p;
}
確かに、引数がポインタとイメージで戻り値がfloatですね。
pythonでdarknetを呼びだすときは、この辺りを参考にすればよさそうです。
#デスクトップを識別してみる
前回訓練させたweightsを使用して、デスクトップの識別をpythonから呼び出してみましょう。
コマンドプロンプトからpython
を起動して、以下のようにperformDetect
を呼び出します。フルパス指定しているので少し長いです・・。パスは適宜読み替えてください。
>>> from darknet import performDetect
>>> performDetect("D:/Projects/python/desktopyolov3/data/datasets/Desktop006.jpg", 0.25, "D:/Projects/python/desktopyolov3/cfg/yolov3-voc.cfg", "D:/Projects/python/desktopyolov3/data/backup/yolov3-voc_last.weights", "D:/Projects/python/desktopyolov3/data/desktop.data")
以下の通り識別が動作しました。
大成功です。
#つづく
次回は、ここでビルドしたDLLを使ってC++からYOLOv3を呼び出して、その場所のアイコンをゴミ箱に移動させるやつを作ろうと思います。
YOLOv3シリーズは以下から参照できます。
Yolo v3+Windows 10でデスクトップのアイコンを識別してみる その1
https://qiita.com/yasunari_matsuo/items/78695e9f53bc6b589daa
(おまけ)Yolo v3+Windows 10でデスクトップのアイコンを動的に識別してみる
https://qiita.com/yasunari_matsuo/items/f0989523849f6ae40483#_reference-8747cd277d7aeccfdef1
AIでデスクトップアイコンを自動削除してくれるツールを作ったった(YOLOv3+Windows 10)
https://qiita.com/yasunari_matsuo/items/2ac2140e7ac250304d4a