2013年11月19日火曜日

OpenCVでHOG特徴量+SVMで人物検出を行う 1

以前サンプルを動かしてみたが、独自の辞書作成のためにOpenCVのHOGを調査している。

(現在2.4.7になっており内容が異なっているので、2.4.6限定の話である。
また、調査した時期も数カ月前なのでoclを考慮していない)


OpenCV2.4.6のHOGのソースは、
modules\objdetect\src\hog.cpp
であり、CPU版のサンプルは、
samples\cpp\peopledetect.cpp
GPU版のサンプルは、
samples\gpu\hog.cpp
である。

OCL版も準備されているが、OCLの環境がないため無視する。


CPU版のソースをみると計算される特徴量は、
INRIA Object Detection and Localization Toolkit
      (http://pascal.inrialpes.fr/soft/olt/)
と互換性があるとのことだが、オリジナルが英語なので現在未読である。


サンプルプログラムの内容
CPU版のサンプルプログラムで、HOG関連をひらっていくと

インスタンスの作成
Line48で、HOGDescriptor hog;

辞書の設定
Line49で、hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());

検出処理
Line79で、hog.detectMultiScale(img, found, 0, Size(8,8), Size(32,32), 1.05, 2);

検出結果は、cv::vector<Rect> foundに格納される

検出した領域の重複検査を行い、重複がない場合のみ、cv::vector<Rect> found_filteredに格納されている。(Line 83-91)

また、オリジナルの辞書は、人の周りの余白が多いため、表示の時に検出された領域を縮小している。(Line 92-102)

以上のような処理を行っている。


HOG関数
なぜか、CPU版のドキュメントは準備されていない。Webで検索するとGPU版の説明のみHitする。

HOGDescriptorには、各種パラメータが設定できるようになっているが、コードの実装は固定値を使用しており、自由に変更できない
CELLサイズ 8x8のみサポート
BLOCKサイズ 16x16のみサポート
BINサイズ 9bins
BLOCK移動量 CELLサイズの整数倍

また、入力画像にガンマ補正処理のフラグがあり、デフォルトではtrueとなっている

Line49 API名は、setSVMDetectorとなっているが、HOGDescriptor::getDefaultPeopleDetector()の戻り値は、static std::vector<float>であり、
実際の処理は検出用の辞書データを設定している。

CPU版のソースでgetDefaultPeopleDetectorをみてみると

vector<float> HOGDescriptor::getDefaultPeopleDetector()
{
    static const float detector[] = {

以下 辞書データをそのままfloatの配列に書き込んでいる



一見、辞書の差し替えができる構造に見えるが、辞書作成用のHOG + SVMのツールは、提供されていないので、INRIA Object Detection and Localization Toolkitで
自力で作成する必要がある。

あとドキュメント化されていないようだが、getDefaultPeopleDetectorの辞書に登録されている画像データのサイズは64x128画素であり、
この大きさより、小さい人物を検出したい場合は、対象の画像を拡大しないといけない。

拡大すると、検出精度が低下するため、別途48x96画素の辞書データが準備されている
その場合、HOGDescriptor::getDaimlerPeopleDetector()を使用しないといけない


HOG関数内での基本処理

ガンマ補正
縦、横の3x3のsobelフィルター
角度と長さの計算
blockのヒストグラム計算
ヒストグラムの正規化
SVMの計算


マルチスケールで各スケール画像で領域を検出した後、領域を統合する必要がある
計算コストの関係で、meansiftが使用されるとのこと

ソース内部でも

    if ( useMeanshiftGrouping )
    {
        groupRectangles_meanshift(foundLocations, foundWeights, foundScales, finalThreshold, winSize);
    }
    else
    {
        groupRectangles(foundLocations, (int)finalThreshold, 0.2);

のように使用されている

groupRectangles_meanshiftは、cascadedetect.cppで定義されており、自作プログラムからは、cv::groupRectangles_meanshiftで呼び出すことが可能である。
しかし、ドキュメントには説明はないので、なくなる可能性もある

//new grouping function with using meanshift
static void groupRectangles_meanshift(vector<Rect>& rectList, double detectThreshold, vector<double>* foundWeights,
                                      vector<double>& scales, Size winDetSize)


関数内部では、MeanshiftGroupingクラスが使用されており、計算はこのクラスで行っているようだ。


関連ドキュメント



0 件のコメント:

コメントを投稿