William Zhang2026-09-20

Intelligent Face Recognition System on the reComputer R2135

Uses YOLOv8n + SCRFD-10G + ArcFace MobileFaceNet on a reComputer (Hailo-8 NPU) to detect, align, and cluster pedestrians and faces in video, automatically building a face album organized by person that can be browsed from a minimal web page.

CVFace RecognitionYOLOGitHub

Automatic Face Album Construction from Video on the reComputer

An on-device project for automatically archiving face albums based on Hailo-8 / SCRFD / ArcFace.

The project source is available on GitHub: https://github.com/doublelf/person_face_sign


1. Project Overview

Person Face Sign is a project that builds a "face album" entirely offline on an edge device (reComputer + Hailo-8 NPU). Its core goal is to automatically group every face that appears in a piece of surveillance or activity video into individual "identity albums", so they can be browsed, counted, or archived afterwards.

Typical problems it solves

  • Visitor registration / visitor management: hand a few hours of front-desk camera footage to the script and get a result like "23 people visited today, N images per person".
  • Classroom / meeting attendance assistance: archive course recordings by person as the basis for electronic roll-call.
  • Automatic organization of event photos: merge and cluster multi-camera, multi-angle event footage and automatically produce an album grouped by person.
  • Secondary retrieval of video assets: find people by face instead of by timestamp.

Core pipeline

