Add spherical_reprojected mode to panorama_sfm example - #4552
Add spherical_reprojected mode to panorama_sfm example#4552shuta-ochiai wants to merge 8 commits into
Conversation
8623562 to
eb056c9
Compare
|
A note on feature/matcher support of the reprojection design (the example itself currently wires up the default SIFT + nearest-neighbor matching only):
🤖 Generated with Claude Code |
Extract features on the perspective renderings (as in the perspective modes, so the feature quality does not suffer from the equirectangular distortion, especially towards the poles), reproject the keypoints onto the panoramas, and then match and reconstruct directly on the panoramas with the native EQUIRECTANGULAR camera model (as in the spherical mode, with one image per panorama instead of a rig). This gives feature quality comparable to the perspective modes at a matching and mapping cost comparable to the spherical mode. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
eb056c9 to
60344d5
Compare
|
Thank you for your contribution! I have a few concerns, which to me are for now sufficiently critical to not merge this PR.
Could you please provide evidence of this? The speed of matching and BA scales mostly with the number of features, which is unchanged when projecting features from perspective to spherical. BA already considers all observations in the rig at once.
Could you please quantify this? I highly doubt that LightGlue performs satisfactorily with such inputs. |
…jected-ab # Conflicts: # python/examples/panorama_sfm.py
Resolves the merge conflict between PR colmap#4552 (adds spherical_reprojected mode to the monolithic panorama_sfm.py script) and main's later refactor into pycolmap/panorama.py + thin examples/panorama_sfm.py wrapper. Also wires spherical_reprojected into the TartanAir-v2 benchmark harness (DatasetTartanAirSphericalReprojected) for A/B measurement against perspective_overlapping and spherical.
Resolves the merge conflict between PR colmap#4552 (adds spherical_reprojected mode to the monolithic panorama_sfm.py script) and main's later refactor into pycolmap/panorama.py + thin examples/panorama_sfm.py wrapper. Also wires spherical_reprojected into the TartanAir-v2 benchmark harness (DatasetTartanAirSphericalReprojected) for A/B measurement against perspective_overlapping and spherical.
3b3dfb4 to
9f79e54
Compare
Resolves the merge conflict between PR colmap#4552 (adds spherical_reprojected mode to the monolithic panorama_sfm.py script) and main's later refactor into pycolmap/panorama.py + thin examples/panorama_sfm.py wrapper. Also wires spherical_reprojected into the TartanAir-v2 benchmark harness (DatasetTartanAirSphericalReprojected) for A/B measurement against perspective_overlapping and spherical.
multiprocessing.Pool's default fork start method breaks the OpenGL/CUDA context that SiftGPU's extractor creates in worker processes, crashing scene evaluation. Force spawn instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
PanoramaReconstructionOptions hardcoded SIFT extraction/matching, so evaluate.py's --feature aliked raised immediately for panorama datasets even though nothing about the reconstruction pipeline actually requires SIFT. Add extractor_type/matcher_type options and wire them through the extraction and matching call sites, and map --feature aliked to ALIKED_N16ROT + ALIKED_LIGHTGLUE in the benchmark harness. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
9f79e54 to
6c08768
Compare
|
Thanks for the review, @sarlinpe — I re-ran a broader benchmark (8 scenes, SIFT+NN and ALIKED+LightGlue, reprojection error, mean track length, GT trajectory accuracy (mAA), and 3DGS novel-view-synthesis quality) to get real numbers on both points instead of relying on intuition. Gaussian count is pinned at 150k across all 3DGS runs — otherwise MCMC densification confounds quality differences with point-count differences. Quick apology up front: my earlier read was based only on SIFT+NN's 3DGS quality on one dataset, which happened to favor native — too hasty a call on limited data. Bottom line: ALIKED+LightGlue's 3DGS quality does favor DatasetTartanAir V2 (CMU AirLab, CC-BY-4.0), specifically the panorama SfM benchmark subset already packaged and released by this repo (
1. Matching costConfirmed on 1 scene ( 2. SIFT+NNReprojection error / track length, 8 scenes (click to expand)
Processing time (GPU seconds), 8 scenes (click to expand)
GT trajectory accuracy (mAA %, IMC-style pose error = max(rotation geodesic error, translation direction error), GT trajectory mAA %, 8 scenes (click to expand)
3DGS quality, 8 scenes (click to expand)
Native is ahead on reprojection error in all 8 scenes and slightly ahead on average 3DGS PSNR/SSIM, but GT trajectory mAA is a near-exact 4/8 split, and within individual scenes different metrics (PSNR vs SSIM/LPIPS) sometimes disagree on which mode is better (e.g. AbandonedCable-hard-P003: PSNR favors native, SSIM/LPIPS favor reprojected). I'd call this "no meaningful quality regression" rather than "reprojected is clearly as good," which is a weaker claim than I originally suggested. 3. ALIKED+LightGlueReprojection error / track length, 8 scenes (click to expand)
Processing time (GPU seconds), 8 scenes (click to expand)
GT trajectory accuracy (mAA %, see definition above): GT trajectory mAA %, 8 scenes (click to expand)
(50/50 images registered, 1 component, all 8 scenes) 3DGS quality, 8 scenes (click to expand)
(bold = better; Reprojected wins clearly at low rotation thresholds (avg @0.5°: +6.4pts, @1.0°: +3.7pts), roughly ties at high thresholds. Mean track length ( Code changeI also extended Appreciate you taking the time to push on this — it made the evaluation a lot more honest than where I started. |
Summary
This adds a new mode,
spherical_reprojected, topython/examples/panorama_sfm.py, as a middle ground between the existingperspective_*andsphericalmodes. It implements the hybrid flow proposed in #4406, where @chpatrick agreed this is the right approach:convert_to_equirectangular) and inject them, together with their descriptors and GPS pose priors, into a panorama database with a single nativeEQUIRECTANGULARcamera.Compared to the flow sketched in #4406, the one difference is that matching runs on the panoramas after reprojecting the keypoints and descriptors, instead of matching on the faces and reprojecting the matches. This is simpler (no match/two-view-geometry rewriting) and lighter: each panorama pair costs a single matcher invocation and a single geometric verification, whereas matching on the faces needs up to N×N face-pair matches and verifications per panorama pair to catch correspondences that cross face boundaries (12×12 for the overlapping layout), with correspondingly more scheduling overhead and database rows. Cross-face correspondences are matched naturally, since all reprojected features of a panorama live in one image.
Implementation notes
convert_to_equirectangularvia a newPanoProcessor.pano_xy_from_cam_xyhelper; rendering + feature extraction is shared with the perspective modes via a newrender_and_extract_featureshelper.Databasebindings andapply_rig_config([], db), avoiding a throwaway feature extraction pass on the panoramas.--matcher spatialalso works in this mode.This mirrors a pipeline we run in production on long 360° video walkthroughs, where the perspective rig mode is accurate but matching/mapping-heavy and the spherical mode loses feature quality; extracting on the renderings and mapping on the panoramas gave us perspective-level feature quality at spherical-level cost.
Closes #4406.
🤖 Generated with Claude Code