face-clustering-rk3588./README.md

10 KiB

Face Clustering RK3588

Toolkit C++ riutilizzabile per il rilevamento dei volti, la generazione di embedding facciali e il futuro clustering tramite HDBSCAN su dispositivi Rockchip RK3588.

Il progetto usa RKNN per eseguire sulla NPU:

  • SCRFD per il rilevamento dei volti;
  • SFace per la generazione degli embedding;
  • normalizzazione L2 degli embedding;
  • confronto tramite cosine similarity.

Il motore non dipende da database, server o applicazioni specifiche e può essere integrato in altri programmi C++ oppure utilizzato tramite il programma face_scan e il relativo output JSON.

Stato del progetto

Funzionalità attualmente disponibili:

  • caricamento delle immagini RGB;
  • rilevamento facciale tramite SCRFD;
  • confidence score per ogni volto;
  • bounding box;
  • cinque landmark facciali;
  • non-maximum suppression;
  • allineamento del volto a 112 x 112 pixel;
  • generazione di embedding SFace a 128 dimensioni;
  • conversione dell'output in float32;
  • normalizzazione L2;
  • confronto tramite cosine similarity;
  • output JSON per applicazioni esterne;
  • compilazione tramite Makefile.

Funzionalità pianificate:

  • ricerca kNN tramite OpenCL;
  • TOPK uguale a 32;
  • core distance;
  • mutual reachability distance;
  • minimum spanning tree;
  • condensed tree;
  • clustering HDBSCAN;
  • assegnazione di un cluster a ogni embedding facciale.

Pipeline facciale

Immagine
   |
   v
Caricamento RGB
   |
   v
Resize proporzionale
   |
   v
Input SCRFD 640 x 640
   |
   v
SCRFD su RKNN/NPU
   |
   +-- confidence score
   +-- bounding box
   +-- cinque landmark
   |
   v
Non-maximum suppression
   |
   v
Similarity transform
   |
   v
Volto allineato 112 x 112
   |
   v
SFace su RKNN/NPU
   |
   v
Embedding float32[128]
   |
   v
Normalizzazione L2

Poiché gli embedding sono normalizzati, la cosine similarity tra due embedding corrisponde al loro prodotto scalare.

Programmi disponibili

face_recognition

face_recognition è il programma dimostrativo con output leggibile da una persona.

Può analizzare una singola immagine oppure confrontare tutti i volti trovati in due immagini.

Scansione di una singola immagine:

./bin/face_recognition test/image.jpg

Confronto tra due immagini:

./bin/face_recognition \
  test/reference.jpg \
  test/query.jpg

Per ogni volto il programma mostra:

  • confidence score;
  • bounding box;
  • cinque landmark.

Nel confronto fra due immagini calcola la cosine similarity tra ogni volto della prima immagine e ogni volto della seconda.

La soglia dimostrativa attuale è:

0.363

Questa soglia deve essere validata sul dataset reale dell'applicazione.

face_scan

face_scan è destinato all'integrazione con altri programmi.

Accetta il percorso di una singola immagine:

./bin/face_scan test/image.jpg

Scrive:

  • il risultato JSON su standard output;
  • errori e diagnostica su standard error;
  • exit code 0 in caso di successo;
  • exit code diverso da 0 in caso di errore.

Per salvare il risultato:

./bin/face_scan \
  test/image.jpg \
  > result.json

Per verificare e formattare il JSON:

python3 -m json.tool result.json

Il JSON contiene:

  • percorso dell'immagine;
  • larghezza e altezza originali;
  • elenco dei volti;
  • indice sequenziale del volto;
  • confidence score;
  • bounding box;
  • cinque landmark;
  • embedding di 128 valori.

Il formato completo è documentato in docs/json-format.md.

Requisiti

  • Linux AArch64;
  • Rockchip RK3588 o piattaforma RKNN compatibile;
  • compilatore con supporto C++17;
  • GNU Make;
  • runtime RKNN;
  • modello SCRFD in formato RKNN;
  • modello SFace in formato RKNN;
  • Python 3 per la validazione dei test JSON.

File locali richiesti

Modelli RKNN

Copiare i modelli nella directory models:

models/SCRFD_500M_KPS_640.rknn
models/face_recognition_sface_2021dec.rknn

Runtime RKNN

Copiare la libreria runtime in:

lib/librknnrt.so

I modelli RKNN e la libreria runtime sono esclusi dal repository tramite .gitignore.

Prima di distribuire questi file, verificare le rispettive condizioni di licenza e redistribuzione.

Compilazione

Dalla directory principale del repository:

make

Compilazione parallela:

make -j"$(nproc)"

I programmi vengono creati in:

bin/face_recognition
bin/face_scan

Per effettuare una compilazione pulita:

make clean
make -j"$(nproc)"

Test

Le immagini di test locali devono essere copiate nella directory test.

Per eseguire i test automatici:

make test

Il test:

  1. esegue face_recognition;
  2. esegue face_scan;
  3. salva temporaneamente il JSON;
  4. valida la sintassi JSON tramite Python.

Le immagini sono escluse dal repository tramite .gitignore.

Utilizzo da un altro programma C++

Includere l'header pubblico:

#include "face_engine.h"

Inizializzare il motore:

FaceEngine engine;

if (!engine.init(
        "models/SCRFD_500M_KPS_640.rknn",
        "models/face_recognition_sface_2021dec.rknn")) {
    return 1;
}

