はじめに
この記事はOpenCV Advent Calendar 2017 9日目の記事です。
Intel Movidius Neural Compute Stick (NCS)に関しては、説明致しません。日経のテクノロジーの記事等を参考にしてください。
また、SDKの環境構築は、私のOpenCV 備忘録の記事を参考にしてください。今回は、SDKに添付されているC++のサンプルコードを、OpenCVのAPIを使用して書き換える話ですが、まじめに説明すると非常に長くなるので、概略のみとなります。図表もありませんので、おもしろくはないと思います。
サンプルコードの概略
使用するサンプルコードは、ncsdk/examples/caffe/SqueezeNet/cpp/run.cpp です。
サンプルコードは、以下のファイルにより構成されています。
- build.sh (ビルドスクリプト)
- fp16.c (float と fp16 の変換ソース)
- fp16.h (上記のヘッダーファイル)
- run.cpp (サンプルプログラム本体)
- stb_image.h (画像ファイルを読み込むための汎用ライブラリのソース)
- stb_image_resize.h (画像のサイズを変更するための汎用ライブラリのソース)
OpenCV の API で書き換えると、fp16.c, fp16.h, stb_image.h, stb_image_resize.h の4つのファイルは不要になります。
ソースの説明
プロフラムは、以下の順で処理が行われています。
- デバイス初期化
- グラフデータの読み込み
- グラフデータを NCS に転送
画像データの読み込みと変換
4.1. ファイルの読み込み
4.2. ファイルのリサイズ
4.3. unsigned char から float への変換
4.4. RGB各画素値より平均値を減算し、RとBを入れ替える
4.5. float から fp16 への変換fp16 形式のデータをNCSに転送
fp16 形式で結果を取得
fp16 から float への変換
最大値のindexの探索
最大値とindexの表示
デバイスクローズ
- 上記で、青色で記載した 4.1-4.5,7,8 の処理を OpenCV の APIで置き換えます。
- 以下に、該当する部分のみ OpenCV の API で書き換えたソースを掲載します。
- 冒頭にOpenCVのインクルードファイルが必要です。
#include <opencv2/opencv.hpp>
画像データの読み込み処理
4.1-4.5 の処理を書き換えたものです。
cv::Mat mat = cv::imread(IMAGE_FILE_NAME);
cv::resize(mat, mat, cv::Size(networkDim, networkDim));
mat.convertTo(mat, CV_32F);
mat -= cv::Scalar(0.40787054*255.0, 0.45752458*255.0, 0.48109378*255.0);
cv::convertFp16(mat, mat16);
half* imageBufFp16 = (half*)mat16.data;
注:OpenCVでは画像の並びがBGRなので入れ替える必要はない
結果から最大値の取得
7,8 の処理を書き換えたものです。
cv::Mat mat16res(cv::Size(1, numResults), CV_16SC1, resultData16);
cv::Mat mat32;
cv::convertFp16(mat16res, mat32);
double maxVal;
cv::Point maxLoc;
cv::minMaxLoc(mat32, NULL, &maxVal, NULL, &maxLoc);
printf("Index of top result is: %d\n", maxLoc.y);
printf("Probability of top result is: %f\n", maxVal);
ビルドコマンド
g++ run.cpp -o run -lmvnc `pkg-config --cflags opencv` `pkg-config --libs opencv`
結果
オリジナルのソースをOpenCV の API に変更することにより、コードがすっきりとし読みやすくなったが
オリジナルの計算結果
Index of top result is: 546
Probability of top result is: 0.969727
に対して、OpenCV版では、
Index of top result is: 546
Probability of top result is: 0.991211
となり indexは同じであるが、最大値が異なる結果となった。
補足
- cv::convertFp16(OpenCV) と floattofp16(fp16.c) や fp16tofloat(fp16.c) は、特定のデータで結果が同じになることを別途確認している。
- 結果が異なる理由は、cv::resize と stbir_resize_uint8 のリサイズ結果を合わせることができなかったためと推測している。
最後に
- ここで省略した内容は、ブログの方に補足として書いていく予定である。
- 明日は、dandelion1124 さんの番です。タイトルは未定ですが楽しみにしています。