William Zhang2026-09-20

Système intelligent de reconnaissance faciale avec reComputer R2135

Détection, alignement et regroupement de personnes et de visages en vidéo directement sur le reComputer (NPU Hailo-8) avec YOLOv8n + SCRFD-10G + ArcFace MobileFaceNet. Génère automatiquement un « album de visages » archivé par personne, consultable via une page web minimaliste.

CVFace RecognitionYOLOGitHub

Construction automatique d'un album de visages à partir de vidéos sur reComputer

Un projet d'archivage automatique d'album de visages basé sur Hailo-8 / SCRFD / ArcFace, exécuté sur l'appareil.

Vous pouvez consulter le code source de ce projet sur GitHub : https://github.com/doublelf/person_face_sign


1. Présentation du projet

Person Face Sign est un projet de construction hors-ligne d'un « album de visages » sur un appareil edge (reComputer + NPU Hailo-8). L'objectif principal est d'affecter automatiquement tous les visages présents dans une vidéo de surveillance ou d'activité à leur « album d'identité » respectif, afin de faciliter la recherche ultérieure, les statistiques ou l'archivage.

Problèmes typiques résolus

  • Enregistrement des visiteurs / gestion de l'accueil : transmettez au script plusieurs heures d'enregistrement de la caméra d'accueil, et il génère automatiquement « 23 personnes sont venues aujourd'hui, avec N images chacune ».
  • Aide au pointage en classe / réunion : les enregistrements de cours sont archivés par tête, servant de base à l'appel électronique.
  • Organisation de photos d'événement : fusionnez et regroupez des prises multi-angle et multivue sur place afin de générer automatiquement des albums par personne.
  • Recherche secondaire dans un fichier vidéo : chercher par personne, et non par horodatage.

Pipeline principal

