Skip to content

Fetzer Factor Integration - #1115

Draft
kathirgounder wants to merge 1 commit into
borglab:masterfrom
kathirgounder:fetzer-pr-draft
Draft

Fetzer Factor Integration#1115
kathirgounder wants to merge 1 commit into
borglab:masterfrom
kathirgounder:fetzer-pr-draft

Conversation

@kathirgounder

Copy link
Copy Markdown
Collaborator

Implemented the Fetzer Auto Calibration Estimation with GTSAM so we dont need scipy

@kathirgounder
kathirgounder force-pushed the fetzer-pr-draft branch 4 times, most recently from 6d8f5b4 to 604ec98 Compare June 17, 2026 08:12
@dellaert
dellaert requested a review from Copilot June 17, 2026 10:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR integrates Fetzer-based view graph focal calibration using GTSAM (replacing the prior SciPy least-squares approach) and plumbs additional two-view geometry outputs (fundamental matrix + configuration type) through the frontend so calibration and downstream filtering can be more GLOMAP-faithful.

Changes:

  • Extend verifier outputs to optionally include a focal-independent fundamental matrix (i2Fi1) and two-view configuration type (config), and propagate these through TwoViewResult into multiview calibration.
  • Replace SciPy-based focal refinement with a GTSAM FetzerFactor graph (robust Cauchy kernel) and add view-graph inlier re-scoring against F using Sampson error.
  • Add a “chordal-only” rotation averaging fallback mode (skip Shonan SDP) and switch BA track filtering to per-measurement trimming.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/frontend/verifier/test_verifier_base.py Update tests to unpack the expanded verifier return tuple.
gtsfm/view_graph_estimator/view_graph_calibration.py Replace SciPy optimization with GTSAM FetzerFactor graph; add gating and support for plumbed F/config.
gtsfm/two_view_estimator.py Capture and store verifier-produced F/config in TwoViewResult.
gtsfm/products/two_view_result.py Add fields for i2Fi1 and config to carry calibration geometry downstream.
gtsfm/multi_view_optimizer.py Extract and use F/config; add F-based inlier re-scoring and feed Fetzer calibration inputs.
gtsfm/frontend/verifier/verifier_base.py Update verifier interface to return (…, i2Fi1, config) and adjust failure tuple.
gtsfm/frontend/verifier/poselib_verifier.py Optionally estimate focal-independent F + planar/uncalibrated config via PoseLib.
gtsfm/frontend/verifier/opencv_verifier_base.py Extend return signature and propagate F when estimated in the F-branch.
gtsfm/frontend/verifier/loransac.py Extend return signature and propagate F when estimated.
gtsfm/frontend/verifier/gric_verifier.py Extend return signature (returns None for new outputs).
gtsfm/frontend/verifier/degensac.py Extend return signature and propagate F when estimated.
gtsfm/configs/megaloc_sift_gp_single_pt.yaml Add a tuned pipeline config enabling calibration geometry estimation + Fetzer calibration + GP.
gtsfm/common/gtsfm_data.py Extend measurement-level filtering API to optionally return a survival mask.
gtsfm/bundle/bundle_adjustment.py Switch BA filtering to per-measurement trimming via filter_landmark_measurements().
gtsfm/averaging/rotation/shonan.py Add chordal_only mode (chordal init + robust LM refinement).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 75 to 77
"""Performs verification of correspondences between two images to recover the relative pose and indices of
verified correspondences.

camera_intrinsics_i1: CALIBRATION_TYPE,
camera_intrinsics_i2: CALIBRATION_TYPE,
) -> Tuple[Optional[Rot3], Optional[Unit3], np.ndarray, float]:
) -> Tuple[Optional[Rot3], Optional[Unit3], np.ndarray, float, Optional[np.ndarray], Optional[int]]:
Comment on lines 313 to 316
elif isinstance(old_K, Cal3_S2):
# Colmap loader hands back Cal3_S2 (fx, fy, skew, u0, v0). Fetzer optimizes a single
# focal (square pixels), so set fx = fy = new_focal and keep skew + principal point.
refined[cam_idx] = Cal3_S2(
Comment thread gtsfm/averaging/rotation/shonan.py
kathirgounder added a commit to kathirgounder/gtsfm that referenced this pull request Jul 7, 2026
…anar/focal-sanity gates

Ports the load-bearing elements of the SelfCalibrationFactor PR into the
view-graph calibration: robust LO-RANSAC F via PoseLib (replacing 8-point on
inliers), the H/F planar-config gate, the interior-minimum focal-sanity gate,
and edge filtering scored at applied focals. Solver uses
gtsam.SelfCalibrationFactor when the (custom) build provides it and falls back
to the existing sparse scipy Cauchy solve otherwise.

Gold-graded on ToL (592 GT cams, exact per-image scales):
  gates ON  4.31% median focal err, bias -2.64%
  gates OFF 14.32% median, bias -13.50%  (56% of edges are Fetzer-degenerate)
  gate counts: 8324 kept / 2598 planar / 7949 focal-sanity of 18871.
use_robust_gates=True by default; calibration_source=fetzer users (e.g. IMC
phototourism, stripped EXIF) get the gated recipe automatically.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dellaert

Copy link
Copy Markdown
Member

@kathirgounder want to revise and merge now that it's in GTSAM?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants