146 lines
7.7 KiB
Markdown
146 lines
7.7 KiB
Markdown
# Calibration Solver Preflight v1
|
|
|
|
**PASS — sélection d'un futur générateur externe d'évidence ; aucune
|
|
implémentation n'est introduite ici.** Ce document n'autorise aucune
|
|
modification de `CALIBRATION_SCIENCE_V1`, de `CALIBRATION_TOOLING_V1`, de
|
|
`L3DCALB1`, du Project DB ou de Sparse SfM. S21 historique reste exclu.
|
|
|
|
## Décision
|
|
|
|
La plus petite voie conforme est un exécutable C++ externe, versionné et
|
|
haché, construit contre **OpenCV 5.0.x** avec `core`, `imgproc`, `imgcodecs`,
|
|
`objdetect` et `calib`. Il n'est pas lié par Lardon3D, n'écrit pas le Project
|
|
DB et produit seulement un bundle d'évidence borné. Un adaptateur ultérieur
|
|
traduit ce bundle vers `calibration_tooling.h`; Lardon3D reste seul producteur
|
|
`L3DCALB1` et seul appelant de l'importeur.
|
|
|
|
Les alternatives évaluées sont : OpenCV ChArUco externe, retenu ; outils tiers
|
|
généralistes, non retenus faute de contrat public stable pour résidus point par
|
|
point et flags exacts ; solveur custom, hors scope car OpenCV fournit déjà la
|
|
détection, la calibration pinhole et les résidus nécessaires.
|
|
|
|
## API OpenCV et modèle
|
|
|
|
La cible est créée par `cv::aruco::CharucoBoard(cv::Size(9, 7), 0.030f,
|
|
0.021f, cv::aruco::getPredefinedDictionary(cv::aruco::DICT_5X5_100))`, puis
|
|
rendue par `generateImage`. La version OpenCV et `legacyPattern=false` sont
|
|
archivés. La détection emploie `cv::aruco::CharucoDetector::detectBoard` sans
|
|
matrice caméra au premier passage et archive coins, IDs, marqueurs et paramètres
|
|
de détection. `CharucoBoard::matchImagePoints` associe ID, pixel et point objet
|
|
en mètres. Une vue est explicitement rejetée, avec motif, si elle ne satisfait
|
|
pas Science v1.
|
|
|
|
Dans le chemin OpenCV 5.0.x qualifié, la détection ChArUco fournit les
|
|
observations image en `Point2f` et la planche fournit les observations objet
|
|
en `Point3f`. `calibrateCamera` reçoit donc ces observations
|
|
`binary32` : c'est l'exception explicite de transport de
|
|
`CALIBRATION_SCIENCE_V1`, et non une troncature silencieuse. Le chemin de
|
|
conversion, l'absence de quantification ultérieure et les bornes maximales
|
|
mesurées sont archivés pour chaque session : chaque coordonnée image est
|
|
strictement inférieure à `0.01 px`; chaque coordonnée objet est rapportée
|
|
dans l'unité physique de la cible, avec la représentation source `Point3f`
|
|
de la planche qui justifie cette exception.
|
|
|
|
La voie qualifiée convertit les données de calibration dans son calcul interne
|
|
`CV_64F` là où OpenCV 5.0.x l'établit. La `cameraMatrix` et les
|
|
`distCoeffs` faisant autorité sont `CV_64F`; les huit paramètres publiés,
|
|
les poses archivées, les projections/résidus indépendants et toutes les
|
|
métriques de validation restent `binary64`.
|
|
|
|
Le solveur appelle la surcharge étendue `cv::calibrateCamera` :
|
|
|
|
```text
|
|
flags = cv::CALIB_FIX_K3
|
|
criteria = COUNT | EPS, 500, DBL_EPSILON
|
|
cameraMatrix = Matx33d::eye()
|
|
distCoeffs = Mat::zeros(5, 1, CV_64F)
|
|
```
|
|
|
|
L'ordre OpenCV est `[k1,k2,p1,p2,k3]`; `CALIB_FIX_K3` fixe le dernier à zéro,
|
|
donc les quatre autres se mappent directement à Sparse SfM v1. `fx`, `fy`,
|
|
`cx`, `cy`, `k1`, `k2`, `p1` et `p2` restent libres. Sont interdits :
|
|
`CALIB_FIX_ASPECT_RATIO`, `CALIB_FIX_PRINCIPAL_POINT`,
|
|
`CALIB_FIX_FOCAL_LENGTH`, `CALIB_FIX_K1`, `CALIB_FIX_K2`,
|
|
`CALIB_ZERO_TANGENT_DIST`, `CALIB_FIX_TANGENT_DIST`,
|
|
`CALIB_RATIONAL_MODEL`, `CALIB_THIN_PRISM_MODEL`, `CALIB_TILTED_MODEL`, les
|
|
flags de fixage associés, fisheye, QR/LU, EXIF comme intrinsics et calibration
|
|
par image.
|
|
|
|
La surcharge étendue retourne RMS global et par vue. L'outil doit recalculer
|
|
avec `cv::projectPoints` chaque résidu par coin, maximum, fraction `>1 px` et
|
|
RMS avec les mêmes poses ; le succès du solveur seul n'est jamais suffisant.
|
|
Ces API emploient `fx,fy,cx,cy` en pixels et la même distorsion directe que le
|
|
modèle gelé : aucune conversion de modèle n'est permise.
|
|
|
|
## Entrée, sortie et déterminisme
|
|
|
|
L'entrée externe est un répertoire immuable d'originaux hachés, manifeste
|
|
d'état optique, cible/mesures et chaîne de décodage-orientation. Les vues sont
|
|
triées par SHA-256 source avant détection. Détection et solve sont deux étapes
|
|
matérialisées (`detection.json` et `solve.json`) d'un seul exécutable : IDs,
|
|
pixels subpixel, décisions et rejets sont ainsi vérifiables avant les trois
|
|
solves. Les fichiers ont ordre canonique, nombres `binary64` hexadécimaux
|
|
pour les quantités faisant autorité, représentation et chemin de conversion
|
|
`binary32` explicitement archivés pour les observations d'API, tableaux
|
|
ordonnés et limites déclarées.
|
|
|
|
La sortie archive nom/version/SHA de l'exécutable, OS/architecture, build
|
|
OpenCV et bibliothèques, configuration hachée, identité de session, vues et
|
|
motifs, points objet/image, résidus, poses diagnostic, huit paramètres,
|
|
supports, hold-out, trois répétitions et calculs des flags `0x01..0x08`. Les
|
|
images de campagne, postérieures à la calibration, sont ajoutées seulement par
|
|
l'adaptateur comme entrées `image_id`/SHA/dimensions dans l'ordre
|
|
`selected_execution` : elles ne sont jamais des entrées de solveur.
|
|
|
|
La preuve initiale est CPU1 : `cv::setNumThreads(1)`, `cv::setRNGSeed` fixé,
|
|
aucun travail parallèle, `OMP_NUM_THREADS=1`, `OPENBLAS_NUM_THREADS=1` et
|
|
`MKL_NUM_THREADS=1` lorsqu'applicables. `cv::getBuildInformation`, backend de
|
|
threads et environnement effectif sont archivés. Les trois exécutions sur même
|
|
hôte/architecture/octets doivent donner les mêmes huit `binary64`, décisions
|
|
et rapports canoniques : tout écart bloque Science v1.
|
|
|
|
## Équivalence de coordonnées et versionnement
|
|
|
|
La géométrie est : origine haut-gauche, `x` droite, `y` bas, pixels continus à
|
|
centres demi-entiers. Chaque image archive SHA, décodeur/version, EXIF,
|
|
dimensions avant/après et les équations `0°:(x,y)`, `90°:(H-y,x)`,
|
|
`180°:(W-x,H-y)`, `270°:(y,W-x)`. Vingt coins par vue repassent dans la
|
|
chaîne Feature Store ; chaque erreur est `<=0.01 px` et les dimensions orientées
|
|
doivent être identiques.
|
|
|
|
L'hôte de préflight fournit `opencv 5.0.0-9`. La production future épingle un
|
|
exécutable contre OpenCV 5.0.x avec SHA obligatoire ; le package Arch est bon
|
|
pour développement, pas l'unique identité de production. Sont archivés en
|
|
plus : compilateur, flags, build info, bibliothèques/SHA, OS, architecture et
|
|
politique CPU. Les quatre SHA `L3DCALB1` restent autoritaires.
|
|
|
|
## Prochaine tranche et première preuve physique
|
|
|
|
La prochaine tranche implémente uniquement l'exécutable externe et ses tests :
|
|
caméra pinhole/distorsion connues, projections ChArUco, bruit/outliers,
|
|
récupération, résidus, répétitions, hold-out, entrées invalides et bundle
|
|
byte-identique. Puis seulement : fabriquer/mesurer la cible, figer l'état
|
|
optique, acquérir au moins 40 vues, hacher, résoudre trois fois, vérifier
|
|
Science v1, passer le bundle à Calibration Tooling dans un projet dédié et
|
|
vérifier `CALIBRATION → READY`. La preuve s'arrête avant Sparse SfM ; S21 ne
|
|
participe jamais.
|
|
|
|
## Current lifecycle update
|
|
|
|
The preflight decision above has now been implemented.
|
|
|
|
```text
|
|
CALIBRATION_EVIDENCE_SOLVER_V1=IMPLEMENTED/VALIDATED
|
|
```
|
|
|
|
`tools/calibration_evidence_solver/` contains the external OpenCV 5.x solver selected by this
|
|
preflight. Its deterministic synthetic CPU1 self-test passes. It remains external to Lardon3D
|
|
runtime linkage and Project DB mutation.
|
|
|
|
The current missing implementation boundary is no longer the solver. It is the higher-level
|
|
calibration workflow coordinator that binds an immutable physical session plus the complete solver
|
|
bundle to the exact selected execution, constructs `Lardon3DCalibrationToolingEvidence`, invokes the
|
|
frozen Tooling/Bootstrap path and reaches `READY` without manufacturing evidence.
|
|
|
|
The original preflight text is retained as decision history; this section owns its later lifecycle
|
|
status.
|