Code
Vidéo (data/*.mp4)
    │
    ▼
[VideoSampler] —— 1 image par seconde (1280×720)
    │
    ▼
[YOLOv8n] —— Détection de personnes (640×640)
    │
    ▼
[IoUTracker] —— Suivi de personnes + échantillonnage de visage limité (désactivable)
    │
    ▼
[SCRFD-10G] —— Détection de visage + 5 landmarks
    │
    ▼
[FaceAlign 5pt] —— Alignement affine à 112×112
    │
    ▼
[ArcFace MobileFaceNet] —— Embedding L2-norm 512-d
    │
    ▼
[AlbumCluster] —— pHash prioritaire / Faiss HNSW en repli → attribution de person_id
    │
    ▼
[AlbumStorage] —— Écriture des fichiers + double dédup + mise à jour de manifest.json
    │
    ▼
[Web Browser :8080] —— Parcourir / rechercher le résultat

2. Démarrage rapide

Voici un flux de bout en bout qui, exécuté dans l'ordre, permet de construire un album de visages consultable sur le reComputer.

2.1 Cloner le dépôt

bash
git clone https://github.com/doublelf/person_face_sign.git
cd person_face_sign

2.2 Créer l'environnement virtuel

L'utilisation de venv est recommandée (inclus dans Python, aucune installation supplémentaire requise).

bash
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip

2.3 Installer les dépendances Python

bash
pip install -r requirements.txt

2.4 Installer les dépendances système préalables

build_album.py invoque ffmpeg / ffprobe via subprocess pour l'échantillonnage d'images ; ces outils doivent être installés au niveau du système :

bash
# Debian / Ubuntu (y compris reComputer)
sudo apt update
sudo apt install -y ffmpeg

# Vérifier
ffmpeg -version | head -n 1
ffprobe -version | head -n 1

2.5 Préparer les fichiers de modèle HEF

Code
person_face_sign/
└── models/
    ├── yolov8n.hef                    # ~4.3 MB
    ├── scrfd_10g.hef                  # ~10 MB
    └── arcface_mobilefacenet.hef      # ~5 MB
UsageModèleChemin par défaut (codé en dur dans build_album.py)Source réelle
Détection de personnesYOLOv8n<racine du projet>/models/yolov8n.hefIntégré dans l'image Docker officielle, chemin dans le conteneur /app/model/yolov8n.hef
Détection de visagesSCRFD-10G<racine du projet>/models/scrfd_10g.hefInclus dans le paquet .deb de HailoRT (peut être copié dans models/)
Embedding de visagesArcFace MobileFaceNet<racine du projet>/models/arcface_mobilefacenet.hefInclus dans le paquet .deb de HailoRT (peut être copié dans models/)

2.5.1 Obtenir SCRFD + ArcFace (le plus simple)

Les HEF de SCRFD-10G et ArcFace MobileFaceNet sont des modèles précompilés officiellement par Hailo. Ils sont installés par le paquet hailort dans /usr/local/hailo/resources/models/hailo8/ — il suffit de les copier dans le répertoire models/ de ce projet :

bash
sudo apt install hailort
ls /usr/local/hailo/resources/models/hailo8/
# Vous devriez voir :
#   arcface_mobilefacenet.hef
#   scrfd_10g.hef
#   ainsi que d'autres modèles d'exemple officiels

# Copier vers le répertoire models/ local du projet
cp /usr/local/hailo/resources/models/hailo8/scrfd_10g.hef            models/
cp /usr/local/hailo/resources/models/hailo8/arcface_mobilefacenet.hef models/
ls -lh models/

2.5.2 Obtenir YOLOv8n

Voir https://sensecraft.seeed.cc/ai-lab/en/models/yolov8/hailo-8. Le HEF YOLOv8n est déjà empaqueté dans ghcr.io/seeed-projects/recomputer-r20-cv/yolov8:latest. Le chemin dans le conteneur est /app/model/yolov8n.hef.

bash
mkdir -p models

# 1. Récupérer l'image officielle
docker pull ghcr.io/seeed-projects/recomputer-r20-cv/yolov8:latest

# 2. Créer une instance de conteneur non exécutée via `create` (uniquement pour obtenir le fichier)
docker create --name yolov8-temp ghcr.io/seeed-projects/recomputer-r20-cv/yolov8:latest

# 3. Copier yolov8n.hef depuis le conteneur vers le répertoire models/ du projet
docker cp yolov8-temp:/app/model/yolov8n.hef models/yolov8n.hef

# 4. Nettoyer le conteneur temporaire
docker rm yolov8-temp

# 5. Vérifier
ls -lh models/yolov8n.hef

2.6 Construire l'album de visages (étape principale)

Le dépôt inclut une vidéo de démonstration data/tex.mp4 (environ 11 Mo). Exécutez la commande suivante pour générer l'album :

bash
python apps/build_album.py \
  --video data/tex.mp4 \
  --out data/album \
  --no-tracker \
  --scrfd-score 0.6 \
  --cluster-thresh 0.85 \
  --skip-dedup

Paramètres :

ParamètreValeurDescription
--videodata/tex.mp4Vidéo d'entrée ; peut être spécifié plusieurs fois ou séparé par des virgules
--outdata/albumRépertoire de sortie de l'album
--no-trackerflagDésactive l'IoU tracker ; prend chaque visage sur chaque image (recommandé pour les vidéos courtes)
--scrfd-score0.6Seuil de confiance de détection de visage SCRFD (par défaut 0,60)
--cluster-thresh0.85Regroupement souple : seuil de distance cosinus ; voir la section 4.2 pour plus de détails
--skip-dedupflagSaute le dédoublonnage pHash / embedding à l'écriture (le regroupement privilégiant pHash reste actif)

Une fois la construction terminée, sous data/album/ apparaît :

Code
data/album/
├── manifest.json
├── thumbnails/
│   ├── person_0001.jpg
│   ├── person_0002.jpg
│   └── ...
├── person_0001/
│   ├── representative.jpg
│   ├── info.json
│   ├── embeddings.npz
│   └── img_0001_ts_2.00s_score_0.78.jpg
│   └── img_0002_ts_5.00s_score_0.74.jpg
│   └── ...
├── person_0002/
└── ...

2.7 Démarrer le service web de navigation de l'album

Après la construction, ouvrez un autre terminal et lancez le service web minimaliste :

bash
python apps/web_browser.py --port 8080

Accédez dans le navigateur à http://<reComputer-IP>:8080/ :

  • La barre de statistiques en haut affiche le nombre total de personnes, d'images et de vidéos sources ;
  • La grille principale affiche, selon « 1 image = 1 personne », les miniatures (provenant de representative.jpg, triées par nombre d'images décroissant) ;
  • Cliquez sur une personne pour ouvrir la page de détail listant tous ses img_*.jpg ;
  • Cliquez sur une image pour ouvrir le visualiseur plein écran.

3. Lecture des résultats

3.1 Structure du répertoire de données

Code
data/album/
├── manifest.json                    # Statistiques globales + liste des personnes (source de données de l'UI Web)
├── thumbnails/
│   └── person_<id>.jpg              # Miniature (copie de representative.jpg)
└── person_<NNNN>/                   # Un répertoire par identité ; NNNN est un identifiant à 4 chiffres avec zéros à gauche
    ├── info.json                    # Métadonnées par personne : count / first_ts / last_ts / best_score / source_videos
    ├── embeddings.npz               # Top-N embeddings de cette personne (par défaut N=5, triés par score)
    ├── representative.jpg           # « Photo de couverture » au meilleur score, également copiée dans thumbnails/
    └── img_<NNNN>_ts_<ts>s_score_<score>.jpg  # Chaque visage conservé (après alignement 112×112)

Exemples de convention de nommage :

  • person_0001/img_0001_ts_2.00s_score_0.78.jpg : 1ʳᵉ image, 2,00 secondes, score SCRFD = 0,78
  • person_0001/img_0014_ts_18.50s_score_0.82.jpg : 14ᵉ image, 18,50 secondes

3.2 Champs clés de manifest.json

json
{
  "version": "1.0",
  "created_at": "2026-09-26T10:23:11",
  "updated_at": "2026-09-26T10:24:48",
  "total_persons": 6,
  "total_images": 142,
  "source_videos": ["tex"],
  "config": {
    "interval_s": 1.0,
    "cosine_distance_threshold": 0.85,
    "min_face_size": [40, 40],
    "min_face_score": 0.6,
    "best_n_embeddings": 5,
    "phash_max_dist": 4
  },
  "persons": [
    {
      "id": 1,
      "count": 28,
      "first_ts": 2.0,
      "last_ts": 82.0,
      "best_score": 0.85,
      "source_videos": ["tex"],
      "thumbnail": "thumbnails/person_0001.jpg"
    },
    ...
  ]
}

Signification des champs :

ChampSignification
total_personsNombre total de personnes regroupées (croît de façon monotone avec les builds incrémentiels)
total_imagesNombre total d'images de visages (après déduplication)
configInstantané des paramètres de ce build (réécrit dans l'album pour la traçabilité)
persons[].countNombre d'images de visage pour cette personne
persons[].first_ts / last_tsHorodatage de la première / dernière apparition (secondes)
persons[].best_scoreMeilleur score de détection SCRFD

3.3 Interactions de l'UI Web

Le front-end s'appuie uniquement sur http.server + HTML/CSS/JS statique, sans base de données ; toutes les données sont lues en temps réel depuis manifest.json et le système de fichiers.

Principaux flux d'interaction :

  1. Page d'accueil (/) : récupère /manifest.json, liste les miniatures de toutes les personnes par count décroissant ;
  2. Détail d'une personne : cliquer sur une miniature → le backend fait un glob de person_<id>/img_*.jpg → liste toutes les images ;
  3. Aperçu d'image : cliquer sur une image → modale plein écran <dialog> ;
  4. Rafraîchir : cliquer sur ↻ en haut pour recharger manifest.json.