Pipeline cosma-qc
Vue d’ensemble
Le pipeline cosma-qc traite les vidéos GoPro brutes acquises par les drones sous-marins AUV COSMA pour produire des nuages de points 3D denses (PLY) et des exports web (GLB).
Flux de données global
z620 (/mnt/portablessd)
├── GX*.MP4 (brut)
│
▼ [1. Ingest]
SQLite DB (jobs)
│
▼ [2. Extraction ffmpeg]
GPU worker /cosma-qc-frames/job_{id}/frame_%06d.jpg
│
▼ [3. Reconstruction lingbot-map]
GPU worker /cosma-qc-frames/job_{id}/reconstruction.ply
│
▼ [4. Stitch per_auv]
GPU worker /cosma-qc-frames/stitch_{N}.ply (par AUV)
│
▼ [5. Stitch cross_auv]
GPU worker /cosma-qc-frames/stitch_global.ply
│
▼ [6. Export GLB (à la demande)]
GPU worker /cosma-qc-frames/job_{id}/reconstruction.glb
Étape 1 — Ingest
Script : scripts/ingest.py
Rôle : Scanner le SSD de z620, regrouper les MP4 GoPro par AUV/GoPro/segment temporel et écrire les jobs dans la base SQLite.
Logique de regroupement :
Les fichiers sont groupés par numéro de caméra GoPro (GXXX).
Un nouveau segment est créé si l’écart entre deux fichiers dépasse 5 minutes.
Chaque segment → un job en base avec statut pending.
Structure d’un job en base :
CREATE TABLE jobs (
id INTEGER PRIMARY KEY,
auv TEXT,
gopro TEXT,
segment INTEGER,
files TEXT, -- JSON list of z620:/path/GX*.MP4
status TEXT, -- pending / running / done / failed
worker TEXT,
created_at TIMESTAMP,
updated_at TIMESTAMP
);
Les chemins vidéo sont stockés sous la forme z620:/chemin/absolu/GX*.MP4 pour indiquer que la source est sur z620, pas sur le worker GPU.
Étape 2 — Extraction des frames
Fonction : do_extract dans le dispatcher (core .82)
Outil : ffmpeg
Paramètres d’extraction :
ffmpeg -i input.mp4 -vf fps=2,scale=1920:1080 -q:v 2 {frames_dir}/job_{id}/frame_%06d.jpg
Particularité z620 : lorsque la source est z620:/…, ffmpeg s’exécute directement sur z620 via SSH — seuls les JPEG voyagent sur le réseau. Les MP4 bruts ne quittent jamais z620.
Filtre hors-eau (heuristique de luminosité) :
Les frames dont la luminosité moyenne est au-dessus d’un seuil sont supprimées (ciel, surface, hors-eau).
Ce filtre réduit le bruit dans la reconstruction.
Reprise sur crash :
Un fichier marqueur .video_N.done est créé après chaque MP4 traité.
En cas de redémarrage, les vidéos déjà traitées sont ignorées.
Étape 3 — Reconstruction 3D
Fonction : do_reconstruct
Outil : lingbot-map (demo.py) sur le worker GPU
Entrée : répertoire de frames {worker_frames_dir}/job_{id}/
Sortie : {worker_frames_dir}/job_{id}/reconstruction.ply (nuage de points dense, jusqu’à 150 millions de points)
Un viewer Viser est automatiquement démarré sur le port 8100 + job_id pendant la reconstruction pour visualisation en temps réel.
# Visualiser pendant reconstruction
# naviguer vers http://{worker_ip}:{8100+job_id}
Étape 4 — Stitch par AUV
Fonction : do_stitch_per_auv
Déclenchement : automatique quand tous les jobs d’un AUV sont en statut done.
Outil : cosma-stitch.py
Opération : alignement et fusion des PLY de tous les segments d’un même AUV.
Sortie : {worker_frames_dir}/stitch_{N}.ply
Ce stitch s’exécute sur le worker qui détient les PLY (pas de copie inter-workers).
Étape 5 — Stitch cross-AUV
Fonction : do_stitch_cross_auv
Déclenchement : automatique quand tous les stitches per_auv sont validés.
Opération : fusion de tous les PLY par AUV en un nuage de points global final.
Sortie : {worker_frames_dir}/stitch_global.ply
Étape 6 — Export GLB (à la demande)
Outil : trimesh (conversion PLY → GLB)
Sous-échantillonnage : 5 millions de points (adapté web/navigateur)
Sortie : {worker_frames_dir}/job_{id}/reconstruction.glb
Un serveur HTTP minimal est lancé sur le worker (port 8300) pour le téléchargement :
# Sur le worker
python3 -m http.server 8300 --directory {worker_frames_dir}
# Télécharger depuis un PC
wget http://{worker_ip}:8300/job_{id}/reconstruction.glb
Statuts de jobs
Statut |
Description |
|---|---|
pending |
Job créé, en attente de dispatch |
running |
En cours de traitement (extraction ou reconstruction) |
done |
Reconstruction terminée, PLY disponible |
failed |
Erreur — voir logs du dispatcher |