feat: stitch frames captured as RGB-scan triplets - #723
Merged
Conversation
Stitching refused any RGB-scan frame. The reason was structural: StitchConfig carried one path per part, so the decode loop merged every part against the primary's green/blue exposures. StitchConfig now carries stitch_triplets — the (green, blue) pair per part, indexed like stitch_transforms/stitch_sizes with the primary at 0 — plus stitch_align. Each part is decoded against its own rgbscan config, which makes the existing per-part tail (triplet merge, flat-field, sensor-unmix skip) correct without further change. An empty tuple leaves saved composites alone. The triplet paths are folded into stitch_token, carried on the composite asset dict, persisted with the session and restored on launch; unstitch hands the parts back as triplet assets rather than loose exposures. Also fixes the RGB Scan / Half Frame toggles, which decomposed only green_path/blue_path and so dropped a composite's other parts from the session on re-discovery. Both now share one _component_paths helper.
Closed
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.
What
Panorama stitching now works on RGB-scan frames, so a negative captured in overlapping pieces and with narrowband R/G/B illumination assembles into one frame. Each part merges its own triplet first, then the merged parts register and blend as they do today.
No new UI: turn on RGB Scan, select the pieces, right-click → Stitch selected frames.
Why it was blocked
request_stitch_selectedrefused outright:The refusal was structural, not arbitrary.
StitchConfigcarried a single path per part, so_load_source_f32decoded every part against the sameparams.rgbscan— each part would have been merged with the primary's green/blue files.How
StitchConfiggains the per-part triplet, indexed like the existingstitch_transforms/stitch_sizes(primary at 0, unlikestitch_paths):Each part is then decoded against its own
rgbscanconfig (_part_params). That one change makes the existing per-part decode tail correct for free — including_decode_oriented_f32's "skipapply_sensor_correctionfor triplets" branch, which has to be decided per part. An empty tuple means no part is a triplet, so every already-saved composite behaves exactly as before.Threaded through the places a composite's identity and lifetime live:
stitch_token(or the engine cache serves stale renders), the preview loader,PreviewLoadTask, the composite asset dict, session persist/restore, and unstitch — which now hands the parts back as triplet assets instead of nine loose exposures.Mixed selections (one triplet part, one plain part) fall out working; no guard needed.
StitchWorkeris untouched —params_by_pathalready comes from_batch_params_for, which resolves each part's own triplet, so registration was already decoding merged parts.Drive-by fix
set_rgb_scan_mode/set_half_frame_modedecomposed onlygreen_path/blue_pathwhen re-running discovery, so toggling either mode dropped a composite's other parts out of the session. Both now go through one_component_pathshelper.Measurements
From the sample capture (Fuji X-T5, X-Trans, two overlapping parts × three exposures):
assemble_rgbis plenty, no per-part homography needed.Testing
make allgreen — 2996 passed, 5 skipped, lint +tyclean.12 new tests in
tests/test_stitch.py, including an end-to-end run on real files (skipped when absent) that registers and composites the actual capture and asserts the three channel means diverge — something a red-only merge cannot do.Checked by hand on the same files: the full-res export path produces an 8101×7776 composite in 21 s, and with matching decode settings its channel means track the preview to three decimals (0.2216 / 0.2485 / 0.2248 vs 0.2213 / 0.2481 / 0.2249).
Docs
USER_GUIDE.mdhad no stitch section at all — added one covering Stitch selected frames / Unstitch plus the triplet workflow.PIPELINE.mdgains a composite-assembly bullet under source corrections, noting that flat-field and unmix run per part and never across the canvas.