web-dev-qa-db-ja.com

Viola-Jonesの顔検出は180kの機能を主張

Viola-Jonesの顔検出アルゴリズム の適応を実装しています。この技術は、画像内に24x24ピクセルのサブフレームを配置し、その後、可能なあらゆるサイズであらゆる位置にその中に長方形の特徴を配置することに依存しています。

これらの機能は、2つ、3つ、または4つの長方形で構成できます。次の例を示します。

Rectangle features

彼らは、網羅的なセットが180k以上であると主張しています(セクション2):

検出器の基本解像度が24x24であるとすると、長方形の特徴の網羅的なセットは非常に大きく、180,000を超えます。 Haarの基礎とは異なり、長方形の特徴のセットは完全すぎることに注意してください。

以下のステートメントは、このペーパーでは明示的に述べられていないため、私の側の前提です。

  1. 2つの長方形の機能は2つ、3つの長方形の機能は2つ、4つの長方形の機能は1つだけです。この背後にあるロジックは、強調表示された長方形の間のdifferenceを観察していることであり、色や輝度、またはその種の何かを明示的にではありません。
  2. フィーチャタイプAを1x1ピクセルブロックとして定義することはできません。少なくとも1x2ピクセルである必要があります。また、タイプDは少なくとも2x2ピクセルである必要があり、この規則は他の機能にも適用されます。
  3. 中央のピクセルは分割できないため、フィーチャタイプAを1x3ピクセルブロックとして定義することはできず、それ自体から減算することは1x2ピクセルブロックと同じです。このフィーチャタイプは、偶数の幅に対してのみ定義されます。また、フィーチャタイプCの幅は3で割り切れる必要があり、このルールは他のフィーチャにも適用されます。
  4. 幅および/または高さ0のフィーチャを定義することはできません。したがって、xおよびyを24マイナス機能のサイズ。

これらの仮定に基づいて、網羅的なセットを数えました。

const int frameSize = 24;
const int features = 5;
// All five feature types:
const int feature[features][2] = {{2,1}, {1,2}, {3,1}, {1,3}, {2,2}};

int count = 0;
// Each feature:
for (int i = 0; i < features; i++) {
    int sizeX = feature[i][0];
    int sizeY = feature[i][1];
    // Each position:
    for (int x = 0; x <= frameSize-sizeX; x++) {
        for (int y = 0; y <= frameSize-sizeY; y++) {
            // Each size fitting within the frameSize:
            for (int width = sizeX; width <= frameSize-x; width+=sizeX) {
                for (int height = sizeY; height <= frameSize-y; height+=sizeY) {
                    count++;
                }
            }
        }
    }
}

結果は162,336です。

Viola&Jonesが言う「180,000以上」を概算するために私が見つけた唯一の方法は、仮定#4を捨て、コードにバグを導入することです。これには、4行をそれぞれ次のように変更する必要があります。

for (int width = 0; width < frameSize-x; width+=sizeX)
for (int height = 0; height < frameSize-y; height+=sizeY)

結果は180,625になります。 (これにより、機能がサブフレームの右および/または下に触れるのを効果的に防ぐことに注意してください。)

当然のことながら、彼らは実装に誤りを犯したのでしょうか?表面がゼロのフィーチャを考慮することは意味がありますか?それとも間違った方法で見ていますか?

78
Paul Lammertsma

よく見ると、あなたのコードは私にとって正しいように見えます。これにより、元の作者に1つずれのバグがあったのではないかと思われます。誰かがOpenCVがそれをどのように実装するかを見るべきだと思います!

それでも、理解しやすくするための1つの提案は、最初にすべてのサイズを調べてからforループの順序を反転させ、次にサイズを指定して可能な場所をループすることです。

#include <stdio.h>
int main()
{
    int i, x, y, sizeX, sizeY, width, height, count, c;

    /* All five shape types */
    const int features = 5;
    const int feature[][2] = {{2,1}, {1,2}, {3,1}, {1,3}, {2,2}};
    const int frameSize = 24;

    count = 0;
    /* Each shape */
    for (i = 0; i < features; i++) {
        sizeX = feature[i][0];
        sizeY = feature[i][1];
        printf("%dx%d shapes:\n", sizeX, sizeY);

        /* each size (multiples of basic shapes) */
        for (width = sizeX; width <= frameSize; width+=sizeX) {
            for (height = sizeY; height <= frameSize; height+=sizeY) {
                printf("\tsize: %dx%d => ", width, height);
                c=count;

                /* each possible position given size */
                for (x = 0; x <= frameSize-width; x++) {
                    for (y = 0; y <= frameSize-height; y++) {
                        count++;
                    }
                }
                printf("count: %d\n", count-c);
            }
        }
    }
    printf("%d\n", count);

    return 0;
}

前の162336と同じ結果


それを確認するために、4x4ウィンドウのケースをテストし、すべてのケースを手動でチェックしました(1x2/2x1と1x3/3x1の形状は90度回転しただけなので同じように数えやすいです):

