484 lines
25 KiB
Markdown
484 lines
25 KiB
Markdown
# Pipeline de reconstruction Lardon3D
|
||
|
||
## Vision
|
||
|
||
Lardon3D ne doit plus être décrit simplement comme « dossier de photos → objet 3D ». La vision cible est :
|
||
|
||
> « ensemble progressif d'observations et de contraintes
|
||
> → reconstruction géométrique persistante, enrichissable et versionnable »
|
||
|
||
Chaque ajout d'images, de mesures ou de documents enrichit la reconstruction
|
||
existante sans détruire les résultats antérieurs. L'utilisateur peut
|
||
interrompre le pipeline à tout instant, consulter l'état courant via le
|
||
viewer, puis reprendre ultérieurement exactement où il s'était arrêté.
|
||
|
||
---
|
||
|
||
## Étapes du pipeline
|
||
|
||
### A. Scan Sets / acquisitions
|
||
|
||
| Aspect | Description |
|
||
|--------|-------------|
|
||
| **Définition** | Un *scan set* (ou acquisition) regroupe un ensemble d'images capturées dans un contexte donné : même lieu, même session, même objectif de reconstruction. |
|
||
| **Enrichissement progressif** | Un scan set peut être alimenté par vagues successives : images initiales, images de relèvement, images de contrôle. Chaque vague est horodatée et traçable. |
|
||
| **Identification stable** | Chaque ScanSet reçoit un `scanset_id` SQLite positif qui ne dépend pas de son nom. |
|
||
|
||
**Statut :** IMPLEMENTED v1 — identité, nom et horodatages persistants. Les
|
||
vagues et relations géométriques entre acquisitions restent planifiées.
|
||
|
||
---
|
||
|
||
### B. Image Catalog
|
||
|
||
| Aspect | Description |
|
||
|--------|-------------|
|
||
| **Identité stable** | Chaque image possède un `image_id` stable, distinct du nom et de l'asset physique. |
|
||
| **Provenance** | Le catalogue enregistre le ScanSet, la date d'import, le nom et le chemin source, ainsi que la tâche productrice éventuelle. |
|
||
| **Asset** | Le contenu physique est identifié par `asset_id`, SHA-256, taille et chemin géré. Plusieurs images logiques peuvent partager cet asset. |
|
||
|
||
**Statut :** IMPLEMENTED v1 — catalogue SQLite paginé et assets
|
||
content-addressed. Les états Feature/Matching/Reconstruction restent planifiés.
|
||
|
||
---
|
||
|
||
### C. Feature Extraction et Feature Store
|
||
|
||
| Aspect | Description |
|
||
|--------|-------------|
|
||
| **Extraction** | ORB coarse, SIFT précis et RootSIFT, chacun avec sa tâche durable. |
|
||
| **Métadonnées persistantes** | `FeatureSet` logique et `FeatureAsset` physique content-addressed dans ProjectDb v7. |
|
||
| **Données numériques massives** | ORB U8×32 v1 et SIFT/RootSIFT F32×128 v2 restent hors SQLite. |
|
||
| **Lecture bornée** | Le reader lit au plus 256 features par plage et ne charge pas tout le fichier. |
|
||
|
||
**Statut :** IMPLEMENTED v1 — extraction, publication atomique, reprise et reader borné.
|
||
|
||
**Extension v1A :** ORB reste la passe coarse et l'unique entrée du Visual
|
||
Index ORB-LSH. SIFT/RootSIFT F32×128 sont des passes précises indépendantes,
|
||
suivies d'une consolidation spatiale intra-image qui ne mélange jamais les
|
||
descriptors.
|
||
|
||
---
|
||
|
||
### D. Visual Index
|
||
|
||
| Aspect | Description |
|
||
|--------|-------------|
|
||
| **Choix basé sur le contenu visuel** | Le *visual index* permet de retrouver rapidement les images visuellement proches d'une image donnée, sans comparaison exhaustive. Structure type : vocabulaire visuel inversé ou similarité locality-sensitive hashing. |
|
||
| **Pipeline conceptuel** | Extraction de features globales → construction de l'index → requête par similarité → retour des K plus proches voisins. |
|
||
| **Proximité temporelle comme signal secondaire** | Lorsque les images portent un horodatage EXIF, la proximité temporelle sert de signal complémentaire au contenu visuel, mais ne remplace jamais l'analyse visuelle. |
|
||
|
||
**Statut :** IMPLEMENTED v1 — LSH binaire déterministe, segments immuables,
|
||
updates incrémentales et query top-K bornée. Le générateur de paires reste planifié.
|
||
|
||
---
|
||
|
||
### E. Candidate Pair Generator
|
||
|
||
| Aspect | Description |
|
||
|--------|-------------|
|
||
| **Sources de paires candidates** | (1) Visual index : paires visuellement proches. (2) Proximité temporelle. (3) Scan set commun. (4) Géométrie approximative (si GPS/IMU disponible). |
|
||
| **Matching coûteux limité** | Le nombre de paires soumises au matching géométrique (étape F) doit être borné. Le candidate generator filtre et classe pour ne garder que les paires les plus prometteuses. |
|
||
| **Persistance** | Les paires candidates sont persistées dans la table `candidate_pairs` (Project DB v8). Ordre canonique : `image_id_a < image_id_b`. Self-pairs interdits. Unicité garantie. |
|
||
| **Déterminisme** | Pour mêmes entrées et configuration, le générateur produit les mêmes paires dans le même ordre. |
|
||
| **Idempotence** | L'exécution répétée ne crée pas de doublons. |
|
||
|
||
**Statut :** IMPLEMENTED v1 — génération single-source et batch depuis Visual
|
||
Index, persistance, canonicalisation, idempotence et tâche durable.
|
||
|
||
---
|
||
|
||
### F. Matching de descripteurs
|
||
|
||
| Aspect | Description |
|
||
|--------|-------------|
|
||
| **Matcher v1** | ORB CPU/Vulkan ; SIFT/RootSIFT L2 CPU (Vulkan rejeté) ; k=2 + Lowe ; sans géométrie. |
|
||
| **Persistance** | Match Result NO_MATCH/MATCHED et Match File content-addressed validé. |
|
||
| **Orchestration** | `matcher.run` traite les Candidate Pairs par pages et lots durables de 1/2/4/8. |
|
||
|
||
**Statut :** IMPLEMENTED v1 — Matcher, Match Store, reprise idempotente et Task
|
||
durable. Le Geometric Verifier consomme désormais ces résultats.
|
||
Le Match Result appartient à Project DB v10 et la tâche durable `matcher.run`
|
||
à Project DB v11.
|
||
|
||
### F2. Geometric Verification
|
||
|
||
Project DB v12 implémente le modèle scientifique persistant. Chaque
|
||
résultat appartient à un Match Result `MATCHED`, possède une identité exacte,
|
||
un masque compact borné et, si VERIFIED, une matrice fondamentale 3×3 finie.
|
||
La publication est atomique et immutable. Project DB v13 ajoute uniquement la
|
||
persistance de `geometric_verifier.run` v1. Le calcul Fundamental emploie
|
||
USAC/MAGSAC avec configuration, seed et fingerprint déterministes.
|
||
|
||
**Statut :** IMPLEMENTED v1 — MODEL, VERIFIER ET TASK DURABLE.
|
||
|
||
---
|
||
|
||
### G. Tracks
|
||
|
||
| Aspect | Description |
|
||
|--------|-------------|
|
||
| **Observation 2D → track → point3D** | Un *track* est une chaîne d'observations 2D cohérentes d'un même point 3D à travers plusieurs images. Chaque observation est un keypoint indexé par image. |
|
||
| **Lien avec le catalogue** | Les tracks référenceront les images par `image_id`, jamais par nom ou chemin. |
|
||
| **Persistance** | Les tracks sont persistés entre les sessions de traitement. Un track ne peut être détruit que par une action explicite de l'utilisateur. |
|
||
|
||
**Statut :** COMPLETED/FROZEN — le Track Builder v1 direct et durable est
|
||
implémenté dans Project DB v15 (`track_sets`, `tracks`, `track_observations` et
|
||
le payload de tâche). Les primitives de géométrie calibrée Gate C sont
|
||
implémentées et le noyau Sparse SfM incrémental Gate D est IMPLEMENTED / PASS ;
|
||
le Bundle Adjustment final Gate E est PASS / FROZEN ; l'orchestration projet
|
||
et tâche Gate F est PASS / FROZEN.
|
||
Le modèle de persistance Sparse SfM v16 est gelé après Gate B.
|
||
|
||
**Sparse SfM Gate A : PASS.** Le contrat géométrique, la stratégie
|
||
incremental, la triangulation candidate, le gauge, les conventions de pose,
|
||
les limites BA et l'enveloppe matérielle sont documentés dans
|
||
`architecture/sparse_sfm.md`. Ses primitives pures calibrées Gate C sont
|
||
**IMPLEMENTED / PASS** et son noyau incrémental synchrone en mémoire Gate D est
|
||
**IMPLEMENTED / PASS**. Le Bundle Adjustment final par composante Gate E est
|
||
**PASS / FROZEN**. L'orchestration Gate F est **PASS / FROZEN**. Le modèle de
|
||
reconstruction v16 et ses lecteurs bornés restent ceux de B2 ; le payload de
|
||
tâche Gate F est l'ajout v17.
|
||
|
||
---
|
||
|
||
### H. Reconstruction incrémentale
|
||
|
||
La phase H est une étape du pipeline, pas un « Gate H ». Sa version 1 enrichit
|
||
scientifiquement un snapshot Sparse SfM publié, sans réexécuter Gate F depuis
|
||
zéro. Ses entrées immuables sont l'identité de la reconstruction de base,
|
||
l'identité d'un Track Set d'extension et l'identité d'un scope de calibration.
|
||
Son identité scientifique est :
|
||
|
||
```
|
||
(base_reconstruction_identity, extension_track_set_identity,
|
||
calibration_scope_identity, incremental_kind, incremental_version,
|
||
parameter_fingerprint)
|
||
```
|
||
|
||
L'enregistrement canonique `L3DHIDV1` est encodé little-endian puis condensé
|
||
par SHA-256. Le fingerprint H v1, distinct de F0, encode `L3DHPRM1`, sa version
|
||
et les politiques versionnées suivantes : filiation stricte par identité
|
||
d'observation `(feature_set_id, feature_index)`, absence de split/merge,
|
||
`STRICT_DESCENDANT_REGISTERED_OBSERVATIONS_V1`,
|
||
`PRESERVE_BASE_COMPONENT_KEY_V1`, absence de fusion de composantes de base,
|
||
politiques scientifiques Gate D v1 pour PnP/triangulation/raffinement, BA
|
||
complète Gate E v1 de chaque composante affectée, calibration historique
|
||
exacte, préservation du gauge historique, snapshot complet immuable,
|
||
ordre canonique et absence de nouvelle composante déconnectée. Matériel,
|
||
ressources, tâche, chemins, horodatages et télémétrie sont exclus.
|
||
L'enregistrement de fingerprint fait exactement 80 octets ; son vecteur doré
|
||
SHA-256 v1 est
|
||
`f44a89b23b520481701848ecf175638e82f2c9e25b70a01f3eb767bf28446cd8`.
|
||
Après le magic et les deux versions `u32`, ses seize champs `u32` versionnés
|
||
sont, dans l'ordre : `STRICT_OBSERVATION_LINEAGE`, `NO_SPLIT`, `NO_MERGE`,
|
||
`STRICT_DESCENDANT_REGISTERED_OBSERVATIONS`, `PRESERVE_BASE_COMPONENT_KEY`,
|
||
`NO_BASE_COMPONENT_MERGE`, `GATE_D_PNP_REGISTRATION`,
|
||
`GATE_D_TRIANGULATION_REFINEMENT`, `FULL_AFFECTED_COMPONENT_BA`,
|
||
`GATE_E_POLICY`, `EXACT_HISTORICAL_CALIBRATION`, `HISTORICAL_BASE_GAUGE`,
|
||
`COMPLETE_IMMUTABLE_SNAPSHOT`, `CANONICAL_ID_ORDER`,
|
||
`NO_DISCONNECTED_COMPONENT` et `TERMINAL_BA_FAILURE`. Chaque valeur vaut 1
|
||
en H v1 ; la position identifie la politique sans chaîne dépendante de locale.
|
||
|
||
La filiation est dérivée par indexation déterministe des observations, jamais
|
||
par égalité de `track_id` entre générations. Chaque Track historique publié a
|
||
un unique descendant contenant exactement toutes ses observations historiques.
|
||
Un historique manquant, dupliqué, scindé, fusionné ou reliant deux composantes
|
||
de base invalide toute la mise à jour. Une observation ajoutée à un descendant
|
||
historique dont l'image nouvelle reste non enregistrée dans sa composante
|
||
invalide également toute la mise à jour ; une image non enregistrée qui ne
|
||
porte que des Tracks nouveaux reste admissible et ne crée pas de composante.
|
||
|
||
Chaque caméra nouvelle est localisée dans exactement une composante historique.
|
||
Les composantes de base ne fusionnent pas et gardent leur `component_key`, égal
|
||
au plus petit `image_id` historique enregistré. Une caméra géométriquement
|
||
enregistrée dont l'ID est inférieur à cette clé rend la mise à jour
|
||
incompatible ; elle n'est pas maquillée en rejet géométrique. Les landmarks
|
||
existants reçoivent leurs observations descendantes admissibles, les Tracks
|
||
nouveaux entièrement ancrés peuvent être triangulés, puis chaque composante
|
||
affectée subit une BA complète avec les ancres historiques. Une composante non
|
||
affectée est copiée sans modification scientifique.
|
||
|
||
La sortie est un snapshot complet, autonome et immuable. Le prédécesseur est
|
||
une provenance, jamais une dépendance de lecture en chaîne. Publication et
|
||
métadonnées H sont atomiques ; toute erreur de filiation, calibration,
|
||
compatibilité de clé, géométrie, BA, annulation ou base de données ne publie
|
||
rien et ne modifie pas le prédécesseur. Une identité H déjà publiée est
|
||
réutilisée avant matérialisation lourde. Une extension sans effet scientifique
|
||
retourne explicitement le prédécesseur sans publier une génération factice.
|
||
Les métriques globales sont recalculées après la BA sur chaque observation
|
||
finalement retenue, avec la projection pixel Gate F. Une profondeur invalide,
|
||
un résidu non fini ou un ensemble vide rend la publication impossible.
|
||
|
||
L'API scientifique publique valide aussi la cohérence complète du snapshot de
|
||
base : landmark, Track, caméra, composante et position canonique de chaque
|
||
observation doivent correspondre. Son résultat doit être initialisé à zéro ou
|
||
avoir été préalablement détruit avant un nouvel appel.
|
||
|
||
L'orchestration appartient à la tâche durable `incremental_reconstruction.run`
|
||
v1, atomique (lot 1..1), sans DAG ni état scientifique intermédiaire durable.
|
||
Après redémarrage elle recommence depuis les entrées immuables. Son estimation
|
||
opérationnelle H v1 est, avec arithmétique `uint64_t` vérifiée et arrondi au MiB
|
||
supérieur :
|
||
|
||
```
|
||
raw = 268435456
|
||
+ base_cameras * 131072
|
||
+ base_landmarks * 4096
|
||
+ base_observations * 1024
|
||
+ extension_images * 131072
|
||
+ extension_tracks * 4096
|
||
+ extension_observations * 1024
|
||
```
|
||
|
||
Elle est CPU, fixe, `min_batch_size=max_batch_size=1`, demande un thread CPU,
|
||
zéro slot GPU et un slot IO. Elle est persistée avec la tâche, exclue de
|
||
l'identité et admise uniquement par Queue → Governor → Reservation. Pression
|
||
mémoire et ressources ne modifient jamais la science.
|
||
|
||
Project DB v18 ajoute seulement les métadonnées d'identité/prédécesseur H et
|
||
le payload de tâche H. Le parent générique conserve le vrai fingerprint de
|
||
paramètres et porte l'identité H dans son `derivation_identity` nullable ; les
|
||
lignes Gate F gardent ce champ à `NULL` et leur unicité historique. La
|
||
géométrie reste un snapshot complet conforme au
|
||
modèle historique ; aucun sous-ensemble d'observations, remappage de clé ou
|
||
graphe de filiation générique n'est introduit.
|
||
|
||
**Statut :** PASS / FROZEN — contrat H v1 implémenté et validé. Validation
|
||
finale : suite normale 42/42 PASS ; suite ciblée ASan/UBSan/LSan 5/5 PASS ;
|
||
revue finale indépendante PASS ; `git diff --check` PASS. Restent différés :
|
||
généalogie complexe, split/merge légitime,
|
||
fusion de composantes, BA locale, DAG, étapes scientifiques intermédiaires
|
||
durables, scratch/SSD, GPU SfM/BA et nouvelles composantes déconnectées.
|
||
|
||
---
|
||
|
||
### MVS-M1. Dense externe borné
|
||
|
||
MVS-M1 est **IMPLEMENTED / VALIDATION PENDING**. Son identité scientifique lie
|
||
l'identité de reconstruction de base, l'identité du jeu d'images source, le
|
||
`calibration_scope_identity` historique, le binding numérique de calibration MVS,
|
||
le backend et les paramètres. Les octets des sources restent liés séparément par
|
||
leur SHA-256 ; ils ne sont pas remplacés par le binding de calibration. Le record
|
||
d'identité dense est `L3DMDID2`, version 2, de taille fixe 220 octets. Sa frontière
|
||
externe est OpenMVS v2.4.0 : Sparse/H est exporté vers COLMAP, puis traité par
|
||
`InterfaceCOLMAP` et `DensifyPointCloud`.
|
||
|
||
Le binding numérique de calibration est le record `L3DMCAL1`, version 1. Il est
|
||
formé après tri strict des `image_id` et rejet des identifiants dupliqués ; tous
|
||
les entiers et binary64 y sont encodés explicitement en little-endian de largeur
|
||
fixe. Les NaN et infinis sont rejetés et toute valeur `-0` est canonisée en `+0`
|
||
avant l'encodage. Il lie, pour chaque image, son identifiant, ses dimensions et
|
||
les paramètres numériques de calibration utilisés par l'undistortion.
|
||
|
||
L'export COLMAP est déterministe et écrit en flux : locale classique, notation
|
||
scientifique et précision binary64 fidèle au round-trip (`max_digits10 - 1`
|
||
chiffres après le point). Les images et les observations source sont undistordues
|
||
de façon déterministe avec OpenCV ; les observations exportées sont les
|
||
coordonnées transformées. `points3D.txt` contient les tracks COLMAP réels,
|
||
produits dans l'ordre déterministe à partir d'un index de landmarks et de leurs
|
||
observations : l'export ne rescane pas quadratiquement les observations pour
|
||
chaque landmark.
|
||
|
||
Chaque invocation crée sous le staging fourni par l'appelant un espace de travail
|
||
privé neuf. Aucune scène, profondeur, cache ou sortie d'une invocation antérieure
|
||
n'est recherchée ni réemployée. Les images undistordues et tous les intermédiaires
|
||
COLMAP/OpenMVS restent dans cet espace de travail.
|
||
|
||
Le résultat accepté est le PLY fusionné ; `fusion_mode` doit être 0. Le lecteur
|
||
valide le format de sortie par défaut d'OpenMVS v2.4.0 : PLY binaire
|
||
little-endian. Le plafond d'en-tête est de 1 MiB et compte les octets bruts :
|
||
une fin de ligne CRLF consomme donc deux octets, contrairement à LF. Les règles
|
||
de lignes acceptent LF et CRLF ; un CR seul malformé est rejeté. Chaque ligne
|
||
est bornée à 64 KiB. Le lecteur borne les listes de propriétés `view_indices` et
|
||
`view_weights` avant
|
||
allocation ou lecture de leur contenu, et valide les valeurs numériques sans
|
||
dépendre de la locale du processus.
|
||
|
||
La capacité CPU-only est conditionnelle : le probe borné interroge chaque
|
||
exécutable backend, vérifie qu'il s'identifie comme OpenMVS v2.4.0 et relève les
|
||
options effectivement exposées. Si `DensifyPointCloud` expose `--cuda-device`,
|
||
l'adaptateur demande explicitement le périphérique CPU ; sinon il n'ajoute aucune
|
||
option CUDA. Les options requises, dont `--max-threads`, doivent être exposées ;
|
||
celle-ci reçoit le nombre de threads d'exécution. Ce nombre est opérationnel et
|
||
exclu de l'identité scientifique.
|
||
|
||
Les contrats B1–B6 du jalon sont les suivants :
|
||
|
||
- **B1 — result failure atomicity.** Un échec ne retourne aucun
|
||
résultat MVS-M1 partiel.
|
||
- **B2 — source-image status classification.** Les erreurs source,
|
||
snapshot, I/O, backend, output et OOM restent distinctes.
|
||
- **B3 — source byte identity binding.** Chaque source acceptée est
|
||
un fichier régulier dont la taille du descripteur est contrôlée avant le hash ;
|
||
son SHA-256 complet est calculé avec une mémoire de streaming fixe, jusqu'à
|
||
1 GiB au maximum par fichier source, puis la stabilité du fichier est vérifiée
|
||
après lecture. Il n'existe volontairement aucun budget agrégé de 1 GiB pour le
|
||
jeu de sources : la vérification totale croît avec les octets d'entrée acceptés
|
||
et son admission/comptage global relève d'un futur Task/Governor.
|
||
- **B4 — deterministic COLMAP numeric export.** Les images, observations et
|
||
tracks sont ceux décrits ci-dessus ; aucune observation distordue n'est exportée
|
||
à la place de sa coordonnée transformée, et l'export des tracks ne réalise pas
|
||
de rescan quadratique landmark-observation. Une coordonnée source undistordue
|
||
non finie est `INVALID_SOURCE_IMAGE`, tandis qu'une pose du snapshot invalide
|
||
reste `INVALID_SNAPSHOT`.
|
||
- **B5 — write/close FD cleanup.** Les descripteurs possédés sont nettoyés
|
||
explicitement lors de l'écriture et de la fermeture,
|
||
y compris sur erreur.
|
||
- **B6 — C ABI / `std::bad_alloc` containment.** L'API C ne laisse pas
|
||
traverser `std::bad_alloc`.
|
||
|
||
Indépendamment de la borne de ligne PLY, l'inspection de l'en-tête d'image
|
||
encodée avant décodage est bornée à 64 KiB. Les formats acceptés implémentés sont
|
||
PNG, JPEG et BMP ; les dimensions, le nombre de pixels et l'estimation de working
|
||
set sont validés avant décodage (16 384 pixels par dimension, 40 Mpx et 240 MB).
|
||
Les intermédiaires d'undistortion déterministe
|
||
et les intermédiaires COLMAP/OpenMVS sont privés à l'espace de travail neuf créé
|
||
par invocation sous le staging appelant ; aucune invocation ne réemploie des
|
||
artefacts antérieurs.
|
||
|
||
Les deux exécutables backend sont hashés sous un budget borné partagé, distinct
|
||
du plafond par fichier des sources. Les processus possédés et leurs groupes sont
|
||
nettoyés ; stdout et stderr sont intégralement drainés pour chaque backend, avec
|
||
au plus 1 MiB retenu par log. L'excédent est consommé puis écarté, sans empêcher
|
||
le backend de poursuivre et de réussir.
|
||
|
||
Restent différés : publication dense dans la Project DB, Task Runtime,
|
||
Queue/Governor, `ResourceEstimate`, annulation, publication dense durable,
|
||
mesh, texturing, viewer, scratch/SSD et infrastructure backend généralisée.
|
||
Ce jalon ne marque ni MVS complet ni PASS / FROZEN.
|
||
|
||
---
|
||
|
||
### I. Reconstruction Layers
|
||
|
||
| Aspect | Description |
|
||
|--------|-------------|
|
||
| **Conservation de la provenance** | Chaque point 3D, chaque caméra, chaque track conserve la trace de son origine : quel scan set, quelle vague, quelle session. |
|
||
| **Consolidation distincte** | La fusion de layers (consolidation) est un processus séparé de l'ajout de données. L'utilisateur décide quand consolider. La consolidation ne détruit pas les layers d'origine. |
|
||
|
||
**Statut :** PLANNED — aucune implémentation existante.
|
||
|
||
---
|
||
|
||
### J. Sources géométriques externes
|
||
|
||
| Aspect | Description |
|
||
|--------|-------------|
|
||
| **PHOTO** | Images du scan set (source principale). |
|
||
| **MEASUREMENT** | Mesures directes : distances, orientations, coordonnées GPS, nuages de points LiDAR. Intègrent le graphe de contraintes comme edges géométriques supplémentaires. |
|
||
| **DOCUMENT** | Plans, relevés, fiches techniques. Métadonnées contextuelles qui enrichissent le projet sans contribuer directement au calcul géométrique. |
|
||
|
||
**Statut :** PLANNED — aucune implémentation existante.
|
||
|
||
---
|
||
|
||
### K. Viewer intégré
|
||
|
||
| Aspect | Description |
|
||
|--------|-------------|
|
||
| **Consommateur passif** | Le viewer ne calcule jamais. Il lit les snapshots validés publiés par le pipeline et les affiche. |
|
||
| **Isolation fonctionnelle** | Le viewer s'exécute dans un thread dédié ou un processus séparé. Il ne partage aucun buffer mutable avec les workers de calcul. |
|
||
| **Reactive** | L'utilisateur voit la reconstruction apparaître progressivement pendant les calculs, sans attendre la fin de l'étape courante. |
|
||
|
||
**Statut :** PLANNED — le viewer Vulkan séparé n'est pas encore commencé.
|
||
|
||
---
|
||
|
||
## Invariants
|
||
|
||
Ces invariants s'appliquent à toutes les étapes du pipeline :
|
||
|
||
1. **Chaque étape est indépendante et reprenable.**
|
||
L'exécution peut être interrompue à n'importe quelle frontière de lot
|
||
et reprise sans perte de données.
|
||
|
||
2. **Résultats atomiques et validés uniquement.**
|
||
Un résultat n'est publié (rendu visible aux étapes suivantes et au
|
||
viewer) que lorsqu'il est entièrement calculé, vérifié et persisté.
|
||
|
||
3. **Pas de destruction silencieuse des données sources.**
|
||
Les images originales, les features extraites, les tracks et les
|
||
points 3D existants ne jamais supprimés implicitement. Toute
|
||
suppression est une action explicite et traçable.
|
||
|
||
4. **Le scheduler ne décide jamais des ressources.**
|
||
Seul le Resource Governor arbitre les budgets, les lots et les
|
||
réservations.
|
||
|
||
5. **Les réservations sont obligatoires.**
|
||
Aucune tâche ne s'exécute sans réservation active préalablement
|
||
accordée par le governor.
|
||
|
||
6. **ncurses appartient exclusivement au thread principal.**
|
||
Aucun worker ne touche à l'interface TUI.
|
||
|
||
---
|
||
|
||
## Diagramme conceptuel
|
||
|
||
```
|
||
Scan Sets (A)
|
||
│
|
||
▼
|
||
Image Catalog (B) ──► Feature Store (C)
|
||
│
|
||
▼
|
||
Visual Index (D)
|
||
│
|
||
▼
|
||
Candidate Pair Generator (E)
|
||
│
|
||
▼
|
||
Matching / Geometric Verification (F)
|
||
│
|
||
▼
|
||
Tracks (G)
|
||
│
|
||
▼
|
||
Reconstruction Incrémentale (H)
|
||
│ │
|
||
▼ ▼
|
||
Reconstruction Sources
|
||
Layers (I) Externes (J)
|
||
│ │
|
||
└────┬─────┘
|
||
▼
|
||
Viewer Intégré (K)
|
||
```
|
||
|
||
---
|
||
|
||
## Statut du pipeline
|
||
|
||
Import, Image Catalog, Feature Extraction, Feature Store, Visual Index,
|
||
Candidate Pair, Matching v1, Geometric Verification, Track Model/Builder v1
|
||
and Sparse SfM Gate C geometry are **IMPLEMENTED**. The synchronous in-memory
|
||
incremental Sparse SfM Gate D core is **IMPLEMENTED / PASS**, and final
|
||
per-component Gate E BA is **PASS / FROZEN**. Gate F orchestration and Gate G
|
||
Governor integration are **PASS / FROZEN**. Phase H v1 is **PASS / FROZEN**.
|
||
MVS-M1 is **IMPLEMENTED / VALIDATION PENDING**: `L3DMDID2` v2 (220-byte) dense
|
||
identity binds the base reconstruction, source-image-set,
|
||
historical `calibration_scope_identity`, exact `L3DMCAL1` v1 numeric calibration
|
||
binding, backend and parameters, while source bytes remain separately bound;
|
||
deterministic OpenCV-undistorted COLMAP images, transformed observations and real
|
||
tracks exported from an index without a quadratic landmark-observation rescan;
|
||
and the external OpenMVS v2.4.0
|
||
`InterfaceCOLMAP`/`DensifyPointCloud` boundary. Every invocation has a fresh
|
||
private workspace beneath caller staging and reuses no prior scene, depth, cache
|
||
or output. Its numeric calibration binding sorts image IDs, uses explicit
|
||
fixed-width little-endian fields, rejects NaN/Inf and canonicalizes `-0`; PLY
|
||
headers are capped at 1 MiB of raw bytes (so CRLF costs two), accept LF/CRLF,
|
||
reject malformed bare CR, and cap each line at 64 KiB.
|
||
Non-finite undistorted source coordinates are `INVALID_SOURCE_IMAGE`; invalid
|
||
snapshot poses remain `INVALID_SNAPSHOT`. It validates OpenMVS's default binary
|
||
little-endian PLY, including bounded `view_indices`/`view_weights` lists with
|
||
locale-independent numeric validation, requires fusion mode 0 for the fused PLY,
|
||
and has conditional CPU-only capability plus supported `--max-threads`. It does
|
||
not include durable dense publication, runtime/governor integration, mesh,
|
||
texturing or viewer; those remain **PLANNED**.
|
||
|
||
Ce document décrit la vision architecturale cible du pipeline de
|
||
reconstruction. Les modules listés ici ne sont pas tous implémentés.
|
||
L'implémentation suit la feuille de route canonique de `docs/roadmap/roadmap.md`
|
||
et progresse par phases respectant les invariants d'indépendance et de reprise.
|