Tính năng phát hiện khuôn mặt của Viola-Jones tuyên bố 180k


84

Tôi đang triển khai một bản điều chỉnh của thuật toán phát hiện khuôn mặt của Viola-Jones . Kỹ thuật này dựa vào việc đặt một khung phụ 24x24 pixel trong một hình ảnh, và sau đó đặt các đối tượng hình chữ nhật vào bên trong nó ở mọi vị trí với mọi kích thước có thể.

Các tính năng này có thể bao gồm hai, ba hoặc bốn hình chữ nhật. Ví dụ sau đây được trình bày.

Đặc điểm hình chữ nhật

Họ tuyên bố tập hợp đầy đủ là hơn 180 nghìn (phần 2):

Cho rằng độ phân giải cơ bản của máy dò là 24x24, tập hợp đầy đủ các tính năng hình chữ nhật là khá lớn, hơn 180.000. Lưu ý rằng không giống như cơ sở Haar, tập hợp các tính năng hình chữ nhật chưa hoàn chỉnh.

Các tuyên bố sau đây không được nêu rõ ràng trong bài báo, vì vậy chúng là giả định về phía tôi:

  1. Chỉ có 2 đối tượng địa lý hai hình chữ nhật, 2 đối tượng địa lý ba hình chữ nhật và 1 đối tượng địa lý hình chữ nhật có bốn. Logic đằng sau điều này là chúng ta đang quan sát sự khác biệt giữa các hình chữ nhật được đánh dấu, không rõ ràng là màu sắc hoặc độ sáng hoặc bất kỳ thứ gì thuộc loại đó.
  2. Chúng tôi không thể xác định loại đối tượng A là một khối pixel 1x1; nó phải có ít nhất 1x2 pixel. Ngoài ra, loại D phải có ít nhất 2x2 pixel và quy tắc này tương ứng với các tính năng khác.
  3. Chúng tôi không thể xác định loại đối tượng A là một khối pixel 1x3 vì pixel ở giữa không thể được phân vùng và trừ đi chính nó thì nó giống với khối pixel 1x2; loại tính năng này chỉ được xác định cho các chiều rộng chẵn. Ngoài ra, chiều rộng của loại đối tượng C phải chia hết cho 3 và quy tắc này tương ứng với các đối tượng địa lý khác.
  4. Chúng tôi không thể xác định đối tượng địa lý có chiều rộng và / hoặc chiều cao bằng 0. Do đó, chúng tôi lặp xy thành 24 trừ đi kích thước của đối tượng địa lý.

Dựa trên những giả định này, tôi đã tính toàn bộ:

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++;
                }
            }
        }
    }
}

Kết quả là 162,336 .

Cách duy nhất tôi tìm ra để ước tính "hơn 180.000" mà Viola & Jones nói đến, là bỏ giả định số 4 và bằng cách đưa ra các lỗi trong mã. Điều này liên quan đến việc thay đổi bốn dòng tương ứng thành:

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

Kết quả sau đó là 180,625 . (Lưu ý rằng điều này sẽ ngăn không cho các tính năng chạm vào bên phải và / hoặc dưới cùng của khung phụ một cách hiệu quả.)

Tất nhiên câu hỏi bây giờ là: họ có mắc sai lầm trong quá trình thực hiện không? Có ý nghĩa gì không khi xem xét các đối tượng địa lý có bề mặt bằng 0? Hay tôi đang nhìn nó sai cách?


Tại sao tôi nhận được count = 114829 khi tôi chạy mã của bạn?
Niki

Tại sao vòng lặp x / y của bạn bắt đầu từ 1? Tôi giả sử x / y là tọa độ trên cùng bên trái của hình chữ nhật đặc trưng. Vậy thì x / y có nên bắt đầu từ 0/0 không?
Niki

Bên cạnh việc nó bắt đầu bằng 0 hay 1, thì việc kết thúc tại x < sizephải liên quan đến giả định số 4: Tôi muốn đối tượng địa lý vẫn nằm trong khung phụ, nhưng có kích thước ít nhất là 1x1. Về việc liệu kích thước của đối tượng địa lý không nên mở rộng ra bên ngoài khung phụ hay không, có lẽ đó cũng là một giả định.
Paul Lammertsma

Tương tự, nếu tôi bắt đầu x ở 0, nó sẽ phải chạy đến x < size - 1, do đó không có lợi.
Paul Lammertsma

Tôi đã thực hiện một triệu vòng lặp. điều này có vẻ sai đối với tôi. <size sẽ giữ cho x không bao giờ trở thành 24, bắt đầu từ 0 sẽ cho bạn 0 ... 23, Với kích thước rộng 1 pixel, hình chữ nhật sẽ không bao giờ rời khỏi khung.
Breton

Câu trả lời:


40

Khi xem xét kỹ hơn, mã của bạn có vẻ chính xác với tôi; điều này làm cho người ta tự hỏi liệu các tác giả ban đầu có một lỗi riêng biệt hay không. Tôi đoán ai đó nên xem cách OpenCV triển khai nó!

