Domanda

Sono stato l'implementazione di un adattamento del Viola-Jones' face detection algoritmo . La tecnica si basa su una sottotrama sistemazione di 24x24 pixel all'interno di un'immagine, e successivamente ponendo caratteristiche rettangolari interno in ogni posizione di ogni dimensione possibile.

Queste caratteristiche possono essere costituite da due, tre o quattro rettangoli. L'esempio che segue è presentato.

caratteristiche rettangolo

Essi sostengono l'insieme esaustivo è più di 180k (sezione 2):

  

Dato che la risoluzione base del rivelatore è 24x24, l'insieme completo degli elementi rettangolo è abbastanza grande, oltre 180.000. Si noti che a differenza di base Haar, l'insieme di rettangolo di   caratteristiche è Overcomplete.

Le seguenti affermazioni non sono esplicitamente indicati nel documento, in modo che siano assunti da parte mia:

  1. Ci sono solo 2 è dotato di due-rettangolo, 2 dispone di tre-rettangolo e 1 funzione quattro rettangolo. La logica alla base di questo è che stiamo osservando il differenza tra i rettangoli evidenziati, non esplicitamente il colore o luminanza o qualcosa del genere.
  2. Non possiamo definire funzionalità di tipo A come un blocco 1x1 pixel; deve almeno essere almeno pixel 1x2. Inoltre, il tipo D deve essere almeno 2x2 pixel, e questa regola tiene conseguenza per le altre funzioni.
  3. Non possiamo definire funzionalità di tipo A come un blocco 1x3 pixel come pixel centrale non può essere partizionato e sottraendolo sé è identico ad un blocco 1x2 pixel; questo tipo di elemento è definito solo per larghezze pari. Inoltre, la larghezza del tipo di funzione C deve essere divisibile per 3, e questa regola tiene di conseguenza per le altre caratteristiche.
  4. Non possiamo definire una funzione con una larghezza e / o altezza pari a 0. Pertanto, iteriamo x e y per 24 meno la dimensione della funzione.

Sulla base di questi presupposti, ho contato il set esaustivo:

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

Il risultato è 162.336 .

L'unico modo che ho trovato per approssimare il "oltre 180.000" Viola & Jones parlano di, sta cadendo assunto # 4 e con l'introduzione di bug nel codice. Questo comporta la modifica quattro linee rispettivamente:

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

Il risultato è quindi 180.625 . (Si noti che questa situazione impedirà le caratteristiche da sempre di toccare il diritto e / o inferiore del telaio ausiliario.)

Ora, naturalmente, la domanda: hanno hanno commesso un errore nella loro attuazione? Ha un qualche senso considerare le caratteristiche con una superficie pari a zero? O sto vedendo nel modo sbagliato?

È stato utile?

Soluzione

A ben guardare, il codice sia corretto per me; il che fa chiedere se gli autori originali avevano un bug off-by-one. Credo che qualcuno dovrebbe guardare a come OpenCV implementa!

Tuttavia, un suggerimento per rendere più facile da capire è quello di capovolgere l'ordine del per loop andando oltre tutte le dimensioni, poi loop sulle posizioni possibili date le dimensioni:

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

con gli stessi risultati come il 162336 precedente


Per verificare che, ho testato il caso di una finestra 4x4 e controllato manualmente tutti i casi (facile contare dal forme 1x2 / 2x1 e 1x3 / 3x1 sono le stesse solo 90 gradi ruotati):

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

Altri suggerimenti

tutti. C'è ancora una certa confusione nei documenti Viola e Jones'.

Nel loro documento CVPR'01 è chiaramente affermato che

  

"In particolare, usiamo tre   tipi di caratteristiche. Il valore di un    funzione due rettangolo è la differenza tra la somma delle   i pixel all'interno due regioni rettangolari.   Le regioni hanno la stessa dimensione e   forma e sono orizzontalmente o   verticalmente adiacente (vedere Figura 1).    Una caratteristica tre rettangolo calcola la somma entro due fuori   rettangoli sottratte dalla somma in   un rettangolo centrale. Infine un   quattro rettangolo funzione ".

Nel documento IJCV'04, esattamente la stessa cosa si dice. Quindi complessivamente, 4 caratteristiche . Ma stranamente, hanno dichiarato che questa volta il set di funzionalità completo è 45396! Questo non sembra essere il version.Here finale Credo che alcuni vincoli aggiuntivi sono stati introdotti lì, come ad esempio MIN_WIDTH, MIN_HEIGHT, rapporto larghezza / altezza, e anche la posizione.

Si noti che entrambi i documenti sono scaricabili su sua pagina web .

Non avendo letto l'intero documento, la formulazione del tuo preventivo sporge verso di me

  

Dato che la risoluzione base del   rivelatore è 24x24, l'insieme esaustivo   di caratteristiche rettangolo è abbastanza grande,   oltre 180.000. Si noti che a differenza del   base Haar, l'insieme di rettangolo di   caratteristiche è Overcomplete.

"Il set di funzionalità rettangolo è Overcomplete" "Insieme esaustivo"

suona per me come un set up, dove mi aspetto che lo scrittore della carta di follow-up con una spiegazione per come da riforma lo spazio di ricerca verso il basso per un insieme più efficace, da, per esempio, sbarazzarsi di casi banali come rettangoli con superficie di zero.

modifica: o utilizzando qualche tipo di algoritmo di apprendimento automatico, come i suggerimenti astratti a. insieme esaustivo implica tutte le possibilità, non solo "ragionevoli" quelli.

Non v'è alcuna garanzia che qualsiasi autore di qualsiasi tipo di carta è corretto in tutte le loro ipotesi e scoperte. Se si pensa che presupposto # 4 è valida, allora continuate a tale ipotesi, e provare la tua teoria. Si può essere più successo di quanto l'autore originale.

abbastanza buona osservazione, ma potrebbero implicitamente zero pad telaio 24x24, o "overflow" e inizia a usare i pixel quando esce dai limiti, come in spostamenti rotazionali, o come detto Breton si potrebbe considerare alcune caratteristiche come " caratteristiche banali" e poi li scartano con l'AdaBoost.

Inoltre, ho scritto versioni di Python e Matlab del codice in modo da poter testare il codice stesso (più facile per eseguire il debug e seguire per me) e così li ho postare qui se qualcuno li trova utili qualche volta.

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)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top