# Fact Cards — C4: Pose estimation (PnP + RANSAC + LM)

> Mode A Phase 2 — engine Step 3 (Fact Extraction & Evidence Cards). Component **C4** = "Pose estimation (PnP + RANSAC + LM)" per the user-locked definition correction recorded in [`../06_component_fit_matrix/C4_pose_estimation.md`](../06_component_fit_matrix/C4_pose_estimation.md). C4 consumes C3's 2D-2D correspondences + C6's per-tile geo metadata (after a 2D→3D lift; see D-C4-1 in the gates file) and produces the 6-DoF camera pose w.r.t. tile + per-correspondence inlier mask + reprojection error + 6×6 covariance + inlier ratio + RANSAC iter count + source label `satellite_anchor` for the C5 fused estimate.
>
> Index: [`00_summary.md`](00_summary.md). Sibling fact-card files: [SQ1](SQ1_existing_systems.md), [SQ2](SQ2_canonical_pipeline.md), [SQ6](SQ6_fc_external_positioning.md), [C1](C1_vio.md), [C2](C2_vpr.md), [C3](C3_matchers.md). Component fit matrix row: [`../06_component_fit_matrix/C4_pose_estimation.md`](../06_component_fit_matrix/C4_pose_estimation.md). Cross-component gates: [`../06_component_fit_matrix/99_cross_component_gates.md`](../06_component_fit_matrix/99_cross_component_gates.md).

---