Tuy nhiên, một gợi ý để làm cho nó dễ hiểu hơn là lật thứ tự của các vòng lặp for bằng cách đi qua tất cả các kích thước trước, sau đó lặp lại các vị trí có thể có kích thước:

#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;
}

với kết quả tương tự như trước 162336


Để xác minh điều đó, tôi đã kiểm tra trường hợp của cửa sổ 4x4 và kiểm tra thủ công tất cả các trường hợp (dễ đếm vì các hình dạng 1x2 / 2x1 và 1x3 / 3x1 giống nhau chỉ được xoay 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

Thuyết phục. Thuyết phục đến mức tôi khá chắc chắn rằng chúng tôi đúng. Tôi đã gửi e-mail cho tác giả để xem liệu tôi có mắc phải sai lầm cơ bản nào đó trong lập luận của mình hay không. Chúng tôi sẽ xem liệu một anh chàng bận rộn có thời gian trả lời hay không.
Paul Lammertsma

Hãy ghi nhớ điều này đã được ra trong một vài năm nay, và nhiều cải tiến đã được thực hiện kể từ đó
Amro

25
Bài báo gốc mà 180k được nêu là từ các thủ tục cho Hội nghị về Thị giác Máy tính và Nhận dạng Mẫu năm 2001. Một bài báo sửa đổi, được chấp nhận vào năm 2003 và được xuất bản trên Tạp chí Quốc tế về Thị giác Máy tính năm 2004, nêu rõ trên p. 139 (cuối phần 2): "tập hợp đầy đủ các hình chữ nhật là khá lớn, 160.000". Có vẻ như chúng tôi đã đúng!
Paul Lammertsma

3
Tuyệt vời, cảm ơn vì đã cập nhật. Đối với những người quan tâm, tôi đã tìm thấy một liên kết đến bài báo IJCV'04
Amro

Vâng, đó là nó. 160k, không phải 180k.
Paul Lammertsma

9

tất cả. Vẫn còn một số nhầm lẫn trong giấy tờ của Viola và Jones.

Trong giấy CVPR'01 của họ có ghi rõ rằng

"Cụ thể hơn, chúng tôi sử dụng ba loại đối tượng địa lý. Giá trị của đối tượng địa lý hai hình chữ nhật là hiệu số giữa tổng số pixel trong hai vùng hình chữ nhật. Các vùng có cùng kích thước và hình dạng và nằm liền kề theo chiều ngang hoặc chiều dọc (xem Hình 1). Tính năng ba hình chữ nhật tính tổng trong hai hình chữ nhật bên ngoài trừ đi tổng trong một hình chữ nhật ở giữa. Cuối cùng là tính năng bốn hình chữ nhật ".

Trong bài báo IJCV'04, điều tương tự cũng được nói. Vì vậy, tổng thể, 4 tính năng . Nhưng kỳ lạ thay, lần này họ tuyên bố rằng tập hợp tính năng đầy đủ là 45396! Đó dường như không phải là phiên bản cuối cùng. Ở đây tôi đoán rằng một số ràng buộc bổ sung đã được giới thiệu ở đó, chẳng hạn như min_width, min_height, tỷ lệ chiều rộng / chiều cao và thậm chí cả vị trí.

Lưu ý rằng cả hai tài liệu đều có thể tải xuống trên trang web của anh ấy .


3

Chưa đọc hết bài báo, từ ngữ của câu trích dẫn của bạn làm tôi khó chịu

Cho rằng độ phân giải cơ bản của máy dò là 24x24, tập hợp đầy đủ các tính năng hình chữ nhật là khá lớn, hơn 180.000. Lưu ý rằng không giống như cơ sở Haar, tập hợp các tính năng hình chữ nhật chưa hoàn chỉnh.

"Tập hợp các tính năng hình chữ nhật chưa hoàn thành" "Tập hợp đã hết"

đối với tôi nó nghe giống như một sự sắp đặt, nơi tôi mong đợi người viết bài sẽ giải thích cách họ sắp xếp không gian tìm kiếm xuống một tập hợp hiệu quả hơn, chẳng hạn như loại bỏ những trường hợp nhỏ nhặt như hình chữ nhật có số 0 diện tích bề mặt.

chỉnh sửa: hoặc sử dụng một số loại thuật toán học máy, như phần tóm tắt gợi ý. Tập hợp cạn kiệt ngụ ý tất cả các khả năng, không chỉ những khả năng "hợp lý".


Tôi nên bao gồm chú thích cuối trang sau "overcomplete": "Một cơ sở hoàn chỉnh không có sự phụ thuộc tuyến tính giữa các phần tử cơ sở và có cùng số phần tử với không gian hình ảnh, trong trường hợp này là 576. Tập hợp đầy đủ 180.000 nghìn đối tượng địa lý gấp nhiều lần- hoàn thành." Họ không loại bỏ rõ ràng các bộ phân loại không có bề mặt, họ sử dụng AdaBoost để xác định rằng "một số lượng rất nhỏ các tính năng này có thể được kết hợp để tạo thành một bộ phân loại hiệu quả". Ok, vì vậy các tính năng bề mặt không sẽ bị loại bỏ ngay lập tức, nhưng tại sao lại xem xét chúng ngay từ đầu?
Paul Lammertsma

Nghe có vẻ giống như lý luận của ai đó thực sự thành lý thuyết tập hợp.
Breton

Tôi đồng ý, tập hợp đầy đủ sẽ ngụ ý tất cả các khả năng. Nhưng hãy cân nhắc rằng nếu bạn lấy 1 đến 24 cho x và width <= x, tính năng sẽ mở rộng 1 pixel ra bên ngoài khung phụ!
Paul Lammertsma

Bạn có chắc chắn mã của mình không bị lỗi "từng lỗi một" không? Tôi vừa mới xem xét kỹ hơn, và chắc chắn bạn có một cách viết vòng lặp for vui nhộn.
Breton

Tôi nên đủ điều kiện cho điều đó- Tôi chỉ nghĩ kỹ một chút và nếu bạn có một hình chữ nhật cao 1 pixel, cao 2 pixel, cao 3 pixel, cao đến 24 pixel, bạn có 24 loại hình chữ nhật, tất cả phù hợp với khung phụ cao 24 pixel. Những gì nhô ra?
Breton

2

Không có gì đảm bảo rằng bất kỳ tác giả nào của bất kỳ bài báo nào đều đúng trong tất cả các giả định và phát hiện của họ. Nếu bạn nghĩ rằng giả định số 4 là hợp lệ, thì hãy giữ nguyên giả định đó và thử lý thuyết của bạn. Bạn có thể thành công hơn các tác giả ban đầu.


Thử nghiệm cho thấy rằng nó hoạt động dường như chính xác như nhau. Tôi tin rằng AdaBoost chỉ đơn giản là bỏ các tính năng không bề mặt bổ sung đó trong chu kỳ đầu tiên, nhưng tôi chưa thực sự xem xét điều này.
Paul Lammertsma

Viola và Jones là những tên tuổi rất lớn trong lĩnh vực máy tính. Trên thực tế, bài báo cụ thể này được coi là có tên tuổi. Mọi người đều mắc sai lầm, nhưng thuật toán cụ thể này đã được chứng minh là hoạt động rất tốt.
Dima

1
Chắc chắn, và tôi không nghi ngờ phương pháp của họ chút nào. Nó hiệu quả và hoạt động rất tốt! Lý thuyết là đúng, nhưng tôi tin rằng họ có thể đã cắt nhầm máy dò của họ ngắn một pixel và bao gồm các tính năng bề mặt không cần thiết. Nếu không, tôi thách bạn chứng minh 180 nghìn tính năng!
Paul Lammertsma

Thực tế là mọi người đều là con người. Ai cũng mắc sai lầm. Khi một tên tuổi lớn mắc sai lầm, họ thường ẩn mình trong nhiều thế hệ vì mọi người sợ đặt câu hỏi về sự khôn ngoan đã nhận được. Nhưng khoa học chân chính, theo phương pháp khoa học và không tôn thờ ai, dù tên tuổi của họ lớn đến đâu. Nếu đó là khoa học, thì những con người bình thường có thể nỗ lực, hiểu cách thức hoạt động của nó và điều chỉnh nó cho phù hợp với hoàn cảnh của họ.
Michael Dillon

Chúng ta sẽ thấy; Tôi đã gửi e-mail cho tác giả.
Paul Lammertsma

1

Quan sát khá tốt, nhưng họ có thể ngầm định xóa khung hình 24x24 hoặc "tràn" và bắt đầu sử dụng các pixel đầu tiên khi nó vượt ra khỏi giới hạn, như trong sự thay đổi quay hoặc như Breton đã nói họ có thể coi một số tính năng là "tính năng tầm thường" và sau đó loại bỏ chúng bằng AdaBoost.

Ngoài ra, tôi đã viết các phiên bản Python và Matlab của mã của bạn để tôi có thể tự kiểm tra mã (gỡ lỗi và làm theo dễ dàng hơn cho tôi) và vì vậy tôi đăng chúng ở đây nếu ai đó thấy chúng hữu ích đôi khi.

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)

Tại sao bạn sử dụng 5 tính năng, chỉ có 4 được đăng trong câu hỏi chính. Nhưng cảm ơn dù sao cho phiên bản python.
Kasparov92

0

Trong bài báo gốc năm 2001 của họ, họ chỉ nói rằng ba loại tính năng được sử dụng:

chúng tôi sử dụng ba loại tính năng

Cũng thế

Các vùng có cùng kích thước và hình dạng

Vì mỗi loại có hai hướng, nên sẽ hợp lý khi giả sử rằng chúng sử dụng tổng cộng 6 đối tượng (ít nhất là để tính tổng số đối tượng): 2 đối tượng hai hình chữ nhật, 2 đối tượng địa lý ba hình chữ nhật và 2 đối tượng địa lý bốn hình chữ nhật. Với giả định này, thực sự có hơn 180.000 tính năng:

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

Nếu bạn bỏ đi một loại đối tượng có bốn hình chữ nhật (có vẻ là trường hợp xuất bản sau này của chúng), thì tổng số đối tượng là 162.336.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.