OpenCV+Pythonの組み合わせで人物検出器を動作させたときに、
クロック速度から予想される処理速度よりも、格段処理が遅いのを
Raspberry Pi B+で感じました。
その理由をメモします。
hog=cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
hogParams = {'winStride': (8, 8), 'padding': (32, 32), 'scale': 1.05}
human, r = hog.detectMultiScale(im, **hogParams)
detectMultiScale()というメソッドは、インテルのマルチコアのCPUでは複数のスレッドで検出処理をしているのです。
そのため、ARMのシングルコアのRaspberryPi B+では、複数のスレッドでは動作しないからです。
実際モジュールの方のhog.cppの記述をみると、以下のように画像のサイズごとに並列に検出処理しているのがわかります。
void HOGDescriptor::detectMultiScale(
const Mat& img, vector& foundLocations, vector& foundWeights,
double hitThreshold, Size winStride, Size padding,
double scale0, double finalThreshold, bool useMeanshiftGrouping) const
{
//中略
parallel_for_(Range(0, (int)levelScale.size()),
HOGInvoker(this, img, hitThreshold, winStride, padding, &levelScale[0], &allCandidates, &mtx, &tempWeights, &tempScales));
//後略
}
実際、Windowsの[タスクマネジャー]で[パフォーマンス]
で各コアの動作状況を見ていると、
detectMultiScale()時には、複数のコアが動作しているのが見て取れます。
それに対し、detect()では、そのような動作はしていません。
これは、C++のときもPythonのときも同じです。
Intel Threading Building Blocks(TBB)を用いた実装なので
RaspberryPi2のクアッドコアでは、別のマルチスレッドの実装をしない限り
クアッドコアの恩恵にはあずかれなさそうです。
追記:
cv::parallel_for_
の使い方について追加した参考資料を参照してください。
cv::parallel_for_
はIntel TBBが使えない環境では、別のフレームワークで、threadを管理するようです。
TBBでは、明示的にthreadの作成や終了を記述しないものとのことです。
追記:
OpenCV TBBによる並列処理に
TBBのインストール方法、OpenCVのCMake時の変更点が記されています。
Threading Building Blocks
を入手してから、CMakeするのは必須ですね。
OpenCV備忘録
Raspberry Pi 2でOpenCV 2.4.11をビルドした
[Raspberry Pi 2 で OpenCV 2.4.10 をビルドした]
(http://iwaki2009.blogspot.jp/2015/02/raspberry-pi-2-opencv-2410.html)
によると、Raspberry Pi 2でTBBをソースからインストールできるようです。後者の記事ではCMakeの設定が書かれています。
参考資料
「TBBによる処理の並列化と高速化」
http://opencv.jp/opencv2-x-tips/opencv_performance_with_tbb
「cv::parallel_for_を使ってみる」https://github.com/atinfinity/lab/wiki/cv::parallel_for_%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B