Coding Memorandum

プログラミングに関する備忘録

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

OpenCVのSURF実装

画像認識などで使われる局所特徴量SURFの特徴量記述は次の式で定義される。(ここではdx, dyの詳細は説明しない)

これを4x4領域のピクセル毎に求めて結合した64次元のベクトルがSURFとなる。

OpenCV(2.0以降)の該当コードは次のようになっている。

/* Construct the descriptor */
vec = (float*)cvGetSeqElem( descriptors, k );
for( kk = 0; kk < (int)(descriptors->elem_size/sizeof(vec[0])); kk++ )
    vec[kk] = 0;
double square_mag = 0;

/* 64-bin descriptor */
for( i = 0; i < 4; i++ )
    for( j = 0; j < 4; j++ )
    {
        for( y = i*5; y < i*5+5; y++ )
        {
            for( x = j*5; x < j*5+5; x++ )
            {
                float tx = DX[y][x], ty = DY[y][x];
                vec[0] += tx; vec[1] += ty;
                vec[2] += (float)fabs(tx); vec[3] += (float)fabs(ty);
            }
        }
        for( kk = 0; kk < 4; kk++ )
            square_mag += vec[kk]*vec[kk];
        vec+=4;
    }
}

/* unit vector is essential for contrast invariance */
vec = (float*)cvGetSeqElem( descriptors, k );
double scale = 1./(sqrt(square_mag) + DBL_EPSILON);
for( kk = 0; kk < descriptor_size; kk++ )
    vec[kk] = (float)(vec[kk]*scale);

求めた特徴量を正規化する処理が入っている(28-30行)。SURFの元論文には正規化に関する記述は見受けられなかったので、OpenCV特有の処理であるようだ。

以前にSURFを実装したNTL MM1では、Bag of FeaturesでSURF特徴量をクラスタリングして用いているが、正規化を行うか否かでクラスタリング結果が変わってくるはずである。ちゃんと検証したわけではないが、直観的に正規化を行わない方がよい結果が得られそうだと思い、このときは論文に合わせて正規化を行わなかった。

ちなみにOpenCV 1.1では次の実装となっている。

vec = (float*)cvGetSeqElem( descriptors, k );
for( kk = 0; kk < (int)(descriptors->elem_size/sizeof(vec[0])); kk++ )
    vec[kk] = 0;

/* 64-bin descriptor */
for( i = 0; i < 4; i++ )
    for( j = 0; j < 4; j++ )
    {
        for( y = i*5; y < i*5+5; y++ )
        {
            for( x = j*5; x < j*5+5; x++ )
            {
                float tx = DX[y][x], ty = DY[y][x];
                vec[0] += tx; vec[1] += ty;
                vec[2] += (float)fabs(tx); vec[3] += (float)fabs(ty);
            }
        }
        double normalize = 0;
        for( kk = 0; kk < 4; kk++ )
            normalize += vec[kk]*vec[kk];
        normalize = 1./(sqrt(normalize) + DBL_EPSILON);
        for( kk = 0; kk < 4; kk++ )
            vec[kk] = (float)(vec[kk]*normalize);
        vec+=4;
    }
}

正規化をピクセル毎に行っており、OpenCV 2.xとは異なった計算式となっている(19-23行)。ピクセル毎に正規化を行うことは、SURFの特性から考えてもあまり良い結果になりそうになく、事実OpenCV 2.0で修正されている。

本来SURFの計算では正規化の必要はなかったが、OpenCVの何らかの都合で正規化の処理が行われているのではないかと思う。OpenCV 1.1の方法は良くなかったんで、2.0から直しておきましたみたいな感じかなぁ。

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://msirocoder.blog35.fc2.com/tb.php/89-bd71c9c6
この記事にトラックバックする(FC2ブログユーザー)

FC2Ad

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。