6.8 KiB
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 :
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.