Face recognition by Local Binary Pattern

Creato il 10 aprile 2014 da Matteo Tosato @MatteoTosato87

Local Binary Pattern, d’ora in poi “LBP“, è un metodo di “feature extraction” utilizzato in computer vision, per il “pattern recognition“, in particolare per classificare i visi rilevati in immagini e video. Descritto per la prima volta nel 1994 in [1] e [2], ha dimostrato, in combinazione con metodi di classificazione, essere in grado di discriminare e riconoscere in maniera esaustiva visi e identità delle persone. In alcuni casi, risultati interessanti sono stati ottenuti anche dal punto di vista delle performance. LBP permette applicazioni di face recognition anche su processori meno performanti [3]. Interessanti sono le possibili applicazioni in ambito mobile.

Figura 1: Operatore LBP su viso rilevato.

Il vettore di “features” LBP è costruito con la seguente procedura per ogni viso rilevato:

- Per ogni pixel del frame, viene confrontato il valore di intensità di ogni pixel che compone il “vicinato” in senso orario (pensiamo ad una matrice di 3 x 3). Quando il pixel ha intensità inferiore, scriveremo ’0′, altrimenti ’1′. Nel paradigma originale, i pixel che compongono il vicinato, sono quelli direttamente adiacenti. Infine viene copiata la stringa binaria di 8 bit risultante prelevando i bit dal primo all’ultimo. Traducendola in decimale, si ottiene il valore di intensità. (tale processo è descritto in figura 3).
Secondo l’operatore LBP originale, il frame che si ottiene è una matrice di valori di intensità (r-1) x (c-1), dove r e c sono il numero delle righe e delle colonne del frame sorgente.

Successivamente, l’operatore LBP inizialmente ideato è stato modificato rendendo variabile il numero di pixel che compongono il “vicinato”. In questa seconda versione, chiamata “Extended Local Binary Pattern (ELBP), viene tracciato un cerchio di raggio arbitrario, tutti i pixel compresi all’interno vengono assunti come vicinato e utilizzati nel calcolo.
Formalmente si ottiene:

Dove ‘ip’ e ‘ic’ sono rispettivamente il valore del pixel centrale e il valore di un numero ‘P’ di pixel vicini compresi all’interno della circonferenza definita da un raggio ‘R’. La funzione s(x) è definita, come abbiamo detto, nel modo seguente:

Figura 2: Three neighborhood examples used to define a texture and calculate a local binary pattern (LBP)

- Una volta completata l’operazione per ogni pixel del frame, l’immagine risultante viene suddivisa in riquadri. Solitamente dividendo “5 x 5″ o “8 x 8″ (figura 4).
- Per ogni riquadro, si calcola l’istogramma delle frequenze di intensità. Che cosa significa? Per ogni valore di intensità si incrementa il rispettivo contatore nell’array (Local Intensity Histogram). Per esempio, se la mia immagine ha dei pixel che variano in intensità da 0 a 254, l’array di cui stiamo parlando ha 255 componenti.
- Questi istogrammi vengono concatenati ad ottenere così un unico array. Tale array contiene la distribuzione delle frequenze nel frame, descrive perciò le caratteristiche del viso in questione indipendentemente dalla luminosità dell’immagine (figura 4).

Figura 3: L’operatore LBP originale

Figura 4: LBP face description

Spesso e volentieri risulta utile ridurre la dimensione di questo istogramma. La riduzione è possibile con diverse tecniche, come PCA (Principal components analysis) , LDA (Linear discriminant analysis) etc…

Ai fini della classificazione, l’operatore LBP viene applicato su un frame mediato per coprire più casistiche (es. espressione leggermente diversa). Sebbene il risultato di LBP varia a seconda dell’espressione che assumiamo, è risultato sufficiente per la discriminazione.

La seguente è l’implementazione in C# dell’operatore ELBP (il codice si basa su una implementazione simile in C++ [4]):

