558 lines
10 KiB
Markdown
558 lines
10 KiB
Markdown
# 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
|
|
|
|
```text
|
|
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:
|
|
|
|
```bash
|
|
./bin/face_recognition test/image.jpg
|
|
```
|
|
|
|
Confronto tra due immagini:
|
|
|
|
```bash
|
|
./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 è:
|
|
|
|
```text
|
|
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:
|
|
|
|
```bash
|
|
./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:
|
|
|
|
```bash
|
|
./bin/face_scan \
|
|
test/image.jpg \
|
|
> result.json
|
|
```
|
|
|
|
Per verificare e formattare il JSON:
|
|
|
|
```bash
|
|
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`:
|
|
|
|
```text
|
|
models/SCRFD_500M_KPS_640.rknn
|
|
models/face_recognition_sface_2021dec.rknn
|
|
```
|
|
|
|
### Runtime RKNN
|
|
|
|
Copiare la libreria runtime in:
|
|
|
|
```text
|
|
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:
|
|
|
|
```bash
|
|
make
|
|
```
|
|
|
|
Compilazione parallela:
|
|
|
|
```bash
|
|
make -j"$(nproc)"
|
|
```
|
|
|
|
I programmi vengono creati in:
|
|
|
|
```text
|
|
bin/face_recognition
|
|
bin/face_scan
|
|
```
|
|
|
|
Per effettuare una compilazione pulita:
|
|
|
|
```bash
|
|
make clean
|
|
make -j"$(nproc)"
|
|
```
|
|
|
|
## Test
|
|
|
|
Le immagini di test locali devono essere copiate nella directory
|
|
`test`.
|
|
|
|
Per eseguire i test automatici:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```cpp
|
|
#include "face_engine.h"
|
|
```
|
|
|
|
Inizializzare il motore:
|
|
|
|
```cpp
|
|
FaceEngine engine;
|
|
|
|
if (!engine.init(
|
|
"models/SCRFD_500M_KPS_640.rknn",
|
|
"models/face_recognition_sface_2021dec.rknn")) {
|
|
return 1;
|
|
}
|
|
```
|
|
|
|
Elaborare un'immagine:
|
|
|
|
```cpp
|
|
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:
|
|
|
|
```cpp
|
|
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 è:
|
|
|
|
```text
|
|
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:
|
|
|
|
```json
|
|
{
|
|
"image": {
|
|
"path": "image.jpg",
|
|
"width": 1920,
|
|
"height": 1080
|
|
},
|
|
"faces": []
|
|
}
|
|
```
|
|
|
|
## Formato dell'embedding
|
|
|
|
Ogni embedding contiene:
|
|
|
|
```text
|
|
Dimensione logica 128
|
|
Tipo nel motore float32
|
|
Norma L2 circa 1.0
|
|
Valori tutti finiti
|
|
```
|
|
|
|
Se salvato come sequenza binaria float32:
|
|
|
|
```text
|
|
128 x 4 byte = 512 byte
|
|
```
|
|
|
|
Questo formato sarà utilizzabile direttamente dai futuri moduli OpenCL.
|
|
|
|
## Struttura del repository
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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à:
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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.
|