Add manual ground/top-plane tilt correction - #429
Open
RufanMelfor wants to merge 1 commit into
Open
Conversation
|
All contributors have signed the CLA. Thank you! |
…op-plane tilt correction Reimplemented from scratch against the current architecture (post "stitch unification" / "executor spine" refactors), like the seam-positioning and color-matching ports before it - neither ground_tilt nor top_tilt exist anywhere in the current codebase. Adds a small additional tilt near the bottom (ground) or top of frame, where the flat two-plane approximation's parallax error is largest: `tan(theta)` of extra tilt, applied only within a band near the respective edge (identity elsewhere), via the tangent-addition identity `warp(t, c, k) = (k*c + t) / (1 - c*t/k)` where `t` is plane-space y and `k = fy / (2*width)` converts between "plane width = 1.0" units and the tangent-addition math's own scale. New Topology fields: ground_tilt_x/z, top_tilt_x/z (the tilt scalars, manual-only - no automatic fitting path exists), ground_tilt_band_width/ top_tilt_band_width (the ramp's adjustable full-strength threshold; the ramp always starts at a fixed GROUND_TILT_BAND_START = 0.08). All six default to a no-op (0.0 tilt / 0.16 band width), so existing calibrations render unchanged. Unlike color-matching, this got a full CPU mirror rather than being made GPU-only/opt-in: the warp is pure closed-form arithmetic with no state, so it was tractable to add to stitch::geometry::PlaneMap:: sample_uv (operating on the same raw pre-extended-UV-remap uv.y as the GPU shader, in the same order, so the two backends agree by construction rather than needing an excluded-from-testing escape hatch). Verified with a new end-to-end agreement test that actually ran on real GPU hardware with non-zero tilt on both planes (cpu_and_gpu_backends_agree_with_ground_top_tilt), plus focused unit tests on the warp math itself (identity below the band threshold, real shift beyond it, top-tilt's mirrored one-sidedness). GPU-side wiring turned out simpler than the seam-positioning/ color-matching precedent needed: encode_stitch_pass already receives the full Calibration, so the two new vec4<f32> uniform fields (ground_tilt, top_tilt) are populated directly from calibration.topology inside it - no new params threaded through render_to_target/render_to_view or StitchPipeline's public render methods. Only a genuine live-editable-without-scene-rebuild setter chain was needed: StitchPipeline::set_ground_tilt_x/z/set_top_tilt_x/z/ set_*_band_width (mirrors set_blend_width exactly) -> Executor -> StitchCore -> reco-gui's preview bridge. reco-gui: 6 new LabeledSliders in the Calibration panel (tilt values -0.3..0.3 at 5 decimals, band widths 0.09..0.4 at 2 decimals), mirroring the existing Intersect/x_ty sliders' wiring exactly, including all 3 calibration-sync sites (reset, file-load, and post-auto-calibrate reload). reco-calibrate's optimizer.rs and reco-autocam's panner test fixtures were updated only for the new required Topology fields (defaulted to no-op) - the automatic-fitting path for these tilt values doesn't exist and is out of scope here, matching the fork's own "manual-only" design. Verified: cargo fmt --check clean; cargo test -p reco-core (156 passed, including the new GPU agreement test and 4 new geometry unit tests; only the 2 pre-existing CUDA hardware-gap failures, unrelated), -p reco-gui (6/6), -p reco-calibrate (48/48, including the optimizer fitting tests - confirms the required-field addition didn't disturb existing fitting behavior), -p reco-autocam (65/65); full workspace check clean (reco-obs excluded, pre-existing unrelated OBS-SDK build gap); clippy clean for this change's own code (verified by overlaying the separate fix/d3d11-stage-frame-unsafe branch's fix to isolate from upstream's 4 pre-existing, unrelated clippy failures). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
RufanMelfor
force-pushed
the
feat/ground-top-tilt
branch
from
July 16, 2026 10:37
7d920dd to
0ddb456
Compare
Contributor
Author
|
I have read the CLA Document and I hereby sign the CLA |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reimplemented from scratch against the current architecture, like the
seam-positioning and color-matching PRs before it — neither
ground_tiltnor
top_tiltexist anywhere in the current codebase.Adds a small additional tilt near the bottom (ground) or top of frame,
where the flat two-plane approximation's parallax error is largest:
tan(theta)of extra tilt, applied only within an adjustable band nearthe respective edge (identity everywhere else), via the tangent-addition
identity
warp(t, c, k) = (k*c + t) / (1 - c*t/k)wheretis plane-spacey and
k = fy / (2*width)converts between "plane width = 1.0" units andthe tangent-addition math's own scale.
New
Topologyfields:ground_tilt_x/z,top_tilt_x/z(the tiltscalars — manual-only, no automatic fitting path exists for either), and
ground_tilt_band_width/top_tilt_band_width(the ramp's adjustablefull-strength threshold; the ramp always starts at a fixed
GROUND_TILT_BAND_START = 0.08). All six default to a no-op (0.0tilt /0.16band width), so existing calibrations render unchanged.Unlike color-matching, this got a full CPU mirror rather than being
made GPU-only/opt-in: the warp is pure closed-form arithmetic with no
state, so it was tractable to add to
stitch::geometry::PlaneMap:: sample_uv(operating on the same raw, pre-extended-UV-remapuv.yas theGPU shader, in the same order, so the two backends agree by construction).
Verified with a new end-to-end agreement test that actually ran on real
GPU hardware with non-zero tilt on both planes
(
cpu_and_gpu_backends_agree_with_ground_top_tilt), plus focused unittests on the warp math itself (identity below the band threshold, a real
shift beyond it, and the top-tilt's mirrored one-sidedness).
GPU-side wiring turned out simpler than the seam-positioning/
color-matching precedent needed:
encode_stitch_passalready receives thefull
Calibration, so the two newvec4<f32>uniform fields(
ground_tilt,top_tilt) are populated directly fromcalibration.topologyinside it — no new params threaded throughrender_to_target/render_to_vieworStitchPipeline's public rendermethods. Only a genuine live-editable-without-scene-rebuild setter chain
was needed:
StitchPipeline::set_ground_tilt_x/z/set_top_tilt_x/z/set_*_band_width(mirrorsset_blend_widthexactly) →Executor→StitchCore→ reco-gui's preview bridge.reco-gui: 6 new
LabeledSliders in the Calibration panel (tilt values-0.3..0.3at 5 decimals, band widths0.09..0.4at 2 decimals),mirroring the existing Intersect/x_ty sliders' wiring exactly, including
all 3 calibration-sync sites (reset, file-load, and post-auto-calibrate
reload).
reco-calibrate's optimizer andreco-autocam's panner test fixtureswere updated only for the new required
Topologyfields (defaulted tono-op) — the automatic-fitting path for these tilt values doesn't exist
and is out of scope here.
Verified:
fmt --checkclean;cargo test -p reco-core(156 passed,including the new GPU agreement test and 4 new geometry unit tests; only
the 2 pre-existing CUDA hardware-gap failures, unrelated),
-p reco-gui(65/65),
-p reco-calibrate(48/48, including the optimizer fitting tests— confirms the required-field addition didn't disturb existing fitting
behavior),
-p reco-autocam(6/6); full workspace build clean.