Elaborare un'immagine:

std::vector<Face> faces;
int image_width = 0;
int image_height = 0;

if (!engine.process_image(
        "image.jpg",
        faces,
        image_width,
        image_height)) {
    return 1;
}

Ogni elemento Face contiene:

  • score, confidence del detector;
  • x1, y1, x2 e y2;
  • cinque elementi kps;
  • un embedding L2-normalizzato di 128 elementi.

Esempio di accesso ai risultati:

for (const Face& face : faces) {
    std::cout
        << "score=" << face.score
        << " bbox="
        << face.x1 << ","
        << face.y1 << ","
        << face.x2 << ","
        << face.y2
        << "\n";

    if (face.embedding.size() == 128) {
        std::cout << "Embedding valido\n";
    }
}

Utilizzo da altri linguaggi

Programmi Node.js, Python, Java, Dart o scritti in altri linguaggi possono eseguire bin/face_scan come processo figlio.

Il contratto di integrazione è:

Input       percorso di una singola immagine
stdout      oggetto JSON completo
stderr      diagnostica ed errori
exit 0      scansione completata
exit != 0   errore

Un'immagine valida senza volti produce comunque exit code 0 e:

{
  "image": {
    "path": "image.jpg",
    "width": 1920,
    "height": 1080
  },
  "faces": []
}

Formato dell'embedding

Ogni embedding contiene:

Dimensione logica    128
Tipo nel motore      float32
Norma L2             circa 1.0
Valori                tutti finiti

Se salvato come sequenza binaria float32:

128 x 4 byte = 512 byte

Questo formato sarà utilizzabile direttamente dai futuri moduli OpenCL.

Struttura del repository

face-clustering-rk3588/
|-- Makefile
|-- README.md
|-- include/
|   |-- face_config.h
|   |-- face_engine.h
|   |-- rknn_api.h
|   `-- stb_image.h
|-- src/
|   |-- face_engine.cc
|   |-- face_recognition.cc
|   `-- face_scan.cc
|-- docs/
|   |-- architecture.md
|   `-- json-format.md
|-- models/
|   `-- README.md
|-- lib/
|   `-- README.md
|-- test/
|   `-- README.md
|-- modules/
|   |-- knn-opencl/
|   |-- mutual-reachability/
|   |-- mst/
|   `-- hdbscan/
|-- build/
`-- bin/

Architettura del motore

Il codice è diviso in tre componenti principali.

face_engine

Implementa:

  • caricamento immagine;
  • resize bilineare;
  • conversione float32 e float16;
  • inferenza SCRFD;
  • decodifica dei risultati;
  • non-maximum suppression;
  • allineamento facciale;
  • inferenza SFace;
  • normalizzazione dell'embedding.

face_recognition

Fornisce un programma dimostrativo e permette di verificare visivamente:

  • volti rilevati;
  • bounding box;
  • landmark;
  • similarità fra embedding.

face_scan

Fornisce un'interfaccia machine-readable tramite JSON.

Il programma non scrive log su standard output, così l'output può essere letto direttamente con un parser JSON.

Pipeline futura di clustering

Il repository verrà esteso con questa pipeline:

Embedding SFace float32[N][128]
    |
    v
OpenCL brute-force kNN
    |
    v
TOPK=32
    |
    +-- indices[N][32]
    `-- scores[N][32]
    |
    v
Core distance
    |
    v
Mutual reachability graph
    |
    v
Minimum spanning tree
    |
    v
Single linkage hierarchy
    |
    v
Condensed tree
    |
    v
HDBSCAN cluster assignment

Moduli futuri

knn-opencl

Calcolerà i 32 vicini più prossimi per ogni embedding usando il prodotto scalare tra vettori L2-normalizzati.

mutual-reachability

Calcolerà:

mrd(i,j) =
    max(
        core_distance(i),
        core_distance(j),
        distance(i,j)
    )

mst

Costruirà il minimum spanning tree del grafo di mutual reachability.

hdbscan

Produrrà:

  • gerarchia single linkage;
  • condensed tree;
  • stabilità dei cluster;
  • assegnazione finale dei cluster;
  • identificazione del rumore.

Roadmap

Face detection e embedding       completato
Confronto cosine                 completato
Output JSON                      completato
Makefile                         completato
Documentazione                   completato
OpenCL kNN TOPK=32               pianificato
Core distance                    pianificato
Mutual reachability              pianificato
Minimum spanning tree            pianificato
HDBSCAN condensed tree           pianificato
Cluster assignment               pianificato

Licenze e componenti esterni

Il repository contiene o utilizza componenti esterni, inclusi:

  • stb_image;
  • header API RKNN;
  • runtime RKNN;
  • modelli SCRFD;
  • modello SFace.

Prima della pubblicazione o redistribuzione verificare separatamente le condizioni di licenza di ogni componente.

I modelli e il runtime non vengono inseriti automaticamente nel repository.

Obiettivo finale

L'obiettivo è fornire una pipeline indipendente e riutilizzabile:

Immagini
   |
   v
Volti e embedding
   |
   v
Grafo kNN
   |
   v
HDBSCAN
   |
   v
Cluster di identità facciali

Il server o l'applicazione che utilizza il toolkit rimane responsabile della persistenza, dell'interfaccia utente e dell'eventuale associazione dei cluster a persone reali.