galleria_photo_face_rknn_op.../faces.md
2026-10-03 12:16:58 +02:00

3.9 KiB
Raw Permalink Blame History

Perfetto. Ora abbiamo il quadro completo: SQLite tramite better-sqlite3 + Knex.

Per il tuo caso farei una piccola estensione del DB esistente, senza modificare la struttura di photos.

Schema che proporrei

photos │ └── faces │ ├── embedding BLOB ← 128 × float32 ├── cluster_id └── person_id │ └── persons

e separatamente:

clusters

Quindi:

photos 1 ─── N faces N ─── 1 clusters │ └──── N ─── 1 persons

Con una distinzione fondamentale:

cluster_id = risultato dell'algoritmo HDBSCAN

person_id = identità assegnata dall'utente

un person_id può avere più cluster_id

un nuovo volto riconosciuto può avere person_id ma cluster_id = NULL

faces

Per esempio:

faces

id photo_id x y width height embedding cluster_id person_id created_at updated_at

embedding sarebbe un BLOB SQLite contenente:

128 × float32 = 512 byte

Questo è adatto al tuo motore OpenCL: leggiamo il BLOB e lo trasformiamo direttamente in float*.

clusters

clusters

id run_id label size created_at

run_id è utile perché HDBSCAN potrebbe essere rieseguito più volte durante la fase iniziale.

persons

persons

id user name created_at updated_at

Poi aggiungerei una struttura per i prototype embedding, invece di obbligarci ad avere un solo embedding rappresentativo per persona.

Ad esempio:

person 7 ├── prototype 1 → volto frontale ├── prototype 2 → profilo ├── prototype 3 → occhiali └── prototype 4 → barba

Questo diventa molto utile per il riconoscimento incrementale.


Una scelta importante: niente embedding dei cluster

Non salverei inizialmente un unico:

cluster.embedding

come rappresentazione obbligatoria.

Abbiamo già tutti i face embedding:

faces.embedding

e possiamo calcolare i rappresentanti quando servono.

Per esempio, dopo che l'utente associa un cluster a una persona, possiamo selezionare alcuni embedding rappresentativi del cluster e inserirli nei prototype della persona.


Quindi il flusso completo diventa

┌──────────────┐ │ photos │ └──────┬───────┘ │ face detector │ ▼ ┌──────────────┐ │ faces │ │ bbox │ │ embedding │ └──────┬───────┘ │ ┌──────────┴──────────┐ │ │ inizializzazione nuove foto │ │ ▼ ▼ HDBSCAN prototype search │ │ ▼ ▼ clusters person_id │ UI utente │ ▼ persons

E soprattutto questa struttura è compatibile con il benchmark OpenCL che stiamo facendo: il DB rimane il persistente, mentre indices[N×32], distanze, MST ecc. rimangono dati di lavoro GPU/CPU e non devono necessariamente finire in SQLite.

Prima di scrivere init.js

Mi manca solo una verifica: hai già codice che estrae i volti / genera gli embedding RKNN?

Se sì, mandami il file che attualmente gestisce quella parte. Così possiamo progettare faces attorno al formato reale dell'output RKNN e non creare una seconda rappresentazione incompatibile.