[algorithm] Viola-Jones의 얼굴 감지 기능으로 180k 기능 주장

저는 Viola-Jones의 얼굴 감지 알고리즘을 적용했습니다 . 이 기술은 이미지 내에 24×24 픽셀의 서브 프레임을 배치 한 다음 가능한 모든 크기로 모든 위치에 직사각형 특징을 배치하는 데 의존합니다.

이러한 기능은 2 개, 3 개 또는 4 개의 직사각형으로 구성 될 수 있습니다. 다음 예가 표시됩니다.

직사각형 기능

그들은 완전한 세트가 180k 이상이라고 주장합니다 (섹션 2) :

감지기의 기본 해상도가 24×24라는 점을 감안할 때 전체 직사각형 기능 집합은 180,000 이상으로 상당히 큽니다. Haar 기반과 달리 직사각형 기능 세트가 과도하게 완성되었습니다.

다음 진술은 논문에 명시 적으로 언급되지 않았으므로 내 입장에서 가정 한 것입니다.

  1. 2 개의 직사각형 피처 2 개, 3 개의 직사각형 피처 2 개, 4 개 직사각형 피처 1 개만 있습니다. 이것의 논리는 명시 적으로 색상이나 휘도 또는 그런 종류의 어떤 것도 아닌 강조 표시된 사각형 사이 의 차이 를 관찰 한다는 것입니다.
  2. 특징 유형 A를 1×1 픽셀 블록으로 정의 할 수 없습니다. 최소 1×2 픽셀 이상이어야합니다. 또한 유형 D는 2×2 픽셀 이상이어야하며이 규칙은 다른 기능에 따라 적용됩니다.
  3. 중간 픽셀은 분할 할 수 없기 때문에 특성 유형 A를 1×3 픽셀 블록으로 정의 할 수 없으며 자체에서 빼는 것은 1×2 픽셀 블록과 동일합니다. 이 기능 유형은 짝수 너비에 대해서만 정의됩니다. 또한 피처 유형 C의 너비는 3으로 나눌 수 있어야하며이 규칙은 다른 피처에 따라 유지됩니다.
  4. 너비 및 / 또는 높이가 0 인 특성은 정의 할 수 없습니다. 따라서 xy 를 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를 삭제하고 코드에 버그를 도입하는 것입니다. 여기에는 네 줄을 각각 다음과 같이 변경하는 작업이 포함됩니다.

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

결과는 180,625 입니다. (이렇게하면 기능이 서브 프레임의 오른쪽 및 / 또는 하단에 닿지 않도록 효과적으로 방지 할 수 있습니다.)

당연히 질문 : 구현에서 실수를 했습니까? 표면이 0 인 피쳐를 고려하는 것이 합리적입니까? 아니면 잘못된 방향으로보고 있습니까?



답변

자세히 살펴보면 귀하의 코드가 저에게 맞는 것처럼 보입니다. 이것은 원저자가 하나의 버그를 가지고 있는지 궁금하게 만듭니다. 누군가 OpenCV가 그것을 구현하는 방법을보아야한다고 생각합니다!

그럼에도 불구하고 이해하기 쉽도록하기위한 한 가지 제안은 먼저 모든 크기를 검토 한 다음 주어진 크기에 대해 가능한 위치를 반복 하여 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


이를 확인하기 위해 4×4 창의 케이스를 테스트하고 모든 케이스를 수동으로 확인했습니다 (1×2 / 2×1 및 1×3 / 3×1 모양이 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


답변

모두. Viola와 Jones의 논문에는 여전히 약간의 혼란이 있습니다.

그들의 CVPR’01 논문에는

“좀 더 구체적으로 말하자면, 우리는
종류의 특징을 사용 합니다. 두 개의 직사각형 특징 의 값은
두 직사각형 영역 내의 픽셀 합계의 차이입니다. 영역은 크기와 모양이 같고 수평 또는 수직으로 인접합니다 (그림 참조). 1)
세 개의 직사각형 특성 은 중앙 직사각형의 합계에서 뺀 두 외부 직사각형 내의 합계를 계산합니다. 마지막 으로 네 직사각형 특성 “.

IJCV’04 논문에서도 똑같은 말이 있습니다. 총 4 개의 기능이 있습니다 . 그러나 이상하게도 이번에는 완전한 기능 세트가 45396이라고 말했습니다! 이것이 최종 버전이 아닌 것 같고 여기에 min_width, min_height, width / height ratio, even position과 같은 몇 가지 추가 제약이 도입 된 것 같습니다.

두 문서 모두 그의 웹 페이지에서 다운로드 할 수 있습니다 .


답변

논문 전체를 읽지 못한 채 당신의 말이 튀어 나와

감지기의 기본 해상도가 24×24라는 점을 감안할 때 전체 직사각형 기능 집합은 180,000 이상으로 상당히 큽니다. Haar 기반과 달리 직사각형 기능 세트가 과도하게 완성되었습니다.

“사각형 기능 세트가 과도합니다” “완전 세트”

마치 설정처럼 들리는데, 종이 작성자가 검색 공간을 더 효과적인 세트로 뽑아내는 방법에 대한 설명을 추가 할 것으로 예상됩니다. 예를 들어 0이있는 직사각형과 같은 사소한 경우를 제거하는 방법 표면적.

편집 : 또는 추상적 인 힌트처럼 어떤 종류의 기계 학습 알고리즘을 사용합니다. 철저한 세트는 “합리적인”가능성뿐만 아니라 모든 가능성을 의미합니다.


답변

논문의 저자가 모든 가정과 결과가 정확하다는 보장은 없습니다. 가정 # 4가 타당하다고 생각되면 그 가정을 유지하고 이론을 시도하십시오. 당신은 원저자보다 더 성공할 수 있습니다.


답변

꽤 좋은 관찰이지만, 24×24 프레임 또는 “오버플로”를 암시 적으로 0으로 채우고 회전 이동에서와 같이 경계를 벗어날 때 첫 번째 픽셀을 사용하기 시작하거나 Breton이 말한대로 일부 기능을 “사소한 기능”으로 간주 할 수 있습니다. AdaBoost로 폐기하십시오.

또한 Python 및 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 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)


답변

2001 년 원본 논문에서는 다음과 같은 세 가지 기능 만 사용한다고 언급합니다.

세 가지 기능을 사용합니다.

또한

영역의 크기와 모양이 동일합니다.

각 종류에는 두 가지 방향이 있기 때문에 총 6 개의 기능 (적어도 총 기능 수 계산을 위해)을 사용한다고 가정하는 것이 합리적입니다 : 2 개의 직사각형 기능 2 개, 3 개의 직사각형 기능 2 개 및 4 개의 직사각형 기능 2 개. 이 가정에는 실제로 180,000 개 이상의 기능이 있습니다.

feature_types = [(1,2), (2,1), (1,3), (3,1), (2,2), (2,2)]
window_size = (24,24)

total_features = 0
for f_type in feature_types:
    for f_height in range(f_type[0], window_size[0] + 1, f_type[0]):
        for f_width in range(f_type[1], window_size[1] + 1, f_type[1]):
            total_features += (window_size[0] - f_height + 1) * (window_size[1] - f_width + 1)

print(total_features)
# 183072

네 개의 직사각형 유형의 특성 (나중에 발표 된 것처럼 보임) 하나를 드롭하면 총 특성 수는 162,336 개입니다.


답변