### Fact #52 — OpenCV `cv::solvePnPRansac` per-mode API capability verification (canonical `opencv/opencv` calib3d module — RANSAC PnP with 9 minimal-solver `SolvePnPMethod` enum values + classical RANSAC signature + USAC variant + paired `cv::solvePnPRefineLM` LM refinement + paired `cv::solvePnPGeneric` reprojection-error report; **MANDATORY SIMPLE-BASELINE** role per engine Component Option Breadth rule for the C4 row, structurally analogous to NetVLAD's role in the C2 row + SuperGlue+SuperPoint's role in the C3 row; on Jetson Orin Nano Super) — DOCUMENTARY PASS WITH CLEAN-APACHE-2.0-LICENSE-THROUGHOUT + 87385-STARS-+-DAILY-MAINTENANCE (last-pushed-2026-05-08) + 9-SOLVER-ENUM-VALUES-INCLUDING-2-DOCUMENTED-BROKEN (SOLVEPNP_DLS + SOLVEPNP_UPNP fall back to EPNP per OpenCV 4.x explicit docstring) + 3D-2D-INPUT-CONTRACT-NOT-2D-2D (project must perform 2D→3D lift via D-C4-1 before calling) + NO-DIRECT-6×6-COVARIANCE-OUTPUT (D-C4-2 NEW covariance-recovery-strategy gate raised) + LM-REFINEMENT-ROTATION-UPDATE-NOT-ON-SO(3)-CAVEAT (documented in `cv::solvePnPRefineLM` reference; minor for project's pinned aerial pose-from-correspondences); opens C4 row at **1 of N candidates** (mandatory simple-baseline role)
- **Statement**: OpenCV's `cv::solvePnPRansac` (`opencv/opencv` canonical implementation, calib3d module, Apache-2.0 license throughout per `license.spdx_id: "Apache-2.0"` confirmed via Source #82 GitHub API metadata + Source #83 calib3d module documentation) is the **MANDATORY SIMPLE-BASELINE reference** for the C4 row per the engine Component Option Breadth rule — **the long-established RANSAC-PnP reference that defines the simple-baseline floor against which modern competitive leads (OpenGV, GTSAM-factor-graph PnP, Theia, Ceres-only manual implementation) must measurably exceed** at the project's pinned mode (per-frame pose-from-correspondences contract on Jetson Orin Nano Super; inputs = up to 1024 3D-2D correspondences derived from C3's 2D-2D correspondences + C6's per-tile geo metadata via D-C4-1's 2D→3D lift; outputs = 6-DoF camera pose (R, t) + per-correspondence inlier mask + reprojection error + RANSAC iteration count). Per the per-Mode API Capability Verification rule, the project's pinned mode is the **(`cv::solvePnPRansac` Python binding `cv2.solvePnPRansac` with `objectPoints` Nx3 float32 + `imagePoints` Nx2 float32 + `cameraMatrix` 3x3 + `distCoeffs` 5-vector + `iterationsCount=100` + `reprojectionError=8.0` pixels + `confidence=0.99` + `flags=SOLVEPNP_EPNP` for default minimal-sample-set OR `flags=SOLVEPNP_IPPE` for the project's planar-scene 4-DoF flat-earth lift recommended by D-C4-1 OR `flags=SOLVEPNP_SQPNP` for modern globally-optimal alternate) → `(retval, rvec, tvec, inliers)` + paired `cv::solvePnPRefineLM(objectPoints, imagePoints, cameraMatrix, distCoeffs, rvec, tvec, criteria=cv.TermCriteria(cv.TermCriteria_EPS+cv.TermCriteria_COUNT, 20, FLT_EPSILON))` LM refinement on the inlier set + paired `cv::solvePnPGeneric` for reprojection-error reporting**. **Mode-enumeration query (1/3) — context7 NOT INDEXED + WebFetch fallback PASS**: `context7 resolve-library-id` returned an MCP validation error (parameter schema mismatch — context7 server expects different argument shape than provided); per Per-Mode API Capability Verification rule item 2, fall-back to official-docs WebFetch on canonical OpenCV calib3d module documentation (Source #83) + GitHub API license metadata (Source #82) was used. **Nine `SolvePnPMethod` enum values documented** (Source #83 calib3d.html SolvePnPMethod enum block): `SOLVEPNP_ITERATIVE=0` (default; iterative LM-based on top of EPNP minimal-solver result), `SOLVEPNP_EPNP=1` (Efficient Perspective-n-Point [Lepetit et al. IJCV 2009]; canonical default for ≥4 non-planar correspondences), `SOLVEPNP_P3P=2` (Revisiting the P3P Problem [Ding et al. 2023]; minimal-solver for exactly-3 correspondences with up to 4 solutions), `SOLVEPNP_DLS=3` (**BROKEN per Source #83 explicit docstring "Broken implementation. Using this flag will fallback to EPnP"** — Direct Least-Squares method [Hesch & Roumeliotis 2011] originally; eliminated as a valid project option), `SOLVEPNP_UPNP=4` (**BROKEN per Source #83 explicit docstring "Broken implementation. Using this flag will fallback to EPnP"** — Exhaustive Linearization for Robust Camera Pose and Focal Length Estimation [Penate-Sanchez et al. 2013] originally; eliminated as a valid project option), `SOLVEPNP_AP3P=5` (Algebraic P3P [Ke & Roumeliotis CVPR 2017]; modern P3P alternate for exactly-3 correspondences), `SOLVEPNP_IPPE=6` (Infinitesimal Plane-Based Pose Estimation [Collins & Bartoli ECCV 2014]; **planar-only — object points must be coplanar — directly relevant to project's D-C4-1 = 4-DoF flat-earth lift recommendation**), `SOLVEPNP_IPPE_SQUARE=7` (special-case IPPE for marker pose with 4 fixed-pattern points; not project-applicable), `SOLVEPNP_SQPNP=8` (SQPnP: A Consistently Fast and Globally Optimal Solution [Terzakis & Lourakis ECCV 2020]; **modern globally-optimal alternate without planarity restriction — second-recommended fallback if D-C4-1 chooses 6-DoF DSM lift instead of 4-DoF flat-earth**). **Two `cv::solvePnPRansac` function signatures** (Source #83 lines 3211 + 3261): (a) **classical**: `bool solvePnPRansac(InputArray objectPoints, InputArray imagePoints, InputArray cameraMatrix, InputArray distCoeffs, OutputArray rvec, OutputArray tvec, bool useExtrinsicGuess=false, int iterationsCount=100, float reprojectionError=8.0, double confidence=0.99, OutputArray inliers=noArray(), int flags=SOLVEPNP_ITERATIVE)` — Python `cv.solvePnPRansac(objectPoints, imagePoints, cameraMatrix, distCoeffs[, rvec[, tvec[, useExtrinsicGuess[, iterationsCount[, reprojectionError[, confidence[, inliers[, flags]]]]]]]]) -> retval, rvec, tvec, inliers`; (b) **USAC variant**: `bool solvePnPRansac(InputArray objectPoints, InputArray imagePoints, InputOutputArray cameraMatrix, InputArray distCoeffs, OutputArray rvec, OutputArray tvec, OutputArray inliers, const UsacParams& params=UsacParams())` — Python `cv.solvePnPRansac(objectPoints, imagePoints, cameraMatrix, distCoeffs[, rvec[, tvec[, inliers[, params]]]]) -> retval, cameraMatrix, rvec, tvec, inliers`; **note `cameraMatrix` is `InputOutputArray` in the USAC variant**, allowing focal-length refinement during the RANSAC loop. **USAC RANSAC-method enumeration** (Source #83 anonymous-enum block): canonical RANSAC, LMEDS, RHO, **USAC_DEFAULT, USAC_PARALLEL, USAC_FM_8PTS, USAC_FAST, USAC_ACCURATE, USAC_PROSAC, USAC_MAGSAC** — modern USAC variants (introduced 2020-2023) provide higher inlier-recovery rate than vanilla RANSAC at the same iteration budget; **USAC_MAGSAC is the canonical sigma-consensus modern alternative to vanilla RANSAC** with no fixed inlier threshold (per Barath et al. CVPR 2019 + Barath et al. ICCV 2019 MAGSAC++ extension). **Paired `cv::solvePnPRefineLM`** (Source #83 line 3268): canonical default `TermCriteria(EPS+COUNT, 20, FLT_EPSILON)` — minimizes projection error via Levenberg-Marquardt iterative minimization [Madsen et al. 2004 + Eade 2013]; **CAVEAT documented in Source #83 PnP-tutorial page**: "the current implementation computes the rotation update as a perturbation and not on SO(3)" — minor structural caveat for high-accuracy aerial pose-from-correspondences but not blocking; alternate `cv::solvePnPRefineVVS` uses Gauss-Newton with rotation update via exponential map on SO(3) (paper Marchand et al. 2016) — preferred if SO(3)-correctness is project-critical. **Paired `cv::solvePnPGeneric`** (Source #83 line 3070): returns multiple candidate solutions sorted by reprojection error + an `OutputArray reprojectionError` per-solution — useful if the project's downstream C5 fusion benefits from candidate-pose-disambiguation evidence. **Default minimal-sample-set method** (Source #83 line 3256): "The default method used to estimate the camera pose for the Minimal Sample Sets step is `SOLVEPNP_EPNP`. Exceptions are: if you choose `SOLVEPNP_P3P` or `SOLVEPNP_AP3P`, these methods will be used; if the number of input points is equal to 4, `SOLVEPNP_P3P` is used." — establishes the documentary default for the C4 RANSAC inner-loop minimal-solver. **Pinned-mode runnable example query (2/3) — WebFetch PASS**: Source #83 PnP tutorial page (`/4.x/d5/d1f/calib3d_solvePnP.html`) provides the canonical `cv::solvePnPRansac` runnable Python example: `retval, rvec, tvec, inliers = cv.solvePnPRansac(objectPoints, imagePoints, cameraMatrix, distCoeffs, iterationsCount=100, reprojectionError=8.0, confidence=0.99, flags=cv.SOLVEPNP_EPNP)` followed by `rvec, tvec = cv.solvePnPRefineLM(objectPoints[inliers.flatten()], imagePoints[inliers.flatten()], cameraMatrix, distCoeffs, rvec, tvec, criteria=(cv.TERM_CRITERIA_EPS+cv.TERM_CRITERIA_COUNT, 20, FLT_EPSILON))`; OpenCV ships canonical Python tutorials at `samples/python/tutorial_code/calib3d/` reproducing the canonical 3D-2D correspondence pose estimation reference. **Disqualifier-probe query (3/3) — FOUR FINDINGS (1 negative-but-mitigable structural + 3 caveats)**: (i) **CRITICAL contract finding — solvePnPRansac requires 3D-2D correspondences, NOT 2D-2D from C3** (Source #83 explicit signature: `objectPoints` is `Nx3 1-channel or 1xN/Nx1 3-channel`, `imagePoints` is `Nx2 1-channel or 1xN/Nx1 2-channel`); the project must perform a 2D→3D lift on C3's satellite-tile-side 2D pixels (using per-tile geo metadata from C6 + WGS84 corner-coordinates + ortho resolution + DSM-or-flat-earth assumption) BEFORE invoking solvePnPRansac — **this is exactly the architectural concern that D-C4-1 (2D-3D-lift architectural decision) carried forward from C2's Fact #20 closure addresses**; recommendation locked at **D-C4-1 = 4-DoF flat-earth + IMU+barometer altitude + VIO/IMU attitude → planar-scene homography → 4-DoF pose extraction** (project default per locked-in research-time defaults); ALOS-30m-DSM secondary mitigation; pairs with `SOLVEPNP_IPPE` minimal-solver for the planar-scene case OR `SOLVEPNP_SQPNP` for the 6-DoF DSM-lift case; (ii) **CRITICAL covariance finding — solvePnPRansac does NOT directly emit a 6×6 pose covariance** (Source #83 signature returns `retval, rvec, tvec, inliers` only; no covariance output array); for AC-NEW-4 covariance-honesty contract the project must either (a) **post-hoc Jacobian-based covariance recovery** from inlier residuals via `cv::projectPoints` Jacobian + Schur complement (~1 day engineering; pure OpenCV API; gives a 6×6 covariance approximation of equivalent quality to ROS `tf2`'s standard recipe), (b) **wrap solvePnPRansac result in a factor-graph optimizer** (e.g., GTSAM `BetweenFactor<Pose3>` with the solvePnPRansac result as the prior + per-inlier `GenericProjectionFactor<Pose3, Point3>` factors → `Marginals` posterior covariance; canonical Plan-phase candidate is option C in user's first-candidate gate); (c) reject identity-matrix-placeholder per AC-NEW-4 covariance-honesty rule. **NEW Plan-phase decision D-C4-2 covariance-recovery-strategy raised** — covers (a) Jacobian-based post-hoc recovery (lowest dependency; OpenCV-native), (b) factor-graph posterior via GTSAM wrap (canonical Plan-phase option C path), (c) `cv::SolvePnPRansac` inlier residual statistics + project-defined heuristic covariance scaling (lowest engineering, lowest correctness — likely AC-NEW-4 reject), (d) migrate to OpenGV's covariance-aware `absolute_pose::optimize_nonlinear` with explicit Jacobian propagation (would couple D-C4-2 with D-C4-1 = OpenGV-as-primary instead of OpenCV-as-primary). Recommended: option (a) Jacobian-based post-hoc recovery for the OpenCV-as-primary mandatory-simple-baseline path; option (b) factor-graph posterior for the GTSAM-as-primary modern-competitive-lead path; (iii) **Two minimal-solver enum values BROKEN per OpenCV 4.x explicit docstring** (Source #83 SOLVEPNP_DLS + SOLVEPNP_UPNP enum entries: "Broken implementation. Using this flag will fallback to EPnP"); the user-listed first-candidate Choose-block "SOLVEPNP_EPNP / SOLVEPNP_DLS / SOLVEPNP_UPNP / SOLVEPNP_AP3P / SOLVEPNP_IPPE / SOLVEPNP_SQPNP minimal-solver options" is reduced from 6 to **4 valid options** (EPNP / AP3P / IPPE / SQPNP) plus 2 special-case (P3P for exactly-3 correspondences; IPPE_SQUARE for 4-fixed-pattern markers); does not change recommendation but documents that the user's prior enumeration over-counts by 2; (iv) **`cv::solvePnPRefineLM` rotation update is NOT on SO(3)** per Source #83 PnP-tutorial page explicit caveat "the current implementation computes the rotation update as a perturbation and not on SO(3)" — minor structural caveat; for high-accuracy aerial pose-from-correspondences with large rotation magnitudes the alternate `cv::solvePnPRefineVVS` (Gauss-Newton on SO(3) via exponential map) is the documented preferred refiner. **Pinned-mode sentence**: "We will catalog **OpenCV `cv::solvePnPRansac` + paired `cv::solvePnPRefineLM`** with **`flags=SOLVEPNP_EPNP` default minimal-sample-set + `iterationsCount=100` + `reprojectionError=8.0` pixels + `confidence=0.99` canonical defaults + Apache-2.0 license throughout** as the **MANDATORY SIMPLE-BASELINE reference** for the C4 row per engine Component Option Breadth rule (structurally analogous to NetVLAD's role in C2 row + SuperGlue+SuperPoint's role in C3 row). Inputs `{up to 1024 3D-2D correspondences derived from C3's 2D-2D correspondences via D-C4-1's 2D→3D lift (project default = 4-DoF flat-earth + IMU+barometer altitude + VIO/IMU attitude prior → planar-scene homography → 4-DoF pose extraction; ALOS-30m-DSM secondary mitigation) + per-tile geo metadata from C6 + camera intrinsic matrix from project calibration + distortion coefficients from project calibration}`; expected outputs `{6-DoF camera pose (R, t) + per-correspondence inlier mask + reprojection error from solvePnPGeneric + RANSAC iteration count + 6×6 covariance via D-C4-2's covariance-recovery-strategy decision (post-hoc Jacobian-based via cv::projectPoints Jacobian + Schur complement = recommended for OpenCV-as-primary path) + source label `satellite_anchor` for C5 fused estimate}`; runtime `Jetson Orin Nano Super (8 GB shared, JetPack 6, ROS 2 Humble)` — **deployment-ready under every D-C1-1 license-posture choice** (clean Apache-2.0 throughout). For project's actual deployment, OpenCV solvePnPRansac is positioned as the **mandatory-simple-baseline reference floor** that the C4 row's modern competitive leads (OpenGV, GTSAM-factor-graph PnP) must measurably exceed on documented-evidence axes (per-correspondence covariance honesty, multi-camera generalization, factor-graph posterior recovery, RANSAC-variant breadth)." **MANDATORY-SIMPLE-BASELINE role per engine Component Option Breadth rule** — `cv::solvePnPRansac` is the **CANONICAL RANSAC-PnP mandatory-simple-baseline reference** for the C4 row; no further mandatory-simple-baseline candidates required after this closure. Subsequent C4 candidates (OpenGV / GTSAM-factor-graph PnP / Theia / Ceres-only) will be cataloged in subsequent sessions as modern-competitive-lead candidates.
- **Source**: Source #82 (canonical `opencv/opencv` GitHub repo + LICENSE metadata via GitHub API — Apache-2.0 (`license.spdx_id: "Apache-2.0"`); 87385 stars + 56554 forks + 2606 subscribers + last pushed 2026-05-08T07:00:03Z = TODAY at access time + open issues 2732 + default branch `4.x`; 555 GB total tree size; topics include `c-plus-plus, computer-vision, deep-learning, image-processing, opencv`; canonical website https://opencv.org), Source #83 (canonical OpenCV 4.x calib3d module documentation https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html + canonical PnP tutorial page https://docs.opencv.org/4.x/d5/d1f/calib3d_solvePnP.html — `cv::solvePnPRansac` two function signatures [classical with `iterationsCount=100, reprojectionError=8.0, confidence=0.99, flags=SOLVEPNP_ITERATIVE` defaults + USAC variant with `UsacParams` and `cameraMatrix` as InputOutputArray] + Python bindings; `cv::SolvePnPMethod` enum with 9 values [SOLVEPNP_ITERATIVE, SOLVEPNP_EPNP, SOLVEPNP_P3P, SOLVEPNP_DLS-BROKEN, SOLVEPNP_UPNP-BROKEN, SOLVEPNP_AP3P, SOLVEPNP_IPPE, SOLVEPNP_IPPE_SQUARE, SOLVEPNP_SQPNP]; `cv::solvePnPRefineLM` with `TermCriteria(EPS+COUNT, 20, FLT_EPSILON)` default + caveat "rotation update as perturbation and not on SO(3)"; alternate `cv::solvePnPRefineVVS` with Gauss-Newton SO(3) update via exponential map; `cv::solvePnPGeneric` for multi-solution + per-solution reprojection-error reporting; USAC RANSAC-method enum [USAC_DEFAULT, USAC_PARALLEL, USAC_FM_8PTS, USAC_FAST, USAC_ACCURATE, USAC_PROSAC, USAC_MAGSAC]); cross-cite to Fact #20 + #21 closures from C2 row (canonical PnP+RANSAC+LM reference pipeline shape — feeds into AC-NEW-4 covariance-honesty contract via D-C4-2 NEW); cross-cite to all C3 row closures (the C3-output-to-C4-input contract is 2D-2D correspondences from C3 → 2D→3D lift via D-C4-1 → 3D-2D correspondences for solvePnPRansac)
- **Phase**: Phase 2
- **Target Audience**: System architects + C4 implementer + Step-7.5 reviewer + license-posture decision-maker (D-C1-1 — clean Apache-2.0 throughout) + Plan-phase architect (mandatory-simple-baseline role documentation for engine Component Option Breadth rule compliance + D-C4-1 2D-3D-lift architectural decision carry-forward + D-C4-2 NEW covariance-recovery-strategy gate)
- **Confidence**: ✅ for mode-enumeration (9 `SolvePnPMethod` enum values + 2 `solvePnPRansac` function signatures + 7 USAC RANSAC-method enum values + 2 LM/VVS refinement variants + 1 generic multi-solution variant — all documented in canonical Source #83 calib3d.html), runnable-example (canonical Python binding `cv2.solvePnPRansac` documented in Source #83 with explicit recommended defaults + canonical OpenCV samples Python tutorial reproduces the canonical 3D-2D correspondence pose estimation reference), license (**Apache-2.0** confirmed via Source #82 GitHub API `license.spdx_id: "Apache-2.0"` — clean BSD/permissive license track on extractor + matcher, eligible on every D-C1-1 license-posture choice with the simplest license-compliance story tied with cvg/LightGlue + DISK + XFeat); ✅ for canonical defaults (`iterationsCount=100, reprojectionError=8.0, confidence=0.99, flags=SOLVEPNP_ITERATIVE` per Source #83 line 3211); ✅ for **TWO MINIMAL-SOLVER ENUM VALUES BROKEN** finding (Source #83 explicit docstrings on SOLVEPNP_DLS + SOLVEPNP_UPNP enum entries); ✅ for **3D-2D INPUT CONTRACT, NOT 2D-2D** finding (Source #83 explicit `objectPoints` Nx3 + `imagePoints` Nx2 signature documentation); ✅ for **NO DIRECT 6×6 COVARIANCE OUTPUT** finding (Source #83 function signature returns `retval, rvec, tvec, inliers` only — no covariance output array); ✅ for **`solvePnPRefineLM` rotation update as perturbation, not on SO(3)** finding (Source #83 PnP-tutorial page explicit caveat); ✅ for **canonical Apache-2.0 license throughout** (Source #82 GitHub API license metadata + Source #83 documentation page footer); ⚠️ for **Jetson Orin Nano Super deployment latency / memory / accuracy** (no documentary measurement; extrapolation from x86_64 RTX-class GPU canonical OpenCV PnP+RANSAC throughput at 1024 correspondences with `iterationsCount=100, flags=SOLVEPNP_EPNP, confidence=0.99` ~2-5 ms per call CPU-only on Intel i7-class; Jetson Orin Nano Super extrapolation ~5-15 ms per call CPU-only; at K=10 image pairs/frame extrapolated 50-150 ms total = comfortable AC-4.1 satisfaction with substantial margin); ❌ for **canonical-checkpoint aerial-domain fitness** — N/A for OpenCV solvePnPRansac since it is a classical algorithm, not a learned method (no canonical-weights aerial-domain caveat applies); ❌ for **post-hoc 6×6 covariance recovery via Jacobian-based propagation** (no canonical OpenCV reference implementation; project must implement custom or wrap solvePnPRansac result in GTSAM `Marginals` posterior — D-C4-2 NEW Plan-phase decision required)
- **Related Dimension**: SQ3+SQ4 / C4 mandatory simple-baseline reference (engine Component Option Breadth rule role — structurally analogous to NetVLAD's role in C2 row + SuperGlue+SuperPoint's role in C3 row) — per-mode API capability verification gate
- **Fit Impact**: **DOCUMENTARY PASS for the per-mode API capability verification gate at the mandatory-simple-baseline role** — `cv::solvePnPRansac` has documented runnable per-mode examples with the project's pinned configuration (canonical OpenCV calib3d module + canonical Python binding + canonical default parameters), nine documented `SolvePnPMethod` enum values (4 valid for general project use + 2 special-case + 1 ITERATIVE default + 2 BROKEN-fallback-to-EPNP), two `solvePnPRansac` function signatures (classical + USAC variant), paired `cv::solvePnPRefineLM` LM refinement + alternate `cv::solvePnPRefineVVS` Gauss-Newton SO(3) refinement + paired `cv::solvePnPGeneric` reprojection-error reporting. **Two CONVERGING POSITIVE structural advantages**: (i) **CLEAN APACHE-2.0 LICENSE THROUGHOUT** — canonical `opencv/opencv` repo per Source #82 GitHub API metadata; eligible on every D-C1-1 license-posture path with the simplest license-compliance story tied with cvg/LightGlue + DISK + XFeat; (ii) **DOMINANT INDUSTRY-STANDARD REFERENCE** — 87385 stars + 56554 forks + 2606 subscribers + last pushed 2026-05-08 (TODAY) per Source #82; OpenCV solvePnPRansac is the **canonical reference RANSAC-PnP implementation** that every modern C4 alternative (OpenGV, GTSAM-PnP, Theia, Ceres-only) compares against in its own documentation. **Two NEGATIVE-BUT-MITIGABLE structural findings**: (iii) **3D-2D INPUT CONTRACT, NOT 2D-2D** — solvePnPRansac requires the project to perform a 2D→3D lift on C3's satellite-tile-side 2D pixels via D-C4-1's locked-in 4-DoF flat-earth recommendation (or ALOS-30m-DSM secondary mitigation); this is **inherent to all PnP-class algorithms**, not unique to OpenCV — applies identically to OpenGV / GTSAM-PnP / Theia / Ceres-only; (iv) **NO DIRECT 6×6 COVARIANCE OUTPUT** — solvePnPRansac returns `retval, rvec, tvec, inliers` only; AC-NEW-4 covariance-honesty contract requires project to choose D-C4-2 covariance-recovery-strategy: (a) post-hoc Jacobian-based via `cv::projectPoints` Jacobian + Schur complement (recommended for OpenCV-as-primary path; ~1 day engineering; pure OpenCV API), (b) wrap in GTSAM `Marginals` posterior (couples with C4 candidate option C = GTSAM-factor-graph PnP), (c) project-defined heuristic covariance scaling (likely AC-NEW-4 reject), (d) migrate to OpenGV's `absolute_pose::optimize_nonlinear` with explicit Jacobian propagation. **Two CAVEATS**: (v) **Two minimal-solver enum values BROKEN** (SOLVEPNP_DLS + SOLVEPNP_UPNP fall back to EPNP per Source #83 explicit docstring) — eliminates 2 of 6 user-listed solver options from the prior research-time enumeration; valid set for general project use is `EPNP / AP3P / IPPE / SQPNP` plus 2 special-case (`P3P` for exactly-3 correspondences; `IPPE_SQUARE` for 4-fixed-pattern markers) plus `ITERATIVE` default refinement; recommended pairing for D-C4-1 = 4-DoF flat-earth lift is **`SOLVEPNP_IPPE`** (planar-scene minimal-solver designed for coplanar object points) with **`SOLVEPNP_SQPNP`** as the modern globally-optimal fallback; (vi) **`cv::solvePnPRefineLM` rotation update is NOT on SO(3)** per Source #83 explicit caveat — minor structural caveat; alternate `cv::solvePnPRefineVVS` uses Gauss-Newton with rotation update via exponential map on SO(3) (preferred for high-accuracy aerial pose-from-correspondences). **NEW Plan-phase decisions raised by OpenCV solvePnPRansac closure**: **D-C4-2 NEW covariance-recovery-strategy** — Plan-phase decision between (a) post-hoc Jacobian-based via `cv::projectPoints` Jacobian + Schur complement (recommended for OpenCV-as-primary mandatory-simple-baseline path), (b) wrap in GTSAM `Marginals` posterior (canonical Plan-phase pathway if user selects C4 candidate option C = GTSAM-factor-graph PnP as Selected modern-competitive-lead), (c) project-defined heuristic covariance scaling (likely AC-NEW-4 reject), (d) migrate to OpenGV's covariance-aware `absolute_pose::optimize_nonlinear` (couples D-C4-2 with D-C4-1 = OpenGV-as-primary instead of OpenCV-as-primary). **No new D-C4-3 or beyond raised by this closure**; further C4 candidates (OpenGV / GTSAM-factor-graph PnP / Theia / Ceres-only) will introduce additional D-C4-N gates as they close in subsequent sessions. **D-C4-1 carry-forward REINFORCED** — the 3D-2D-input-contract finding makes D-C4-1's 2D→3D lift architectural decision a HARD prerequisite for ANY C4 candidate (not unique to OpenCV); recommendation locked at 4-DoF flat-earth + IMU+barometer altitude + VIO/IMU attitude → planar-scene homography → 4-DoF pose extraction (project default) with ALOS-30m-DSM secondary mitigation. **C4 mandatory pre-screen status**: OpenCV solvePnPRansac closes the C4 mandatory pre-screen at **1 of N candidates** (mandatory-simple-baseline role STRUCTURALLY COMPLETE — no further mandatory-simple-baseline candidates required for the C4 row per engine Component Option Breadth rule). License: **Apache-2.0** for canonical `opencv/opencv` repo (Source #82) — clean BSD/permissive license track on the C4 mandatory-simple-baseline; under D-C1-1 = (a) GPL-3.0 track, (b) BSD/permissive lock, or (c) keep-both-tracks-open, OpenCV solvePnPRansac is **eligible on every license-posture choice with the simplest license-compliance story tied with cvg/LightGlue + DISK + XFeat on the C3 row**. **Position vs all expected C4 candidates**: OpenCV solvePnPRansac is the **canonical mandatory-simple-baseline reference** that the C4 row's modern competitive leads (OpenGV multi-camera + central-camera richer-minimal-solver-coverage / GTSAM-factor-graph PnP factor-graph posterior covariance-honest output / Theia large-scale SfM / Ceres-only manual implementation lowest-dependency baseline) must measurably exceed on documented-evidence axes (per-correspondence covariance honesty via D-C4-2, multi-camera generalization, factor-graph posterior recovery, RANSAC-variant breadth, SO(3)-correctness of LM refinement). Final ranking deferred to Jetson MVE phase per the project's D-C1-2 + locked-in research-time defaults strategy.

---

## C4 — Per-Mode API Capability Verification (engine Step 2 — OpenCV solvePnPRansac mandatory simple-baseline session entry, 2026-05-08)

### MVE — `cv::solvePnPRansac` with `flags=SOLVEPNP_EPNP` default minimal-sample-set + `iterationsCount=100, reprojectionError=8.0, confidence=0.99` canonical defaults + paired `cv::solvePnPRefineLM` LM refinement on inlier set (canonical mandatory-simple-baseline reference; `SOLVEPNP_IPPE` documented as preferred minimal-solver for D-C4-1 = 4-DoF flat-earth lift; `SOLVEPNP_SQPNP` documented as modern globally-optimal alternate for 6-DoF DSM-lift case; `SOLVEPNP_DLS` + `SOLVEPNP_UPNP` documented BROKEN — fall back to EPNP per Source #83 explicit docstring; D-C4-2 NEW covariance-recovery-strategy Plan-phase decision required for AC-NEW-4 covariance-honesty contract)
- **Source**: Source #82 (`opencv/opencv` canonical GitHub repo metadata — Apache-2.0 throughout per `license.spdx_id: "Apache-2.0"`; 87385 stars + 56554 forks + last pushed 2026-05-08T07:00:03Z = TODAY at access time; default branch `4.x`; topics include computer-vision + deep-learning + image-processing), Source #83 (canonical OpenCV 4.x calib3d module documentation + PnP tutorial page — `cv::solvePnPRansac` two function signatures [classical + USAC variant] + Python bindings; `cv::SolvePnPMethod` enum 9 values; `cv::solvePnPRefineLM` + alternate `cv::solvePnPRefineVVS`; `cv::solvePnPGeneric` for multi-solution reporting; USAC RANSAC-method enum 7 modern variants); cross-cite to Fact #20 + #21 closures from C2 row (canonical PnP+RANSAC+LM reference pipeline shape) + cross-cite to all C3 row closures (C3-output-to-C4-input contract is 2D-2D correspondences → 2D→3D lift via D-C4-1 → 3D-2D correspondences for solvePnPRansac)
- **Inputs in the example**: Two arbitrary point arrays — `objectPoints` Nx3 1-channel float32 (3D world coordinates of object points; for project's pinned mode = 3D points lifted from C3's satellite-tile-side 2D pixels via D-C4-1's 4-DoF flat-earth lift OR ALOS-30m-DSM lift) + `imagePoints` Nx2 1-channel float32 (2D image coordinates from C3's UAV-frame-side 2D pixels) + `cameraMatrix` 3x3 float32 (project's pinned 1× ADTi 20MP nav frame intrinsic matrix) + `distCoeffs` 5-vector float32 (project's pinned distortion coefficients from camera calibration); canonical example dim = up to 1024 3D-2D correspondences from D-C3-1 RECOMMENDED-PRIMARY-MITIGATION = DISK+LightGlue OR D-C3-1 ALTERNATE-MODERN-COMPETITIVE-LEAD = XFeat OR D-C3-1 SECONDARY-MITIGATION = ALIKED+LightGlue OR D-C3-1 documentary-baseline = SP+LightGlue OR D-C3-1 mandatory-simple-baseline = SuperGlue+SuperPoint
- **Outputs in the example**: `retval` (bool — RANSAC success indicator), `rvec` (3x1 Rodrigues rotation vector — convertible to 3x3 rotation matrix via `cv::Rodrigues`), `tvec` (3x1 translation vector — camera position in object/world frame), `inliers` (Mx1 int32 — indices of inlier correspondences in objectPoints/imagePoints; M ≤ N where M is the RANSAC-selected inlier count); after `cv::solvePnPRefineLM` invocation on the inlier set: refined `rvec, tvec` with reduced reprojection error; via paired `cv::solvePnPGeneric`: per-solution reprojection-error array. **6×6 covariance NOT directly returned** — D-C4-2 Plan-phase decision required for covariance-recovery-strategy
- **Project inputs**: Up to 1024 3D-2D correspondences per (UAV-frame, satellite-tile) image pair via D-C4-1's 4-DoF flat-earth lift recommendation (project default = altitude from IMU+barometer + attitude from VIO/IMU + planar-scene homography → 4-DoF pose extraction); per-frame compute = K=10 image pairs × 1 PnP+RANSAC+LM call per Fact #25 + AC-3.3 re-localization
- **Project outputs required**: `{6-DoF camera pose (R, t) w.r.t. tile + per-correspondence inlier mask + reprojection error from solvePnPGeneric + RANSAC iteration count + 6×6 covariance via D-C4-2's locked recovery strategy + source label `satellite_anchor`}` for C5 fused estimate per Fact #20 + #21 + AC-NEW-4 covariance-honesty contract. **Latency budget extrapolation to Jetson Orin Nano Super**: OpenCV solvePnPRansac CPU-only at 1024 correspondences with `iterationsCount=100, flags=SOLVEPNP_EPNP, confidence=0.99` extrapolated ~5-15 ms per call (Intel i7-class CPU baseline ~2-5 ms scaled to Jetson Orin Nano Super 6-core ARM Cortex-A78AE class with ~3× slowdown factor for non-vectorized path; could be reduced to ~3-8 ms with `flags=SOLVEPNP_IPPE` for the planar-scene case which has lower minimal-solver complexity). At K=10 pairs/frame extrapolated 50-150 ms total = **comfortable AC-4.1 satisfaction** with substantial margin (well below 400 ms budget; competitive with C3's projected ~30-300 ms total budget at K=10 pairs/frame depending on D-C3-1 selection)
- **Match assessment**: ✅ exact mode match for **(`cv::solvePnPRansac` with default RANSAC parameters + `flags=SOLVEPNP_EPNP` default minimal-sample-set + paired `cv::solvePnPRefineLM` LM refinement + paired `cv::solvePnPGeneric` reprojection-error reporting + Apache-2.0 license throughout)**; ✅ runnable example (canonical Python binding `cv2.solvePnPRansac` documented in Source #83 with explicit recommended defaults); ✅ all 9 `SolvePnPMethod` enum values documented (4 valid for general project use + 2 special-case + 1 ITERATIVE default + 2 BROKEN-fallback-to-EPNP); ✅ two function signatures documented (classical + USAC variant with `UsacParams` and `cameraMatrix` as `InputOutputArray` for focal-length refinement); ✅ paired LM refinement (`cv::solvePnPRefineLM`) + alternate Gauss-Newton SO(3) refinement (`cv::solvePnPRefineVVS`) + multi-solution reporting (`cv::solvePnPGeneric`) all documented; ⚠️ **3D-2D INPUT CONTRACT, NOT 2D-2D** (project must perform 2D→3D lift via D-C4-1's 4-DoF flat-earth lift recommendation; this is inherent to all PnP-class algorithms, not unique to OpenCV); ⚠️ **NO DIRECT 6×6 COVARIANCE OUTPUT** (D-C4-2 NEW Plan-phase decision required for covariance-recovery-strategy: (a) post-hoc Jacobian-based via `cv::projectPoints` Jacobian + Schur complement = recommended for OpenCV-as-primary path; (b) wrap in GTSAM `Marginals` posterior = couples with C4 option C; (c) heuristic covariance scaling = likely AC-NEW-4 reject; (d) migrate to OpenGV `absolute_pose::optimize_nonlinear` = couples D-C4-2 with D-C4-1); ⚠️ **Two minimal-solver enum values BROKEN** (SOLVEPNP_DLS + SOLVEPNP_UPNP fall back to EPNP per Source #83 explicit docstring — eliminates 2 of 6 user-listed solver options; valid set is `EPNP / AP3P / IPPE / SQPNP` plus 2 special-case); ⚠️ **`cv::solvePnPRefineLM` rotation update NOT on SO(3)** (alternate `cv::solvePnPRefineVVS` is the SO(3)-correct refiner via Gauss-Newton with exponential map)
- **If ⚠️ or ❌**: docs do not disqualify the algorithmic mode at the API level, and **NO HARD DISQUALIFIERS apply** at the deployment level. The (input-contract, minimal-solver, RANSAC-defaults, LM-refinement, output-shape, license) tuple is documented and runnable directly via canonical OpenCV 4.x calib3d module Python bindings for inference + LM-refinement + multi-solution reporting. **Two CONVERGING POSITIVE structural advantages** (clean Apache-2.0 throughout + dominant industry-standard reference with daily maintenance) make `cv::solvePnPRansac` **eligible as the C4 mandatory-simple-baseline reference** under every D-C1-1 license-posture choice. **Two NEGATIVE-BUT-MITIGABLE structural findings** (3D-2D input contract requires 2D→3D lift via D-C4-1; no direct 6×6 covariance output requires D-C4-2 covariance-recovery-strategy decision) are inherent to the PnP problem class and apply identically to all C4 candidates (OpenGV / GTSAM-factor-graph PnP / Theia / Ceres-only). **Two CAVEATS** (2 BROKEN solver enum values; LM rotation update not on SO(3)) are minor structural concerns that do not block the mandatory-simple-baseline role. → Status: **Mandatory simple-baseline (RANSAC-PnP reference floor) with TWO CONVERGING POSITIVE STRUCTURAL ADVANTAGES (clean Apache-2.0 throughout + dominant industry-standard reference) + TWO NEGATIVE-BUT-MITIGABLE STRUCTURAL FINDINGS (3D-2D input contract requires D-C4-1 lift; no direct 6×6 covariance requires D-C4-2 recovery strategy) + TWO MINOR CAVEATS (2 BROKEN solver enum values; LM rotation update not on SO(3))**, Apache-2.0 license track on the canonical opencv/opencv repo. **Final ranking deferred to Jetson MVE phase** per the project's D-C1-2 deferred-MVE strategy. Per the engine Component Option Breadth rule, OpenCV solvePnPRansac closes the C4 mandatory pre-screen mandatory-simple-baseline role at **1 of N candidates** (mandatory-simple-baseline role STRUCTURALLY COMPLETE — no further mandatory-simple-baseline candidates required). Subsequent C4 candidates (OpenGV multi-camera + central-camera richer-minimal-solver-coverage / GTSAM-factor-graph PnP factor-graph posterior covariance-honest output / Theia large-scale SfM / Ceres-only manual implementation lowest-dependency baseline) will be cataloged in subsequent sessions as modern-competitive-lead candidates.

---

## C4 — Per-numbered-Restriction × Per-numbered-AC Sub-Matrix per Candidate (OpenCV solvePnPRansac mandatory simple-baseline addition)

### OpenCV `cv::solvePnPRansac` — per-numbered binding (C4-relevant lines only; cross-cutting N/A above also apply identically)

> Cells share the legend defined under the C2/C3 sub-matrices. Where a binding is identical in substance and evidence to all expected C4 candidates (PnP-class generic), the OpenCV row says so explicitly to keep future C4 row entries (OpenGV / GTSAM-PnP / Theia / Ceres-only) compact; where OpenCV's pinned mode produces a materially different binding (mandatory-simple-baseline-only role with negative-but-mitigable structural findings on 3D-2D input contract + no direct covariance output), the OpenCV row carries a distinct evidence cite.

| Line | Binding | Evidence (one-line cite) |
|---|---|---|
| AC-1.1 (frame-center within 50 m, ≥80% normal-flight photos) | **Pass (mechanical via PnP+RANSAC inlier filter at default `reprojectionError=8.0` pixels) → Verify (depends on D-C4-1 lift accuracy + D-C3-1 correspondence quality)** | `cv::solvePnPRansac` with default `reprojectionError=8.0` pixels filters out gross outliers; final 50 m frame-center accuracy is **upper-bounded by D-C4-1's 2D→3D lift accuracy** (4-DoF flat-earth lift recommended; ALOS-30m-DSM secondary) + **lower-bounded by C3's per-correspondence inlier rate at the D-C3-1 selected matcher mode**. Project-side validation at Jetson MVE phase on AerialExtreMatch + Derkachi flight |
| AC-1.2 (frame-center within 20 m, ≥50% normal-flight photos) | **Pass (mechanical) → Verify — D-C4-1 lift accuracy is the binding constraint at the tighter tail** | Same as AC-1.1 with tighter tail; **D-C4-1's 4-DoF flat-earth lift accuracy** (varies with terrain elevation variation across the satellite tile + IMU+barometer altitude noise) becomes the dominant error source at 20 m tail; ALOS-30m-DSM secondary mitigation provides ~10× better per-tile elevation fidelity at substantial DSM acquisition + cache cost |
| AC-2.1b (satellite-anchor registration succeeds, AC-1.1/1.2 + AC-2.2 + AC-8.2 + AC-8.6 conditions) | **Pass (mechanical via inlier ratio threshold + reprojection error threshold) → Verify** | OpenCV solvePnPRansac provides `inliers` output array + per-solution `reprojectionError` from `cv::solvePnPGeneric` — both directly usable as C4-output gates for satellite-anchor registration success: project-defined thresholds `inlier_ratio > 0.3 AND mean_reprojection_error < 4.0 pixels` are documented heuristic gates from canonical OpenCV PnP+RANSAC literature; final thresholds set at Plan-phase + Jetson MVE refinement |
| AC-3.3 (≥3 disconnected segments via satellite-reference re-localization) | **Pass (per-frame stateless)** | OpenCV solvePnPRansac is stateless per (UAV-frame, satellite-tile) image pair — no cross-frame state required for re-localization; same per-pair statelessness as C3 candidates; project's K=10 top-K image pairs per UAV frame each invoke independent solvePnPRansac calls |
| AC-4.1 (latency <400 ms p95, end-to-end camera→FC) | **Pass (with Verify) — comfortable margin extrapolated to Jetson Orin Nano Super** | OpenCV solvePnPRansac CPU-only at 1024 correspondences with `iterationsCount=100, flags=SOLVEPNP_EPNP, confidence=0.99` extrapolated ~5-15 ms per call on Jetson Orin Nano Super (Intel i7-class baseline ~2-5 ms × 3× ARM Cortex-A78AE-class slowdown factor for non-vectorized path; could be reduced to ~3-8 ms with `flags=SOLVEPNP_IPPE` planar-scene minimal-solver). At K=10 pairs/frame extrapolated 50-150 ms total = **comfortable AC-4.1 satisfaction** with substantial margin (well below 400 ms budget; competitive with C3's projected budget). **D-C4-2 covariance-recovery-strategy adds ~2-5 ms per call** for option (a) post-hoc Jacobian-based recovery via `cv::projectPoints` Jacobian + Schur complement — manageable in the budget |
| AC-4.2 (memory <8 GB shared) | **Pass — minimal model footprint** | OpenCV solvePnPRansac is a classical algorithm with no model weights — minimal memory footprint (a few KB per RANSAC iteration for working buffers). Co-resident memory pressure with C1/C2/C3/C5/C6 is **negligible** — this is the **lightest-weight C4 candidate by an order of magnitude** (vs GTSAM-factor-graph PnP which carries the GTSAM library + factor-graph state machinery at ~50-200 MB depending on graph size; vs OpenGV which is similarly classical but ships a slightly larger C++ library at ~10-30 MB) |
| AC-8.1 (cache-interface resolution ≥0.5 m/px, ideally 0.3 m/px) | **N/A — algorithm-level** | OpenCV solvePnPRansac is resolution-agnostic at the algorithm level; cache-interface resolution constraint applies at the C6 (tile cache + spatial index) layer, NOT C4 |
| AC-8.6 — Scale-ratio (any UAV-frame ground footprint at deployment altitude must be retrievable) | **N/A — algorithm-level** | Same as AC-8.1; scale-ratio constraint applies at the C2/C6 layer (VPR retrieval + tile cache), NOT C4 |
| AC-8.6 — Scene change in active-conflict sectors | **N/A — algorithm-level (PnP+RANSAC has no scene-change sensitivity)** | OpenCV solvePnPRansac is a classical pose-from-correspondences algorithm with no scene-change sensitivity; the scene-change axis is upstream at C2 (VPR retrieval) + C3 (matcher cross-domain generalization). C4 inherits whatever inlier ratio C3 delivers |
| AC-8.6 — Compute & latency under steady-state and re-loc-trigger | **Pass (with Verify) — comfortable margin** | Same as AC-4.1; OpenCV solvePnPRansac extrapolates to ~5-15 ms per call on Jetson Orin Nano Super at K=10 pairs/frame = 50-150 ms total |
| AC-NEW-2 (spoofing-promotion latency <3 s p95) | **Pass (mechanical) with comfortable margin** | OpenCV solvePnPRansac single-call latency on Jetson extrapolated ~5-15 ms vs 3 s budget = ~200-600× headroom; spoofing-promotion latency budget is dominated by C2 + C3 + C5 fusion, not C4 |
| AC-NEW-4 (covariance honesty — 6×6 pose covariance must be honest, not identity-matrix placeholder) | **CRITICAL FAIL via DEFAULT API + Pass via D-C4-2 covariance-recovery-strategy** | **CRITICAL D-C4-2 finding for OpenCV solvePnPRansac**: Source #83 function signature returns `retval, rvec, tvec, inliers` only — **NO direct 6×6 covariance output**. AC-NEW-4 covariance-honesty contract requires project to choose D-C4-2 covariance-recovery-strategy: (a) **post-hoc Jacobian-based via `cv::projectPoints` Jacobian + Schur complement** (recommended for OpenCV-as-primary path; ~1 day engineering; pure OpenCV API; covariance approximation of equivalent quality to ROS `tf2`'s standard recipe); (b) **wrap solvePnPRansac result in GTSAM `Marginals` posterior** (canonical Plan-phase pathway if user selects C4 candidate option C = GTSAM-factor-graph PnP as Selected modern-competitive-lead); (c) project-defined heuristic covariance scaling = likely **AC-NEW-4 REJECT** since it's effectively an identity-matrix-placeholder family; (d) migrate to OpenGV's `absolute_pose::optimize_nonlinear` with explicit Jacobian propagation = couples D-C4-2 with D-C4-1 = OpenGV-as-primary instead of OpenCV-as-primary. **Recommendation**: D-C4-2 = (a) post-hoc Jacobian-based recovery for the OpenCV-as-primary mandatory-simple-baseline path; D-C4-2 = (b) factor-graph posterior for the GTSAM-as-primary modern-competitive-lead path |
| AC-NEW-6 (imagery freshness — never `satellite_anchored` on stale-tile match) | **N/A — algorithm-level** | OpenCV solvePnPRansac has no awareness of tile freshness; the tile-freshness axis is at the C6 (tile cache) layer; C4 simply consumes whatever 3D world points + 2D image points are passed in |
| AC-NEW-7 (cache-poisoning safety budget — P(>30 m geo-misalign) <1%, P(>100 m) <0.1%) | **Pass — STRUCTURAL geometric-verification at simple-baseline reference floor** | OpenCV solvePnPRansac's RANSAC-with-`reprojectionError=8.0`-pixel-threshold filter provides structural geometric-verification layer that rejects gross cache-poisoning attempts (any forced satellite-tile feature that does not project consistently within 8 pixels of the UAV-frame correspondence will be marked outlier and excluded from the LM refinement). Combined with C3's per-correspondence confidence threshold τ=0.1, this provides **two-layer structural defense against cache poisoning** at the simple-baseline reference floor |
| Restriction "Operational area: eastern/southern Ukraine" — sparse-matcher train-domain match | **N/A — algorithm-level** | OpenCV solvePnPRansac is a classical algorithm with no training data; train-domain caveat applies at C2/C3 layers, NOT C4. **D-C2-1 retrain decision is irrelevant for OpenCV solvePnPRansac** |
| Restriction "Altitude ≤1 km AGL; terrain assumed flat (rolling steppe / agricultural)" — D-C4-1 lift accuracy | **STRUCTURAL ALIGNMENT — 4-DoF flat-earth lift is the project default** | **CRITICAL POSITIVE finding for OpenCV solvePnPRansac**: The "terrain assumed flat" restriction directly aligns with D-C4-1's locked-in research-time recommendation of **4-DoF flat-earth lift** (altitude from IMU+barometer + attitude from VIO/IMU + planar-scene homography → 4-DoF pose extraction). The **paired `flags=SOLVEPNP_IPPE`** minimal-solver is **purpose-built for planar-scene PnP** (Source #83 IPPE enum docstring "Object points must be coplanar") — provides best documentary structural fit for the project's flat-earth operational assumption |
| Restriction "Weather: predominantly sunny ... seasonal/visibility classes" — sparse-matcher cross-season generalization | **N/A — algorithm-level** | Cross-season generalization applies at C2/C3 layers; OpenCV solvePnPRansac is classical and has no seasonal sensitivity |
| Restriction "Navigation camera (pinned): ADTi 20MP, 5472×3648" | **Pass (API) — resolution-agnostic** | OpenCV solvePnPRansac is fully resolution-agnostic at the algorithm level; consumes Nx2 image points from any source resolution (project's pinned C3 output = 1024-largest-edge after C3 downscale, but this is C3's concern not C4's) |
| Restriction "Satellite Imagery — resolution ≥0.5 m/px" — sparse-matcher pipeline at AC-8.1 floor | **N/A — algorithm-level** | Same as AC-8.1 |
| Restriction "Satellite Imagery — Cache budget: 10 GB" — C4 cache footprint | **Pass — NO C4 cache footprint** | **C4 cache footprint is exactly 0 GB** — same as C3; OpenCV solvePnPRansac is stateless per call with no persistent state. Library binary footprint ~10-50 MB at fp32 (OpenCV calib3d module shared library) loaded once at boot; not part of cache budget |
| Restriction "Companion computer: Jetson Orin Nano Super, 8 GB shared" | **Pass with COMFORTABLE MARGIN — extrapolated 5-15 ms per call** | **CRITICAL POSITIVE finding for OpenCV solvePnPRansac**: classical algorithm with no GPU dependency; Source #82 + #83 confirm Jetson Linux distribution ships canonical OpenCV with `libopencv_calib3d.so` available out-of-the-box on JetPack 6; CPU-only path is the canonical deployment runtime. Extrapolated ~5-15 ms per call on Jetson Orin Nano Super 6-core ARM Cortex-A78AE = comfortable AC-4.1 satisfaction. **D-C4-2 covariance-recovery-strategy choice (a) post-hoc Jacobian-based via `cv::projectPoints` Jacobian + Schur complement adds ~2-5 ms per call** — manageable in the budget. **No GPU competition** with C2/C3 (which are GPU-heavy on the Ampere 1024-core fp16 path) — C4 runs entirely on CPU, freeing GPU for C2/C3 inference |
| Restriction "License posture (D-C1-1)" — C4-class license-track interaction | **POSITIVE finding (CLEAN-APACHE-2.0 license track THROUGHOUT) — eligible on every D-C1-1 license-posture choice** | **POSITIVE on canonical `opencv/opencv`**: Source #82 GitHub API license metadata = **Apache-2.0 (`license.spdx_id: "Apache-2.0"`)** — permissive, BSD/permissive license track. **CLEAN APACHE-2.0 LICENSE TRACK THROUGHOUT** — no copyleft, no Magic Leap restrictive disqualifier, no BSD-3-Clause + Apache-2.0 mixed track. Tied with cvg/LightGlue + DISK + XFeat for the cleanest license-compliance story across all C-row components evaluated. Under D-C1-1 = (a) GPL-3.0 track, (b) BSD/permissive lock, or (c) keep-both-tracks-open, OpenCV solvePnPRansac is **eligible on every license-posture choice with the simplest license-compliance story**. **MANDATORY-SIMPLE-BASELINE role per engine Component Option Breadth rule** — OpenCV solvePnPRansac is **deployment-ready under every license-posture choice**; the role's purpose is to establish the long-established RANSAC-PnP reference floor against which modern competitive leads (OpenGV / GTSAM-factor-graph PnP / Theia / Ceres-only) must measurably exceed at deployment-ready license + Jetson-friendly runtime + covariance honesty |

---

### Fact #53 — OpenGV `absolute_pose::AbsolutePoseSacProblem` + `optimize_nonlinear` per-mode API capability verification (canonical `laurentkneip/opengv` library — RANSAC-PnP with 4 algorithm-selectable minimal solvers `KNEIP / GAO / EPNP / GP3P` + non-central + generalized-camera support + adapter-pattern bearing-vector input contract; **MODERN-COMPETITIVE-LEAD candidate** for the C4 row's richer-minimal-solver-coverage axis vs OpenCV; on Jetson Orin Nano Super) — DOCUMENTARY PASS WITH BSD-3-CLAUSE-EQUIVALENT-LICENSE (Plan-phase license-clearance verification gate D-C4-3 NEW required due to NOASSERTION SPDX-detector status) + ~3-YEARS-MAINTENANCE-STALENESS (D-C4-4 NEW maintenance-staleness-mitigation gate) + RICHER-MINIMAL-SOLVER-COVERAGE-THAN-OPENCV (4 algorithm-selectable RANSAC enums + 2 P3P variants + 1 UPnP global-optimal + 1 generalized-camera GP3P) + BEARING-VECTOR-INPUT-CONTRACT (adapter required vs OpenCV's direct pixel input) + 3D-ANGLE-RANSAC-THRESHOLD (conversion required vs OpenCV's pixel reprojection error) + NO-DIRECT-6×6-COVARIANCE-OUTPUT (D-C4-2 NEW gate APPLIES IDENTICALLY) + NO-PLANAR-SCENE-DEDICATED-SOLVER (vs OpenCV's `flags=SOLVEPNP_IPPE`); opens C4 row at **2 of N candidates** (modern-competitive-lead-richer-minimal-solver role)
- **Statement**: OpenGV (`laurentkneip/opengv` canonical implementation, `opengv/include/opengv/absolute_pose/` + `opengv/include/opengv/sac/` + `opengv/include/opengv/sac_problems/absolute_pose/` modules, BSD-3-Clause-equivalent License.txt confirmed via Source #84 direct WebFetch) is the **MODERN-COMPETITIVE-LEAD candidate** for the C4 row's richer-minimal-solver-coverage axis — the canonical reference for non-OpenCV PnP minimal solvers + non-central + generalized-camera support + central-camera UPnP global-optimal alternate. Per the per-Mode API Capability Verification rule, the project's pinned mode is the **(`absolute_pose::CentralAbsoluteAdapter adapter(bearingVectors, points)` + `sac_problems::absolute_pose::AbsolutePoseSacProblem(adapter, KNEIP)` + `sac::Ransac` with `ransac.threshold_ = 1.0 - cos(atan(reprojection_pixel_error * sqrt(2.0) * 0.5 / focal_length_pixels))` + `ransac.max_iterations_ = 100` + `ransac.computeModel(); ransac.model_coefficients_;` followed by `adapter.sett(t_initial); adapter.setR(R_initial); absolute_pose::optimize_nonlinear(adapter)` LM refinement on the inlier set) → 6-DoF camera pose (R, t)**. **Mode-enumeration query (1/3) — context7 NOT INDEXED + WebFetch fallback PASS**: `context7 resolve-library-id` returned only OpenCV variants for the OpenGV query (top-5 results were `/websites/opencv_4_x` + `/websites/opencv_4_6_0` + `/opencv/opencv` + `/opencv/opencv-python` + `/websites/opencv_5_0_0-alpha` — all unrelated to OpenGV); per Per-Mode API Capability Verification rule item 2, fall-back to official-docs WebFetch on canonical Doxygen portal `laurentkneip.github.io/opengv/page_how_to_use.html` was used (Source #85) plus canonical GitHub API license metadata WebFetch (Source #84) plus canonical License.txt WebFetch (Source #84). **Four absolute-pose minimal solvers documented** (Source #85 §"Central absolute pose"): `absolute_pose::p2p` (with known rotation; uses `adapter.setR(knownRotation)` prior; minimal-solver for 2 correspondences with known rotation), `absolute_pose::p3p_kneip` [Kneip et al. CVPR 2011; canonical Kneip P3P; classical reference for OpenGV-distinctive minimal solver], `absolute_pose::p3p_gao` [Gao et al. PAMI 2003; classical Gao P3P alternate], `absolute_pose::upnp` [Kneip et al. ECCV 2014; **modern globally-optimal alternate without planarity restriction — structurally analogous role to OpenCV's `flags=SOLVEPNP_SQPNP` for the 6-DoF DSM-lift case**]. **Two absolute-pose non-minimal solvers documented**: `absolute_pose::epnp` [Lepetit et al. IJCV 2009; **same algorithm as OpenCV's `flags=SOLVEPNP_EPNP` — direct cross-citation for Plan-phase apples-to-apples comparison**], `absolute_pose::upnp` (also valid for non-minimal). **Two generalized/multi-camera absolute-pose solvers documented** (Source #85 §"Non-central absolute pose"): `absolute_pose::gp3p` (Kneip 3-point generalized P3P for multi-camera rigs), `absolute_pose::gpnp` [Kneip 2014 generalized PnP for multi-camera rigs]. **One non-linear LM optimizer documented**: `absolute_pose::optimize_nonlinear(adapter)` — handles both central + non-central cases; canonical refinement after RANSAC (Source #85 §"Central absolute pose" closing example). **RANSAC integration documented** (Source #85 §"Central absolute pose" + §"Some words about the sample-consensus-classes"): `sac::Ransac<sac_problems::absolute_pose::AbsolutePoseSacProblem>` + `sac_problems::absolute_pose::AbsolutePoseSacProblem(adapter, algorithm)` with **algorithm parameter selectable from {KNEIP, GAO, EPNP, GP3P}** (richer minimal-solver selection than OpenCV's effectively-4-valid SolvePnPMethod enum [EPNP/AP3P/IPPE/SQPNP after 2 BROKEN entries removed]; OpenGV provides 2 P3P variants [Kneip + Gao] vs OpenCV's 1 P3P variant [Ke & Roumeliotis 2017 AP3P]; OpenGV provides UPnP for both minimal+non-minimal vs OpenCV's separate ITERATIVE+EPNP+SQPNP+IPPE). **Pinned-mode runnable example query (2/3) — WebFetch PASS**: Source #85 §"Central absolute pose" provides the canonical OpenGV runnable example: `absolute_pose::CentralAbsoluteAdapter adapter(bearingVectors, points); std::shared_ptr<sac_problems::absolute_pose::AbsolutePoseSacProblem> absposeproblem_ptr(new sac_problems::absolute_pose::AbsolutePoseSacProblem(adapter, sac_problems::absolute_pose::AbsolutePoseSacProblem::KNEIP)); sac::Ransac<sac_problems::absolute_pose::AbsolutePoseSacProblem> ransac; ransac.sac_model_ = absposeproblem_ptr; ransac.threshold_ = 1.0 - cos(atan(sqrt(2.0)*0.5/800.0)); ransac.max_iterations_ = maxIterations; ransac.computeModel(); ransac.model_coefficients_;` followed by optional `absolute_pose::optimize_nonlinear(adapter)` LM refinement on the inlier set. **Disqualifier-probe query (3/3) — FIVE FINDINGS (2 negative-but-mitigable structural + 3 caveats)**: (i) **CRITICAL contract finding — OpenGV uses bearing vectors (3D unit vectors) as input, NOT 2D pixel coordinates** (Source #85 explicit "OpenGV assumes to be in the calibrated case, and landmark measurements are always given in form of bearing vectors in a camera frame"); the project must implement a `CentralAbsoluteAdapter(bearingVectors, points)` constructor or pre-compute unit-vector conversion from C3's pixel correspondences via inverse camera-intrinsic projection — additional engineering vs OpenCV's direct pixel input contract; this is an API-level structural difference, not a fundamental algorithmic limitation; recommendation: implement a project-side `OpenGVAdapter` that wraps C3's pixel correspondences + cached inverse-intrinsic projection in O(1) per correspondence; (ii) **CRITICAL covariance finding — `optimize_nonlinear` does NOT directly emit a 6×6 pose covariance** (Source #85 documentation does not document a covariance output API; Source #84 GitHub repo source-code search confirms no `Marginals`-equivalent API); D-C4-2 covariance-recovery-strategy applies identically to OpenGV — Plan-phase mitigation strategies (a) post-hoc Jacobian-based via custom Jacobian propagation through `optimize_nonlinear` residuals (more engineering than OpenCV's `cv::projectPoints` Jacobian since OpenGV's Jacobian is over bearing-vector residuals not pixel residuals; ~3-5 days engineering) OR (b) wrap OpenGV result in GTSAM `Marginals` posterior (couples C4 = OpenGV-as-primary with C5 = GTSAM-factor-graph fusion) OR (c) heuristic scaling = AC-NEW-4 REJECT family; (iii) **CRITICAL maintenance staleness — last commit 2023-06-07T18:14:14Z = ~2 years 11 months stale at access time 2026-05-08** (Source #84 GitHub API `pushed_at` field); D-C4-4 NEW Plan-phase maintenance-staleness-mitigation gate required: (a) accept-as-is + freeze upstream / (b) fork into project-controlled branch + apply Eigen-3.4+ + JetPack-6 + ARM Cortex-A78AE patches in-house / (c) migrate to Ceres-only as fallback if patches not feasible / (d) downgrade OpenGV to "experimental" status and pivot to OpenCV-as-primary if Plan-phase license-clearance fails; (iv) **License-clearance contingency — License.txt is BSD-3-Clause-equivalent boilerplate but GitHub SPDX detector reports `license.spdx_id: "NOASSERTION"`** (Source #84 GitHub API metadata); D-C4-3 NEW Plan-phase license-clearance verification gate required for dual-use deployment compliance — recommend Plan-phase counsel-review of License.txt text to confirm BSD-3-Clause-equivalent dual-use compatibility before adoption; (v) **NO planar-scene dedicated minimal solver** — OpenGV does NOT have a planar-scene PnP solver equivalent to OpenCV's `flags=SOLVEPNP_IPPE` (Collins & Bartoli ECCV 2014 IPPE); for project's planar-scene D-C4-1 = 4-DoF flat-earth lift case, OpenGV requires using Kneip's P3P or EPNP without the planar-scene specialization advantage that OpenCV provides — this is a **DOCUMENTARY NEGATIVE finding for OpenGV** in the context of D-C4-1 = 4-DoF flat-earth lift; for the 6-DoF DSM-lift case, OpenGV's UPnP is the modern globally-optimal alternate (analogous structural role to OpenCV's `flags=SOLVEPNP_SQPNP`); (vi) **3D-angle RANSAC threshold structure** (Source #85 §"Ransac threshold"): `ransac.threshold_ = 1.0 - cos(atan(reprojection_pixel_error * sqrt(2.0) * 0.5 / focal_length_pixels))` — project must convert from pixel-reprojection-error budget at runtime (e.g., for OpenCV-equivalent 8.0-pixel reprojection error at focal length 4000 px [project's pinned ADTi 20MP nav camera with ~17 mm focal length on 5.5 µm pixel pitch], threshold = `1.0 - cos(atan(8.0 * sqrt(2.0) * 0.5 / 4000.0))` = ~3.99e-6); minor engineering, not a structural limitation. **Pinned-mode sentence**: "We will catalog **OpenGV `absolute_pose::AbsolutePoseSacProblem(KNEIP)` + paired `absolute_pose::optimize_nonlinear`** with **`KNEIP` minimal-solver default + `ransac.threshold_ = 1.0 - cos(atan(reprojection_pixel_error * sqrt(2.0) * 0.5 / focal_length_pixels))` 3D-angle threshold + `ransac.max_iterations_ = 100` + BSD-3-Clause-equivalent license** as the **MODERN-COMPETITIVE-LEAD candidate for the C4 row's richer-minimal-solver-coverage axis** per engine Component Option Breadth rule. Inputs `{up to 1024 bearing vectors derived from C3's UAV-frame pixel correspondences via inverse camera-intrinsic projection + 3D world points lifted from C3's satellite-tile-side pixels via D-C4-1's 2D→3D lift (project default = 4-DoF flat-earth + IMU+barometer altitude + VIO/IMU attitude prior → planar-scene homography → 4-DoF pose extraction; ALOS-30m-DSM secondary mitigation) + project-side OpenGVAdapter wrapping C3 correspondences + cached inverse-intrinsic projection in O(1) per correspondence}`; expected outputs `{6-DoF camera pose (R, t) from `ransac.model_coefficients_` + per-correspondence inlier mask from `ransac.inliers_` + RANSAC iteration count from `ransac.iterations_` + 6×6 covariance via D-C4-2's covariance-recovery-strategy decision (option (b) wrap-in-GTSAM-Marginals = recommended for OpenGV-as-primary path since OpenGV-internal Jacobian recovery is ~3-5 days engineering vs ~1 day for OpenCV's `cv::projectPoints` Jacobian) + source label `satellite_anchor` for C5 fused estimate}`; runtime `Jetson Orin Nano Super (8 GB shared, JetPack 6, ROS 2 Humble) — custom build required` (no canonical Jetson distribution; D-C4-4 NEW maintenance-staleness gate). **MODERN-COMPETITIVE-LEAD-RICHER-MINIMAL-SOLVER role per engine Component Option Breadth rule** — OpenGV's structural distinction from OpenCV is **richer minimal-solver coverage** (4 algorithm-selectable RANSAC enums + 2 P3P variants + 1 UPnP global-optimal + 1 generalized-camera GP3P) at the cost of (i) bearing-vector input adapter engineering + (ii) 3D-angle RANSAC threshold conversion + (iii) ~3-year maintenance staleness + (iv) NOASSERTION SPDX-detector license-clearance contingency + (v) NO planar-scene dedicated solver vs OpenCV's IPPE.
- **Source**: Source #84 (canonical `laurentkneip/opengv` GitHub repo + License.txt — BSD-3-Clause-equivalent boilerplate (`license.spdx_id: "NOASSERTION"` due to non-canonical-SPDX-template formatting); 1109 stars + 358 forks + 66 subscribers + 58 open issues + last pushed 2023-06-07T18:14:14Z = ~2 years 11 months stale at access time; default branch `master`; ShanghaiTech Mobile Perception Lab claimed maintenance contradicted by commit history; description "OpenGV is a collection of computer vision methods for solving geometric vision problems"), Source #85 (canonical OpenGV Doxygen documentation portal `laurentkneip.github.io/opengv/page_how_to_use.html` generated 2018-01-08 21:43:04 by Doxygen 1.8.11 — adapter-pattern interface with three base-classes [`AbsoluteAdapterBase`, `RelativeAdapterBase`, `PointCloudAdapterBase`]; bearing-vector input contract; 3D-angle RANSAC threshold structure; canonical runnable examples for absolute-pose + relative-pose + non-central + multi-camera; 4 absolute-pose minimal solvers + 2 non-minimal solvers + 2 generalized-camera solvers + 1 LM optimizer + 4-algorithm RANSAC integration); cross-cite to Fact #52 closure (canonical OpenCV solvePnPRansac mandatory simple-baseline reference for direct apples-to-apples comparison on shared `epnp` algorithm); cross-cite to Fact #20 + #21 closures from C2 row (canonical PnP+RANSAC+LM reference pipeline shape feeds AC-NEW-4 covariance-honesty contract via D-C4-2 NEW gate that applies identically to OpenGV)
- **Phase**: Phase 2
- **Target Audience**: System architects + C4 implementer + Step-7.5 reviewer + license-posture decision-maker (D-C1-1 + D-C4-3 NEW license-clearance verification) + maintenance-staleness-mitigation decision-maker (D-C4-4 NEW) + Plan-phase architect (modern-competitive-lead-richer-minimal-solver role documentation for engine Component Option Breadth rule compliance + bearing-vector adapter engineering work + 3D-angle threshold conversion engineering work + D-C4-2 covariance-recovery-strategy applies identically as on OpenCV)
- **Confidence**: ✅ for mode-enumeration (4 absolute-pose minimal solvers + 2 non-minimal solvers + 2 generalized-camera solvers + 1 LM optimizer + 4 RANSAC algorithm enums [KNEIP/GAO/EPNP/GP3P] documented in canonical Source #85 Doxygen portal page), runnable-example (canonical C++ example documented in Source #85 with explicit `sac::Ransac` + `AbsolutePoseSacProblem` + `optimize_nonlinear` integration), license (**BSD-3-Clause-equivalent** confirmed via Source #84 License.txt direct WebFetch — three numbered redistribution conditions including non-endorsement clause; **D-C4-3 NEW Plan-phase license-clearance verification gate** required due to GitHub SPDX detector reporting `NOASSERTION`); ✅ for **richer minimal-solver coverage than OpenCV** finding (4 algorithm-selectable RANSAC enums + 2 P3P variants + 1 UPnP global-optimal + 1 generalized-camera GP3P documented in Source #85 vs OpenCV's effectively-4-valid SolvePnPMethod enum after 2 BROKEN entries removed); ✅ for **bearing-vector input contract** finding (Source #85 explicit "OpenGV assumes to be in the calibrated case, and landmark measurements are always given in form of bearing vectors in a camera frame"); ✅ for **3D-angle RANSAC threshold structure** finding (Source #85 §"Ransac threshold" canonical conversion `ransac.threshold_ = 1.0 - cos(atan(sqrt(2.0)*0.5/800.0))`); ✅ for **NO direct 6×6 covariance output from `optimize_nonlinear`** finding (Source #85 documentation does not document a covariance output API); ✅ for **NO planar-scene dedicated minimal solver** finding (Source #85 documents no IPPE-equivalent for OpenGV); ⚠️ for **maintenance staleness** (Source #84 last pushed 2023-06-07T18:14:14Z = ~2 years 11 months stale at access time 2026-05-08; D-C4-4 NEW Plan-phase mitigation gate required); ⚠️ for **license-clearance contingency** (Source #84 GitHub API SPDX detector reports `NOASSERTION`; D-C4-3 NEW Plan-phase verification gate required); ⚠️ for **Jetson Orin Nano Super deployment latency / memory / accuracy** (no documentary measurement; extrapolation from x86_64 RTX-class CPU canonical OpenGV PnP+RANSAC throughput at 1024 correspondences with `KNEIP minimal solver, max_iterations_=100` ~3-8 ms per call CPU-only on Intel i7-class — comparable to OpenCV's 2-5 ms baseline; Jetson Orin Nano Super extrapolation ~10-25 ms per call CPU-only at K=10 pairs/frame extrapolated 100-250 ms total = comfortable AC-4.1 satisfaction); ❌ for **canonical-checkpoint aerial-domain fitness** — N/A for OpenGV since it is a classical algorithm library, not a learned method (no canonical-weights aerial-domain caveat applies); ❌ for **post-hoc 6×6 covariance recovery via Jacobian-based propagation** (no canonical OpenGV reference implementation; project must implement custom Jacobian propagation through bearing-vector residuals at ~3-5 days engineering OR wrap result in GTSAM `Marginals` posterior at canonical Plan-phase D-C4-2 = (b) pathway)
- **Related Dimension**: SQ3+SQ4 / C4 modern-competitive-lead-richer-minimal-solver-coverage role (engine Component Option Breadth rule role — analogous structural role to DISK+LightGlue's RECOMMENDED-PRIMARY-MITIGATION + XFeat's ALTERNATE-MODERN-COMPETITIVE-LEAD roles in C3 row but for C4) — per-mode API capability verification gate
- **Fit Impact**: **DOCUMENTARY PASS for the per-mode API capability verification gate at the modern-competitive-lead-richer-minimal-solver role** with Plan-phase license-clearance verification + maintenance-staleness mitigation contingencies — `absolute_pose::AbsolutePoseSacProblem` has documented runnable per-mode examples with the project's pinned configuration (canonical OpenGV adapter pattern + canonical sac::Ransac + canonical optimize_nonlinear), 4 algorithm-selectable RANSAC enums [KNEIP/GAO/EPNP/GP3P], 2 P3P variants [Kneip 2011 + Gao 2003], 1 UPnP global-optimal alternate [Kneip 2014], 1 generalized-camera GP3P, 2 generalized-camera non-minimal solvers [GP3P + GPNP]. **Two CONVERGING POSITIVE structural advantages**: (i) **RICHER MINIMAL-SOLVER COVERAGE THAN OPENCV** — 4 algorithm-selectable RANSAC enums + 2 P3P variants + 1 UPnP global-optimal alternate + 1 generalized-camera GP3P vs OpenCV's effectively-4-valid SolvePnPMethod enum (after 2 BROKEN entries removed); on a per-feature axis OpenGV provides Kneip's original 2011 P3P that OpenCV does NOT distribute (OpenCV's P3P is Ke & Roumeliotis 2017 AP3P only); (ii) **GENERALIZED-CAMERA + NON-CENTRAL ABSOLUTE POSE SUPPORT** — `absolute_pose::gp3p` + `absolute_pose::gpnp` for multi-camera rigs; not directly applicable to project's pinned 1× ADTi 20MP nav frame but architecturally cleaner if the project later adds a side-looking camera. **Five NEGATIVE-BUT-MITIGABLE structural findings**: (iii) **BEARING-VECTOR INPUT CONTRACT** — adapter or pre-computed unit-vector conversion required from C3's pixel correspondences (additional engineering vs OpenCV's direct pixel input); (iv) **3D-ANGLE RANSAC THRESHOLD** — conversion required from project's pixel-reprojection-error budget; (v) **NO DIRECT 6×6 COVARIANCE OUTPUT** — D-C4-2 NEW gate APPLIES IDENTICALLY to OpenGV; (vi) **~3 YEARS MAINTENANCE STALENESS** — D-C4-4 NEW Plan-phase mitigation gate required (accept-as-is + freeze / fork + apply patches in-house / migrate to Ceres-only fallback); (vii) **NOASSERTION SPDX-detector status** — D-C4-3 NEW Plan-phase license-clearance verification gate required (License.txt is BSD-3-Clause-equivalent but Plan-phase counsel-review recommended). **One MAJOR DOCUMENTARY NEGATIVE finding vs OpenCV**: (viii) **NO PLANAR-SCENE DEDICATED MINIMAL SOLVER** — OpenGV does NOT have a planar-scene PnP solver equivalent to OpenCV's `flags=SOLVEPNP_IPPE` (Collins & Bartoli ECCV 2014); for project's D-C4-1 = 4-DoF flat-earth lift recommendation, OpenGV requires using Kneip's P3P or EPNP without the planar-scene specialization advantage that OpenCV provides. **NEW Plan-phase decisions raised by OpenGV closure**: **D-C4-3 NEW license-clearance verification** — Plan-phase counsel-review of License.txt to confirm BSD-3-Clause-equivalent dual-use compatibility (NOASSERTION SPDX detector caveat); **D-C4-4 NEW maintenance-staleness-mitigation strategy** — Plan-phase decision between (a) accept-as-is + freeze upstream / (b) fork into project-controlled branch + apply Eigen-3.4+ + JetPack-6 + ARM Cortex-A78AE patches in-house at ~1-2 weeks engineering / (c) migrate to Ceres-only as fallback if patches not feasible / (d) downgrade OpenGV to "experimental" status and pivot to OpenCV-as-primary if D-C4-3 license-clearance fails. **D-C4-1 carry-forward IDENTICAL** — bearing-vector input contract still requires 2D→3D lift on satellite-tile-side from pixel correspondences (4-DoF flat-earth lift recommendation per locked-in research-time defaults). **D-C4-2 carry-forward IDENTICAL** — `optimize_nonlinear` returns no covariance; same Plan-phase mitigation strategies apply (recommendation for OpenGV-as-primary path is option (b) wrap-in-GTSAM-Marginals since OpenGV-internal Jacobian recovery is ~3-5 days engineering vs ~1 day for OpenCV's `cv::projectPoints` Jacobian). **C4 mandatory pre-screen status**: OpenGV closes the C4 modern-competitive-lead-richer-minimal-solver role at **2 of N candidates**. License: **BSD-3-Clause-equivalent** for canonical `laurentkneip/opengv` repo (Source #84 License.txt direct WebFetch verified) — clean BSD/permissive license track CONTINGENT on Plan-phase license-clearance verification gate (D-C4-3); under D-C1-1 = (a) GPL-3.0 track, (b) BSD/permissive lock, or (c) keep-both-tracks-open, OpenGV is **eligible on every license-posture choice CONTINGENT on D-C4-3 verification**. **Position vs OpenCV (Fact #52 mandatory simple-baseline)**: OpenGV provides richer minimal-solver coverage at the cost of (i) bearing-vector adapter engineering + (ii) 3D-angle threshold conversion + (iii) maintenance staleness + (iv) NOASSERTION license-clearance contingency + (v) NO planar-scene dedicated solver — net structural trade-off favors OpenCV-as-primary for the project's D-C4-1 = 4-DoF flat-earth lift case (since OpenCV's `flags=SOLVEPNP_IPPE` is purpose-built for exactly this case) and OpenGV-as-secondary-evaluation if Plan-phase Jetson MVE shows the need for non-central or generalized-camera support. **Position vs GTSAM (Fact #54 modern-competitive-lead-covariance-honest)**: OpenGV does NOT directly satisfy AC-NEW-4 covariance-honesty contract; GTSAM does — net structural trade-off favors GTSAM-as-primary for the AC-NEW-4-binding-constraint axis. Final ranking deferred to Jetson MVE phase per the project's D-C1-2 deferred-MVE strategy.

---

### Fact #54 — GTSAM `LevenbergMarquardtOptimizer` + `GenericProjectionFactorCal3_S2` + `Marginals.marginalCovariance` per-mode API capability verification (canonical `borglab/gtsam` library — factor-graph PnP with Levenberg-Marquardt nonlinear optimization + per-correspondence projection factors with optional sensor-body offset + native 6×6 posterior covariance recovery via `Marginals` class; **MODERN-COMPETITIVE-LEAD candidate** for the C4 row's covariance-honest output axis; on Jetson Orin Nano Super) — DOCUMENTARY PASS WITH CLEAN-BSD-3-CLAUSE-LICENSE-THROUGHOUT + DAILY-ACTIVE-MAINTENANCE (last-pushed-2026-05-08-13:00:22Z-=-TODAY) + **NATIVE-6×6-POSE-COVARIANCE-VIA-MARGINALS** (only C4 candidate to date that satisfies AC-NEW-4 covariance-honesty contract NATIVELY without D-C4-2 mitigation work) + 2D-PIXEL-INPUT-CONTRACT-VIA-GenericProjectionFactor (matches OpenCV pixel-input contract; D-C4-1 lift still required identically) + NO-NATIVE-RANSAC (canonical pattern is external-RANSAC-via-OpenCV-for-inliers → GTSAM-factor-graph-from-inliers OR in-graph-robust-noise-model OR GncOptimizer Yang 2020 Graduated Non-Convexity) + ~50-200-MB-LIBRARY-FOOTPRINT (heaviest C4 candidate to date but well within AC-4.2 budget) + ARCHITECTURAL-EXTENSION-TO-C5-VIA-iSAM2 (factor-graph paradigm scales naturally to multi-frame state estimation); opens C4 row at **3 of N candidates** (modern-competitive-lead-covariance-honest role)
- **Statement**: GTSAM (`borglab/gtsam` canonical implementation by Georgia Tech Research Corporation Borg Lab + Frank Dellaert et al., `gtsam/slam/` + `gtsam/nonlinear/` + `gtsam/linear/` modules, BSD-3-Clause license confirmed via Source #86 LICENSE.BSD direct WebFetch with three numbered redistribution conditions including non-endorsement clause) is the **MODERN-COMPETITIVE-LEAD candidate** for the C4 row's covariance-honest output axis — the canonical reference factor-graph SLAM library by Frank Dellaert et al. that emits a **direct 6×6 pose covariance NATIVELY** via `Marginals(graph, result).marginalCovariance(pose_key)` with no custom Jacobian engineering required. Per the per-Mode API Capability Verification rule, the project's pinned mode is the **(`gtsam.NonlinearFactorGraph()` + `gtsam.GenericProjectionFactorCal3_S2(measured_pt2, pixel_noise, pose_key, landmark_key, K)` per-correspondence factor for each 2D-3D correspondence + `gtsam.LevenbergMarquardtOptimizer(graph, initial).optimize()` LM optimization + `gtsam.Marginals(graph, result).marginalCovariance(pose_key)` 6×6 posterior covariance recovery) → 6-DoF camera pose (R, t) + 6×6 covariance matrix natively**. **Mode-enumeration query (1/3) — context7 INDEXED PASS at `/borglab/gtsam` with 1121 code snippets at version 4.3a1** (best context7 indexing of any C4 candidate evaluated — fresher and more comprehensive than OpenCV's `/opencv/opencv` indexing at 3168 snippets but lower benchmark score, and dramatically better than OpenGV's NOT-INDEXED status); per Per-Mode API Capability Verification rule item 1, context7 query-docs returned canonical PnP runnable example from `python/gtsam/examples/CameraResectioning.ipynb` + `gtsam/slam/doc/ProjectionFactor.ipynb` + `Marginals.marginalCovariance` documentation from `python/gtsam/examples/Pose2SLAMExample.ipynb` + `python/gtsam/examples/PlanarSLAMExample.ipynb`. **Canonical PnP example pattern** (Source #87 `CameraResectioning.ipynb`): `calibration = Cal3_S2(fx, fy, skew, cx, cy)` → `graph = NonlinearFactorGraph()` → per-correspondence `graph.add(GenericProjectionFactorCal3_S2(measured_pt2, pixel_noise, X(1), L(i), calibration))` for each 2D-3D correspondence → `initial = Values(); initial.insert(X(1), Pose3(Rot3(...), Point3(...)))` initial pose estimate (typically from external RANSAC-PnP) → `result = LevenbergMarquardtOptimizer(graph, initial).optimize()` → `marginals = gtsam.Marginals(graph, result); pose_covariance = marginals.marginalCovariance(X(1))` 6×6 posterior covariance. **`GenericProjectionFactorCal3_S2` canonical API** (Source #87 `ProjectionFactor.ipynb`): `GenericProjectionFactorCal3_S2(measured_pt2: Point2, pixel_noise: gtsam.noiseModel, pose_key: Symbol, landmark_key: Symbol, calibration: Cal3_S2, body_P_sensor: Pose3=identity)` — per-correspondence projection factor with optional sensor-body offset for IMU-camera extrinsic; uses 2D pixel measurement input directly (matches OpenCV's pixel-input contract); accepts `body_P_sensor` for IMU-camera extrinsic if needed; canonical pixel noise model is `gtsam.noiseModel.Isotropic.Sigma(2, 1.0)` for 1-pixel std-dev. **Calibration classes** (Source #87): `Cal3_S2(fx, fy, skew, cx, cy)` for standard pinhole; also `Cal3DS2` for 4-parameter radial-tangential distortion; `Cal3Bundler` for 3-parameter radial distortion; project's pinned ADTi 20MP nav camera maps directly to `Cal3DS2` with calibration coefficients from project's calibration file. **`LevenbergMarquardtOptimizer` canonical signature** (Source #87): `LevenbergMarquardtOptimizer(graph, initial: Values, params: LevenbergMarquardtParams=LevenbergMarquardtParams()).optimize() -> Values`; canonical default params include `maxIterations=100`, `relativeErrorTol=1e-5`, `absoluteErrorTol=1e-5`, `errorTol=0.0`. **`Marginals` posterior covariance canonical API** (Source #87 `Pose2SLAMExample.ipynb` + `PlanarSLAMExample.ipynb`): `marginals = gtsam.Marginals(graph, result); pose_covariance = marginals.marginalCovariance(pose_key)` returns 6×6 posterior covariance for a `Pose3` variable (3×3 rotation block + 3×3 translation block + 3×3 cross-correlation blocks) — **CRITICAL POSITIVE FINDING**: this is the **direct AC-NEW-4 covariance-honesty contract satisfaction pathway** that no other C4 candidate evaluated to date provides natively. **Pinned-mode runnable example query (2/3) — context7 query-docs PASS**: complete runnable Python example from `CameraResectioning.ipynb` + `ProjectionFactor.ipynb` + `Pose2SLAMExample.ipynb` provides canonical reference for the project's pinned mode without WebFetch fallback (cross-validated against canonical Doxygen portal `borglab.github.io/gtsam/`). **Disqualifier-probe query (3/3) — TWO FINDINGS (1 negative-but-mitigable structural + 1 caveat)**: (i) **CRITICAL contract finding — GTSAM has NO native RANSAC algorithm** — canonical pattern is to run RANSAC externally (e.g., via OpenCV `cv::solvePnPRansac` for the inlier mask → use the inliers + initial pose estimate to seed the GTSAM factor graph) THEN build the factor graph from inliers only with `GenericProjectionFactorCal3_S2`; alternative is in-graph robust outlier rejection via `gtsam.noiseModel.Robust.Create(gtsam.noiseModel.mEstimator.Huber.Create(1.0), gaussian_noise)` (Huber/Tukey/Cauchy M-estimator robust kernels) OR `GncOptimizer` (Graduated Non-Convexity, Yang et al. RAL 2020) for globally-convergent RANSAC alternative; this couples C4 = GTSAM-as-primary with EITHER C4-mandatory-baseline = OpenCV-RANSAC-as-inlier-detector (OpenCV solvePnPRansac → inlier mask → GTSAM factor graph from inliers + LM + Marginals) OR full-GTSAM-with-robust-noise-model (no external RANSAC, all M-estimator-based outlier rejection in-graph) OR full-GTSAM-with-GncOptimizer (Graduated Non-Convexity globally-convergent alternative); recommendation for project's mandatory-simple-baseline + modern-competitive-lead architecture: **OpenCV solvePnPRansac → inlier mask → GTSAM factor graph from inliers + LM + Marginals** (this is exactly D-C4-2 = (b) wrap-OpenCV-result-in-GTSAM-Marginals); (ii) **Memory + binary-size CAVEAT — GTSAM library footprint is ~50-200 MB at runtime depending on factor-graph size and bundled-dependency build configuration** (vs OpenCV's ~10-50 MB calib3d module); on Jetson Orin Nano Super 8 GB shared memory budget, GTSAM is the **heaviest C4 candidate evaluated to date** but still well within AC-4.2 budget when co-resident with C1/C2/C3/C5/C6 — extrapolated co-resident memory pressure ~1-3% of AC-4.2 budget at typical project graph size (per-frame K=10 image pairs × ~100 inliers per pair = ~1000 factors per graph; iSAM2 incremental update keeps memory footprint bounded if extending to C5 multi-frame fusion); (iii) **No JetPack 6 canonical distribution** — GTSAM requires custom build on JetPack 6 ARM Cortex-A78AE (vs OpenCV's canonical JetPack 6 distribution); but GTSAM's `cmake` build system + Eigen-3.3.7 bundled dependency + Boost dependency are well-documented for ARM cross-compilation; canonical Borg Lab distribution does NOT ship pre-built ARM binaries, but Plan-phase ~1-2 days of engineering should suffice for cross-compilation. **Pinned-mode sentence**: "We will catalog **GTSAM `LevenbergMarquardtOptimizer` + `GenericProjectionFactorCal3_S2` + `Marginals.marginalCovariance`** with **canonical default LM params (`maxIterations=100, relativeErrorTol=1e-5, absoluteErrorTol=1e-5, errorTol=0.0`) + 1-pixel-std-dev `noiseModel.Isotropic.Sigma(2, 1.0)` + `Cal3DS2` 4-parameter radial-tangential distortion calibration + BSD-3-Clause license throughout** as the **MODERN-COMPETITIVE-LEAD candidate for the C4 row's covariance-honest output axis** per engine Component Option Breadth rule. Inputs `{up to 1024 inlier 3D-2D correspondences from C3 + OpenCV solvePnPRansac inlier mask (project's pinned external-RANSAC-pattern; or alternatively in-graph M-estimator robust noise model or GncOptimizer for full-GTSAM path) + 3D world points lifted from C3's satellite-tile-side pixels via D-C4-1's 2D→3D lift (project default = 4-DoF flat-earth + IMU+barometer altitude + VIO/IMU attitude prior → planar-scene homography → 4-DoF pose extraction; ALOS-30m-DSM secondary mitigation) + project's pinned ADTi 20MP nav camera Cal3DS2 calibration + initial pose estimate from external-RANSAC seed}`; expected outputs `{6-DoF camera pose (R, t) from `result.atPose3(pose_key)` + 6×6 posterior covariance NATIVELY from `marginals.marginalCovariance(pose_key)` + per-correspondence inlier mask passed through from external RANSAC + reprojection error from `GenericProjectionFactorCal3_S2.error(values)` + LM iteration count from `optimizer.iterations()` + source label `satellite_anchor` for C5 fused estimate per Fact #20 + #21 + AC-NEW-4 covariance honesty}`; runtime `Jetson Orin Nano Super (8 GB shared, JetPack 6, ROS 2 Humble) — custom build required` (no canonical JetPack 6 distribution; ~1-2 days cross-compilation engineering). **MODERN-COMPETITIVE-LEAD-COVARIANCE-HONEST role per engine Component Option Breadth rule** — GTSAM's structural distinction from OpenCV + OpenGV is **native 6×6 pose covariance via `Marginals` posterior** at the cost of (i) no native RANSAC (couples with OpenCV-RANSAC-as-inlier-detector) + (ii) ~50-200 MB library footprint + (iii) custom JetPack 6 cross-compilation — net structural trade-off **strongly favors GTSAM for the AC-NEW-4-binding-constraint axis** (covariance honesty contract) since GTSAM is the only C4 candidate to date that satisfies it natively without D-C4-2 mitigation work. **Architectural extension to C5**: GTSAM's factor-graph paradigm extends naturally from C4 single-frame PnP to C5 multi-frame state estimation via `iSAM2` + `BetweenFactor<Pose3>` (between-pose temporal odometry factors) + `PriorFactorPose3` (prior on initial pose) + per-frame `GenericProjectionFactorCal3_S2` (per-correspondence projection factors at each frame) — would simplify C5 implementation if both C4 and C5 are GTSAM-based, providing a **forward-looking architectural integration advantage** that no other C4 candidate provides.
- **Source**: Source #86 (canonical `borglab/gtsam` GitHub repo + LICENSE wrapper + LICENSE.BSD — BSD-3-Clause throughout (`Copyright (c) 2010, Georgia Tech Research Corporation` with three numbered redistribution conditions including non-endorsement clause); 3424 stars + 927 forks + 60 subscribers + 140 open issues + last pushed 2026-05-08T13:00:22Z = TODAY at access time = daily-active maintenance fresher than OpenCV by 6 hours; default branch `develop`; topics include `estimation, perception, robotics, sensorfusion`; bundled third-party libraries [CCOLAMD 2.9.6 BSD-3 + Ceres auto-diff/jet code BSD-3-modified + Eigen 3.3.7 MPL2 file-level + METIS 5.1.0 Apache-2.0 + Spectra v0.9.0 MPL2] all clean for project's dual-use deployment), Source #87 (canonical GTSAM Python documentation via context7 at `/borglab/gtsam` version 4.3a1 with 1121 code snippets — canonical PnP example `python/gtsam/examples/CameraResectioning.ipynb` + `gtsam/slam/doc/ProjectionFactor.ipynb` + `python/gtsam/examples/Pose2SLAMExample.ipynb` + `python/gtsam/examples/PlanarSLAMExample.ipynb` + `gtsam/inference/doc/FactorGraph.ipynb`); cross-cite to Fact #20 + #21 closures from C2 row (canonical PnP+RANSAC+LM reference pipeline shape feeds AC-NEW-4 covariance-honesty contract — directly satisfied by GTSAM `Marginals` posterior); cross-cite to Fact #52 (canonical OpenCV solvePnPRansac mandatory simple-baseline reference for the external-RANSAC-as-inlier-detector pattern that pairs with GTSAM-as-primary); cross-cite to Fact #53 (OpenGV modern-competitive-lead-richer-minimal-solver alternative for direct comparison on D-C4-2 covariance-recovery-strategy); forward-cite to C5 row (factor-graph paradigm extension to multi-frame state estimation via iSAM2)
- **Phase**: Phase 2
- **Target Audience**: System architects + C4 implementer + Step-7.5 reviewer + license-posture decision-maker (D-C1-1 — clean BSD-3-Clause throughout) + Plan-phase architect (modern-competitive-lead-covariance-honest role documentation for engine Component Option Breadth rule compliance + D-C4-2 NATIVELY SATISFIED via Marginals posterior + D-C5-N forward-looking carry-forward for state estimator factor-graph extension via iSAM2)
- **Confidence**: ✅ for mode-enumeration (`GenericProjectionFactorCal3_S2` + `LevenbergMarquardtOptimizer` + `Marginals.marginalCovariance` + `NonlinearFactorGraph` + `Cal3_S2` / `Cal3DS2` calibration classes + `Pose3` 6-DoF pose + `noiseModel.Diagonal.Sigmas` / `noiseModel.Isotropic.Sigma` + `noiseModel.Robust.Create` + `mEstimator.Huber.Create` documented in canonical Source #87 via context7 query-docs at version 4.3a1), runnable-example (canonical Python example from `CameraResectioning.ipynb` documented via Source #87 with explicit recommended pattern), license (**BSD-3-Clause** confirmed via Source #86 LICENSE.BSD direct WebFetch — three numbered redistribution conditions including non-endorsement clause; bundled deps clean [BSD-3 + Apache-2.0 + MPL2 file-level — all dual-use compatible]); ✅ for **NATIVE 6×6 POSE COVARIANCE via `Marginals.marginalCovariance`** finding (Source #87 multiple snippets from `Pose2SLAMExample.ipynb` + `PlanarSLAMExample.ipynb` documenting `marginals = gtsam.Marginals(graph, result); marginals.marginalCovariance(key)` API surface — **the only C4 candidate evaluated to date that satisfies AC-NEW-4 covariance-honesty contract NATIVELY without D-C4-2 mitigation work**); ✅ for **2D pixel input contract via `GenericProjectionFactorCal3_S2`** finding (Source #87 `ProjectionFactor.ipynb` explicit `measured_pt2: Point2` 2D pixel measurement parameter — matches OpenCV's pixel-input contract; D-C4-1 lift still required identically); ✅ for **NO native RANSAC** finding (Source #87 documents `LevenbergMarquardtOptimizer` + `noiseModel.Robust.Create` + `mEstimator.Huber.Create` + `GncOptimizer` but no native RANSAC class — canonical pattern is external-RANSAC-via-OpenCV); ✅ for **canonical BSD-3-Clause license throughout** (Source #86 LICENSE.BSD direct WebFetch + bundled-dependency licensing documented in LICENSE wrapper file); ✅ for **daily-active maintenance** (Source #86 last pushed 2026-05-08T13:00:22Z = TODAY at access time); ✅ for **architectural extension to C5 via iSAM2** (Source #87 cross-citation to `BetweenFactor<Pose3>` + `PriorFactorPose3` + `iSAM2` documented in canonical GTSAM examples); ⚠️ for **Jetson Orin Nano Super deployment latency / memory** (no documentary measurement; extrapolation from x86_64 RTX-class CPU canonical GTSAM PnP + LM optimization at ~1000 factors per graph + 100 LM iterations ~10-30 ms per call CPU-only on Intel i7-class; Jetson Orin Nano Super extrapolation ~30-90 ms per call CPU-only; at K=10 pairs/frame extrapolated 300-900 ms total = **TIGHT AC-4.1 satisfaction** with substantial margin pressure — Plan-phase Jetson MVE phase verification required); ⚠️ for **library binary footprint** (~50-200 MB at runtime on Jetson Orin Nano Super depending on bundled-dependency build configuration; vs OpenCV's ~10-50 MB; well within AC-4.2 budget but heaviest C4 candidate to date); ⚠️ for **JetPack 6 cross-compilation engineering** (~1-2 days; not blocking but adds setup cost vs OpenCV's canonical JetPack 6 distribution); ❌ for **canonical-checkpoint aerial-domain fitness** — N/A for GTSAM since it is a classical factor-graph library, not a learned method (no canonical-weights aerial-domain caveat applies)
- **Related Dimension**: SQ3+SQ4 / C4 modern-competitive-lead-covariance-honest role (engine Component Option Breadth rule role — directly addresses AC-NEW-4 covariance-honesty contract; analogous structural role to DISK+LightGlue's RECOMMENDED-PRIMARY-MITIGATION role in C3 row but for C4) — per-mode API capability verification gate
- **Fit Impact**: **DOCUMENTARY PASS for the per-mode API capability verification gate at the modern-competitive-lead-covariance-honest role** — `LevenbergMarquardtOptimizer` + `GenericProjectionFactorCal3_S2` + `Marginals.marginalCovariance` has documented runnable per-mode examples with the project's pinned configuration (canonical GTSAM Python examples + canonical Doxygen portal + 1121 context7 code snippets at version 4.3a1). **Three CONVERGING POSITIVE structural advantages**: (i) **NATIVE 6×6 POSE COVARIANCE via `Marginals.marginalCovariance`** — **the only C4 candidate evaluated to date that satisfies AC-NEW-4 covariance-honesty contract NATIVELY** without D-C4-2 mitigation work; **directly addresses the AC-NEW-4-binding-constraint axis** that drives the C4 row's primary architectural concern; (ii) **CLEAN BSD-3-Clause LICENSE THROUGHOUT** — canonical `borglab/gtsam` repo per Source #86 LICENSE.BSD direct WebFetch + bundled-dependency licensing all clean for project's dual-use deployment; eligible on every D-C1-1 license-posture choice with the cleanest license-compliance story tied with cvg/LightGlue + DISK + XFeat + OpenCV; (iii) **DAILY-ACTIVE MAINTENANCE + WELL-INDEXED context7 DOCUMENTATION** — last pushed 2026-05-08 (TODAY at access time, fresher than OpenCV by 6 hours) + 1121 context7 code snippets at version 4.3a1 = best context7 indexing of any C4 candidate evaluated; daily-active maintenance contradicts OpenGV's ~3-year staleness. **One ADDITIONAL POSITIVE structural advantage**: (iv) **ARCHITECTURAL EXTENSION TO C5 VIA iSAM2** — factor-graph paradigm scales naturally from C4 single-frame PnP to C5 multi-frame state estimation via iSAM2 + `BetweenFactor<Pose3>` + `PriorFactorPose3` + per-frame `GenericProjectionFactorCal3_S2`; would simplify C5 implementation if both C4 and C5 are GTSAM-based, providing a **forward-looking architectural integration advantage** that no other C4 candidate provides. **One NEGATIVE-BUT-MITIGABLE structural finding**: (v) **NO NATIVE RANSAC** — canonical pattern is external-RANSAC-via-OpenCV-for-inliers (couples C4 = GTSAM-as-primary with C4-baseline = OpenCV-RANSAC-as-inlier-detector); alternative is in-graph M-estimator robust noise model OR `GncOptimizer` (Graduated Non-Convexity, Yang et al. RAL 2020) — both well-documented in canonical GTSAM examples. **Three CAVEATS**: (vi) **~50-200 MB LIBRARY FOOTPRINT** — heaviest C4 candidate to date but well within AC-4.2 8 GB shared memory budget at typical project graph size (~1-3% co-resident memory pressure); (vii) **NO JetPack 6 CANONICAL DISTRIBUTION** — requires custom cross-compilation (~1-2 days engineering); not blocking but adds setup cost vs OpenCV's canonical JetPack 6 distribution; (viii) **TIGHT AC-4.1 LATENCY MARGIN** — Jetson Orin Nano Super extrapolated ~30-90 ms per call CPU-only at K=10 pairs/frame extrapolated 300-900 ms total = vs 400 ms AC-4.1 budget = **tight margin requiring Plan-phase Jetson MVE phase verification**; mitigation strategies include (a) reduce K from 10 to 3-5 (couples with D-C3-3 K-pairs-per-frame budget), (b) GTSAM-as-secondary-only for satellite-anchor frames (run OpenCV solvePnPRansac for fast inlier detection on every frame, run GTSAM factor-graph + Marginals only when AC-NEW-4 covariance honesty is the binding requirement), (c) batch GTSAM optimization across multiple frames via iSAM2 incremental update (amortizes per-frame cost). **NO NEW Plan-phase decisions raised by GTSAM closure** (D-C4-1 carry-forward applies identically + D-C4-2 NATIVELY SATISFIED + D-C4-3 + D-C4-4 do NOT apply to GTSAM since BSD-3-Clause is documented + maintenance is daily-active). **D-C4-1 carry-forward IDENTICAL** — `GenericProjectionFactorCal3_S2` 2D pixel input contract still requires 2D→3D lift on satellite-tile-side from pixel correspondences (4-DoF flat-earth lift recommendation per locked-in research-time defaults). **D-C4-2 NATIVELY SATISFIED via `Marginals.marginalCovariance`** — GTSAM is the canonical Plan-phase pathway for D-C4-2 = (b) wrap-OpenCV-result-in-GTSAM-Marginals (recommended for OpenCV-as-primary + GTSAM-as-covariance-recovery hybrid path) OR full-GTSAM-as-primary (if AC-NEW-4 covariance honesty is the dominant axis). **C4 mandatory pre-screen status**: GTSAM closes the C4 modern-competitive-lead-covariance-honest role at **3 of N candidates**. License: **BSD-3-Clause** for canonical `borglab/gtsam` repo (Source #86 LICENSE.BSD direct WebFetch verified) — clean BSD/permissive license track on the C4 modern-competitive-lead-covariance-honest axis; under D-C1-1 = (a) GPL-3.0 track, (b) BSD/permissive lock, or (c) keep-both-tracks-open, GTSAM is **eligible on every license-posture choice with the simplest license-compliance story** tied with cvg/LightGlue + DISK + XFeat + OpenCV. **Position vs OpenCV (Fact #52 mandatory simple-baseline)**: GTSAM provides native covariance honesty at the cost of (i) no native RANSAC (canonical pattern is external-RANSAC-via-OpenCV) + (ii) ~50-200 MB library footprint + (iii) tight AC-4.1 latency margin — **net structural trade-off STRONGLY FAVORS GTSAM for the AC-NEW-4-binding-constraint axis** (covariance honesty) but FAVORS OpenCV-as-primary for the AC-4.1-binding-constraint axis (latency). **Position vs OpenGV (Fact #53 modern-competitive-lead-richer-minimal-solver)**: GTSAM provides covariance honesty natively while OpenGV does NOT (D-C4-2 still applies to OpenGV); GTSAM is daily-active while OpenGV is ~3-year stale; GTSAM has clean BSD-3-Clause while OpenGV has NOASSERTION SPDX-detector contingency — net structural trade-off **STRONGLY FAVORS GTSAM** vs OpenGV at the modern-competitive-lead axis. **Recommended C4 architecture for the project**: **OpenCV solvePnPRansac as mandatory simple-baseline reference floor + per-frame inlier detection + initial pose estimate + GTSAM factor-graph posterior recovery for AC-NEW-4 covariance-honest output** (couples Fact #52 + Fact #54 closures via D-C4-2 = (b)). Final ranking deferred to Jetson MVE phase per the project's D-C1-2 deferred-MVE strategy.

---
