Frage

Ich habe die Umsetzung einer Anpassung von Viola-Jones' Gesichtserkennung Algorithmus . Die Technik beruht auf einem Unterrahmen von 24x24 Pixeln innerhalb eines Bildes Platzieren und Platzieren anschließend rechteckige Merkmale darin in jeder Position mit jeder Größe möglich.

Diese Funktionen können bestehen aus zwei, drei oder vier Rechtecken. Das folgende Beispiel wird vorgestellt.

Rectangle Eigenschaften

Sie behaupten, die abschließende mehr als 180k (Abschnitt 2):

  

Da die Basisauflösung des Detektors 24x24, die erschöpfende Reihe von Rechteckmerkmalen ist ziemlich groß, mehr als 180.000. Beachten Sie, dass im Gegensatz zu der Haar-Basis, um den Satz von Rechteck   Funktionen sind übervollständigen.

Die folgenden Aussagen sind nicht explizit in dem Papier angegeben, so dass sie Annahmen, auf meiner Seite:

  1. Es gibt nur 2 Zwei-Rechteck-Funktionen, 2 Drei-Rechteck-Feature und 1 Vier Rechteck-Funktion. Die Logik dahinter ist, dass wir den Unterschied zwischen den markierten Rechtecken beobachten, nicht explizit der Farbe oder Helligkeit oder irgendetwas dieser Art.
  2. Wir können nicht Feature-Typ A als 1x1 Pixelblock definieren; es muß mindestens mindestens 1x2 Pixeln sein. Auch Typ D mindestens 2x2 Pixel groß sein muss, und diese Regel gilt entsprechend für die anderen Funktionen.
  3. Wir können nicht Feature-Typ A als 1x3 Pixelblock als das mittlere Pixel können nicht partitioniert, definieren und sie von sich selbst subtrahiert wird, zu einem 1x2 Pixelblock identisch; Dieses Feature-Typ ist nur für selbst Breiten definiert. Außerdem muss die Breite der Feature-Typ C durch 3 teilbar, und diese Regel gilt entsprechend für die anderen Funktionen.
  4. Wir können nicht über eine Funktion mit einer Breite und / oder Höhe von 0. Deshalb definieren wir iterieren x und y bis 24 minus der Größe des Merkmals.

Auf der Grundlage dieser Annahmen, ich habe die abschließenden gezählt:

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

Das Ergebnis ist 162.336 .

Die einzige Art, wie ich die „mehr als 180.000“ Viola & Jones spricht, annähern gefunden sinkt Annahme # 4 und durch Fehler im Code einzuführen. Dies beinhaltet vier Linien zu ändern bzw. zu:

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

Das Ergebnis ist dann 180.625 . (Beachten Sie, dass dies effektiv die Eigenschaften von je berühren das Recht verhindern und / oder Unterseite des Unterrahmens.)

Jetzt natürlich die Frage: haben sie einen Fehler bei der Umsetzung gemacht? Macht es Sinn, Merkmale mit einer Fläche von Null in Betracht ziehen? Oder bin ich es in die falsche Richtung zu sehen?

War es hilfreich?

Lösung

Bei näherem Hinsehen Ihr Code sieht mir richtig; das macht man sich fragen, ob die Original-Autoren einen Off-by-one Fehler hatten. Ich denke, jemand sollte prüfen, wie OpenCV implementiert es!

Dennoch ein Vorschlag, es leichter verständlich zu machen, ist die Reihenfolge der Flip für Schleifen von allen Größen zuerst gehen über, dann Schleife über die möglichen Standorte der Größe gegeben:

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

mit dem gleichen Ergebnis wie das vorherige 162336


es zu überprüfen, testete ich den Fall eines 4x4-Fenster und manuell überprüft alle Fälle (einfach, da 1x2 / 2x1 und 1x3 / 3x1 Formen zu zählen sind die gleichen nur um 90 Grad gedreht):

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

Andere Tipps

alle. Es gibt noch einige Verwirrung in Viola und Jones' Papieren.

In ihrem CVPR'01 Papier ist es klar gesagt, dass

  

"Genauer gesagt, wir verwenden drei   Arten von Funktionen. Der Wert von a    Zwei Rechteck-Funktion ist die Differenz zwischen der Summe der   Pixel in zwei rechteckige Bereiche.   Die Regionen haben die gleiche Größe und   Form auf und sind horizontal oder   vertikal benachbarte (siehe Abbildung 1).    Eine Drei-Rechteck-Funktion berechnet die Summe innerhalb von zwei außerhalb   Rechtecke von der Summe abgezogen, in   ein Zentrum Rechteck. Schließlich ein   Vier Rechteck-Funktion “.

Im IJCV'04 Papier, genau das Gleiche gesagt. So insgesamt, 4 Funktionen . Aber seltsam genug, sie erklärten diese Zeit, dass die die erschöpfenden Feature-Set 45396 ist! Das scheint nicht der letzte version.Here Ich denke, zu sein, dass einige zusätzliche Einschränkungen dort eingeführt wurden, wie MIN_WIDTH, min_height, Breite / Höhe-Verhältnis und sogar Position.

Beachten Sie, dass beide Papiere auf rel="noreferrer">.

Mit nicht das gesamte Papier lesen, die Benennung Ihrer Zitat bei mir ragt

  

Da die Basisauflösung der   Detektor 24x24, die abschließende   von Rechteckmerkmal ist recht groß,   mehr als 180.000. Beachten Sie, dass im Gegensatz zu den   Haar-Basis, der Satz von Rechteckes   Funktionen sind übervollständigen.

„Der Satz von Rechteckmerkmalen ist over“ "Erschöpfendes set"

es klingt für mich wie ein gesetzt, wo ich das Papier Schriftsteller erwarte mit einem explaination folgen zu lassen, wie sie den Suchraum keulen nach unten zu einem effektiveren Satz, durch zum Beispiel von trivialen Fällen loszuwerden wie Rechtecke mit Null-Oberfläche.

edit: oder irgendeine Art von Maschinenlernalgorithmus, wie die abstrakten Hinweise auf. Erschöpfender Satz impliziert alle Möglichkeiten, nicht nur „angemessen“ ist.

Es gibt keine Garantie, dass jeder Autor von jedem Papier in all ihren Annahmen und Ergebnisse korrekt sind. Wenn Sie denken, dass Annahme # 4 gültig ist, dann halten diese Annahme, und probieren Sie Ihre Theorie. Sie können als die ursprünglichen Autoren erfolgreicher sein.

Ganz gute Beobachtung, aber sie könnten implizit Null-pad des 24x24 Rahmen oder „Überlauf“ und starten erste Pixel zu verwenden, wenn es außerhalb der Grenzen wird, wie in Drehverschiebungen oder wie Breton sagte, sie könnten einige Funktionen wie "betrachten triviale Funktionen“und dann verwerfen sie mit dem AdaBoost.

Darüber hinaus schrieb ich Python und Matlab Versionen des Codes, so kann ich den Code testen, mich (einfacher zu debuggen und folgen für mich) und so poste ich sie hier, wenn jemand sie nützlich irgendwann finden.

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)
scroll top