2x1 shapes:
        size: 2x1 => count: 12
        size: 2x2 => count: 9
        size: 2x3 => count: 6
        size: 2x4 => count: 3
        size: 4x1 => count: 4
        size: 4x2 => count: 3
        size: 4x3 => count: 2
        size: 4x4 => count: 1
1x2 shapes:
        size: 1x2 => count: 12             +-----------------------+
        size: 1x4 => count: 4              |     |     |     |     |
        size: 2x2 => count: 9              |     |     |     |     |
        size: 2x4 => count: 3              +-----+-----+-----+-----+
        size: 3x2 => count: 6              |     |     |     |     |
        size: 3x4 => count: 2              |     |     |     |     |
        size: 4x2 => count: 3              +-----+-----+-----+-----+
        size: 4x4 => count: 1              |     |     |     |     |
3x1 shapes:                                |     |     |     |     |
        size: 3x1 => count: 8              +-----+-----+-----+-----+
        size: 3x2 => count: 6              |     |     |     |     |
        size: 3x3 => count: 4              |     |     |     |     |
        size: 3x4 => count: 2              +-----------------------+
1x3 shapes:
        size: 1x3 => count: 8                  Total Count = 136
        size: 2x3 => count: 6
        size: 3x3 => count: 4
        size: 4x3 => count: 2
2x2 shapes:
        size: 2x2 => count: 9
        size: 2x4 => count: 3
        size: 4x2 => count: 3
        size: 4x4 => count: 1
38
Amro

すべて。ビオラとジョーンズの論文にはまだ混乱があります。

CVPR'01の論文では、次のことが明確に述べられています。

「具体的には、three種類の機能を使用します。atwoの値-rectangle featureは、2つの長方形領域内のピクセルの合計の差です。領域のサイズと形状は同じで、水平または垂直に隣接しています(図1を参照) 3つの長方形の特徴は、中央の合計から減算された2つの外側の長方形内の合計を計算します長方形。最後に4長方形の特徴」。

IJCV'04論文では、まったく同じことが述べられています。 だから、全部で4つの機能。しかし、不思議なことに、彼らは今回、包括的な機能セットが45396であると述べました!これは最終バージョンではないようです。ここでは、min_width、min_height、幅/高さの比率、さらには位置など、いくつかの追加の制約が導入されたと思います。

どちらの論文も his webpage でダウンロードできることに注意してください。

論文全体を読んでいないので、あなたの引用の文言が私に突き出ています

検出器の基本解像度が24x24であるとすると、長方形の特徴の網羅的なセットは非常に大きく、180,000を超えます。 Haarの基底とは異なり、長方形の特徴のセットは完全すぎることに注意してください。

「長方形の特徴のセットが過剰です」「網羅的なセット」

セットアップのように聞こえますが、たとえば、ゼロの長方形などの些細なケースを取り除くことにより、検索スペースをより効果的なセットに絞り込む方法について、紙の作家がフォローアップすることを期待しています表面積。

編集:または抽象的なヒントが示すように、何らかの機械学習アルゴリズムを使用します。完全なセットは、「合理的な」ものだけでなく、すべての可能性を意味します。

3
Breton

論文の著者がすべての仮定と調査結果において正しいという保証はありません。仮定#4が有効であると思う場合は、その仮定を維持して、理論を試してください。元の著者よりも成功する可能性があります。

2
Michael Dillon

かなり良い観察ですが、24x24フレームを暗黙的にゼロパッドするか、「オーバーフロー」して、回転シフトのように、または一部の機能を「些細な機能」と見なす可能性がある範囲外になったときに最初のピクセルの使用を開始する場合がありますそして、AdaBoostでそれらを破棄します。

さらに、コードのPythonおよびMatlabバージョン)を書いたので、自分でコードをテストできます(デバッグとフォローが簡単です)。

Python:

frameSize = 24;
features = 5;
# All five feature types:
feature = [[2,1], [1,2], [3,1], [1,3], [2,2]]

count = 0;
# Each feature:
for i in range(features):
    sizeX = feature[i][0]
    sizeY = feature[i][1]
    # Each position:
    for x in range(frameSize-sizeX+1):
        for y in range(frameSize-sizeY+1):
            # Each size fitting within the frameSize:
            for width in range(sizeX,frameSize-x+1,sizeX):
                for height in range(sizeY,frameSize-y+1,sizeY):
                    count=count+1
print (count)

Matlab:

frameSize = 24;
features = 5;
% All five feature types:
feature = [[2,1]; [1,2]; [3,1]; [1,3]; [2,2]];

count = 0;
% Each feature:
for ii = 1:features
    sizeX = feature(ii,1);
    sizeY = feature(ii,2);
    % Each position:
    for x = 0:frameSize-sizeX
        for y = 0:frameSize-sizeY
            % Each size fitting within the frameSize:
            for width = sizeX:sizeX:frameSize-x
                for height = sizeY:sizeY:frameSize-y
                    count=count+1;
                end
            end
        end
    end
end

display(count)