Code
Video (data/*.mp4)
    │
    ▼
[VideoSampler] —— 1 frame every 1 second (1280×720)
    │
    ▼
[YOLOv8n] —— Pedestrian detection (640×640)
    │
    ▼
[IoUTracker] —— Pedestrian tracking + throttled face sampling (optional)
    │
    ▼
[SCRFD-10G] —— Face detection + 5-point landmarks
    │
    ▼
[FaceAlign 5pt] —— Affine alignment to 112×112
    │
    ▼
[ArcFace MobileFaceNet] —— 512-d L2-normalized embedding
    │
    ▼
[AlbumCluster] —— pHash-first / Faiss HNSW fallback → assign person_id
    │
    ▼
[AlbumStorage] —— Write files + dual deduplication + update manifest.json
    │
    ▼
[Web Browser :8080] —— Browse / search the output

2. Quick Start

The following is an end-to-end reproduction procedure. Execute the steps in order to build a browsable face album on the reComputer.

2.1 Clone the repository

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

2.2 Create a virtual environment

venv is recommended (built into Python, no extra install required).

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

2.3 Install Python dependencies

bash
pip install -r requirements.txt

2.4 Install system-level prerequisites

build_album.py calls ffmpeg / ffprobe via subprocess for frame-skipping sampling; these must be installed at the system level:

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

# Verify
ffmpeg -version | head -n 1
ffprobe -version | head -n 1

2.5 Prepare the HEF model files

Code
person_face_sign/
└── models/
    ├── yolov8n.hef                    # ~4.3 MB
    ├── scrfd_10g.hef                  # ~10 MB
    └── arcface_mobilefacenet.hef      # ~5 MB
PurposeModelDefault path (hardcoded in build_album.py)Actual source
Pedestrian detectionYOLOv8n<project_root>/models/yolov8n.hefBundled in the official Docker image, container path /app/model/yolov8n.hef
Face detectionSCRFD-10G<project_root>/models/scrfd_10g.hefBundled with the HailoRT deb package (can be copied to models/)
Face embeddingArcFace MobileFaceNet<project_root>/models/arcface_mobilefacenet.hefBundled with the HailoRT deb package (can be copied to models/)

2.5.1 Get SCRFD + ArcFace (easiest)

The SCRFD-10G and ArcFace MobileFaceNet HEFs are official pre-compiled Hailo models, installed to /usr/local/hailo/resources/models/hailo8/ by the hailort deb package. Just copy them into this project's models/ directory:

bash
sudo apt install hailort
ls /usr/local/hailo/resources/models/hailo8/
# You should see:
#   arcface_mobilefacenet.hef
#   scrfd_10g.hef
#   plus several other official sample models

# Copy them to the project's local models/ directory
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 Get YOLOv8n

See https://sensecraft.seeed.cc/ai-lab/en/models/yolov8/hailo-8. The YOLOv8n HEF is bundled inside ghcr.io/seeed-projects/recomputer-r20-cv/yolov8:latest; the container path is /app/model/yolov8n.hef.

bash
mkdir -p models

# 1. Pull the official image
docker pull ghcr.io/seeed-projects/recomputer-r20-cv/yolov8:latest

# 2. Create (but do not start) a temporary container instance just to grab the file
docker create --name yolov8-temp ghcr.io/seeed-projects/recomputer-r20-cv/yolov8:latest

# 3. Copy yolov8n.hef from the container into the project's models/ directory
docker cp yolov8-temp:/app/model/yolov8n.hef models/yolov8n.hef

# 4. Clean up the temporary container
docker rm yolov8-temp

# 5. Verify
ls -lh models/yolov8n.hef

2.6 Build the face album (core step)

The repository ships a demo video data/tex.mp4 (about 11 MB). Run the command below to generate the 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

Parameter reference:

ParameterValueDescription
--videodata/tex.mp4Input video; can be specified multiple times or comma-separated
--outdata/albumAlbum output directory
--no-trackerflagDisable the IoU tracker; sample every face in every frame (recommended for short sample videos)
--scrfd-score0.6SCRFD face detection confidence threshold (default 0.60)
--cluster-thresh0.85Loose clustering: cosine distance threshold; see section 4.2
--skip-dedupflagSkip the pHash / embedding dual deduplication on write (pHash-first clustering is still retained)

After the build completes, the following layout appears under data/album/:

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 Start the web album browser

After the build finishes, open another terminal and start the minimal web service:

bash
python apps/web_browser.py --port 8080

Open http://<reComputer-IP>:8080/ in a browser:

  • The top stats bar shows total persons, total images, and source video count.
  • The main grid displays thumbnails, one per person (the thumbnail is the representative.jpg, sorted by image count descending).
  • Click a person to enter the detail page, which shows all img_*.jpg of that person.
  • Click any image to open a fullscreen viewer.

3. Reading the Output

3.1 Data directory structure

Code
data/album/
├── manifest.json                    # Global stats + person list (data source for the Web UI)
├── thumbnails/
│   └── person_<id>.jpg              # Thumbnail (a copy of representative.jpg)
└── person_<NNNN>/                   # One directory per identity; NNNN is a 4-digit zero-padded id
    ├── info.json                    # Per-person metadata: count / first_ts / last_ts / best_score / source_videos
    ├── embeddings.npz               # Top-N embeddings for this person (default N=5, sorted by score)
    ├── representative.jpg           # Highest-scoring cover image, also written to thumbnails/
    └── img_<NNNN>_ts_<ts>s_score_<score>.jpg  # Each retained face (after 112×112 alignment)

File naming convention examples:

  • person_0001/img_0001_ts_2.00s_score_0.78.jpg: 1st image, 2.00 s, SCRFD score = 0.78
  • person_0001/img_0014_ts_18.50s_score_0.82.jpg: 14th image, 18.50 s

3.2 Key fields in 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"
    },
    ...
  ]
}

Field descriptions:

FieldDescription
total_personsTotal number of clustered persons (monotonically increasing on continued builds)
total_imagesTotal number of face images (after deduplication)
configSnapshot of the build parameters (written back to the album for traceability)
persons[].countNumber of face images for this person
persons[].first_ts / last_tsFirst / last appearance timestamp (seconds)
persons[].best_scoreHighest SCRFD detection score

3.3 Web UI interaction

The web side is built on plain http.server + static HTML/CSS/JS with no database dependency; all data is read live from manifest.json and the file system.

Main interaction paths:

  1. Home page (/): fetches /manifest.json and lists thumbnails for all persons sorted by count descending;
  2. Person detail: click a thumbnail → the backend globs person_<id>/img_*.jpg → all images are listed;
  3. Full-size preview: click an image → fullscreen <dialog> popup;
  4. Refresh: click the top ↻ to refetch manifest.json.