...
/// <summary>
/// Compute circular LBP operator for each pixel.
/// ( original code take from: http://www.bytefish.de/blog/local_binary_patterns/ by Philipp Wagner)
/// Thank you Philipp for your work
/// </summary>
/// <param name="image">Source frame</param>
/// <param name="radius">LBP radious</param>
/// <param name="neighbors">Number of neighbors</param>
/// <param name="maxValue">OUT - Max intensity value</param>
/// <returns>LBP frame</returns>
internal static Image<Gray, byte> ELBP(Image<Gray, byte> image, int radius, int neighbors, out double maxValue)
{
    Image<Gray, byte> img = new Image<Gray, byte>(image.Width - 2 * radius, image.Height - 2 * radius);
    maxValue = 0;

    // Apply extended local binary pattern with bilinear interpolation
    for (int n = 0; n < neighbors; n++)
    {
        double x = Convert.ToDouble(radius) * Math.Cos(2.0 * Math.PI * n / Convert.ToDouble(neighbors));
        double y = Convert.ToDouble(radius) * -Math.Sin(2.0 * Math.PI * n / Convert.ToDouble(neighbors));

        int fx = Convert.ToInt32(Math.Floor(x));
        int fy = Convert.ToInt32(Math.Floor(y));
        int cx = Convert.ToInt32(Math.Ceiling(x));
        int cy = Convert.ToInt32(Math.Ceiling(y));

        double ty = y - fy;
        double tx = x - fx;

        double w1 = (1 - tx) * (1 - ty);
        double w2 = tx * (1 - ty);
        double w3 = (1 - tx) * ty;
        double w4 = tx * ty;

        for (int i = radius; i < image.Rows - radius; i++)
        {
            for (int j = radius; j < image.Cols - radius; j++)
            {
                double t =
                    w1 * image[i + fy, j + fx].Intensity +
                    w2 * image[i + fy, j + cx].Intensity +
                    w3 * image[i + cy, j + fx].Intensity +
                    w4 * image[i + cy, j + cx].Intensity;

                img[i - radius, j - radius] = new Gray(
                    Convert.ToInt32(img[i - radius, j - radius].Intensity + Convert.ToDouble((t > image[i, j].Intensity) & (Math.Abs(t - image[i, j].Intensity) > Math.E))) << n
                    );

                if (img[i - radius, j - radius].Intensity > maxValue)
                    maxValue = Convert.ToInt32(img[i - radius, j - radius].Intensity);
            }
        }

    }
    return img;
}
...

Nella dimostrazione seguente carico un set di soggetti già registrati in precedenza. Il software continua a segnalarmi come sconosciuto non essendo io uno dei soggetti preregistrati. Quindi passo alla registrazione, che secondo questa dimostrazione si basa sulla media di 5 immagini del viso. Il tutto viene fatto in real-time. Una volta prodotto l’istogramma viene aggiunto nella lista dei soggetti conosciuti. A questo punto il software è in grado di riconoscere il mi visto e discriminarlo dagli altri.
In azione:


Bibliografia:

.1 T. Ojala, M. Pietikäinen, and D. Harwood (1994), “Performance evaluation of texture measures with classification based on Kullback discrimination of distributions“, Proceedings of the 12th IAPR International Conference on Pattern Recognition (ICPR 1994), vol. 1, pp. 582 – 585
.2 T. Ojala, M. Pietikäinen, and D. Harwood (1996), “A Comparative Study of Texture Measures with Classification Based on Feature Distributions“, Pattern Recognition, vol. 29, pp. 51-59.
.3 Huang, Student, Caifeng Shan, Mohsen Ardabilian, Yunhong Wang, and Liming Chen, “Local Binary Patterns and Its Application to Facial Image Analysis: A Survey“, IEEE TRANSACTIONS ON SYSTEMS, MAN, AND CYBERNETICS—PART C: APPLICATIONS AND REVIEWS, VOL. 41, NO. 6, NOVEMBER 2011
.4 Philipp Wagner Web site – http://www.bytefish.de/index.html


Archiviato in:C#, Computer vision, Informatica, Programmazione Tagged: Computer Vision, EmguCV, Face recognition, Local Binary Pattern

Potrebbero interessarti anche :

Possono interessarti anche questi articoli :