feat(lif)!: auto-stitch is now a cascade default (closes #41)#45
Merged
Conversation
…o-lif) BREAKING: lif_mosaic="auto-stitch" (still the default) no longer means "use bioio-lif's 1-pixel-overlap M-scan-order stitcher". It now runs a per-scene cascade that picks the best available stitcher from the tile metadata surface: 1. stage-stitch — per-tile PosX/PosY + scene physical pixel size (X and Y) 2. grid-stitch — complete rectangular FieldX/FieldY grid 3. bioio-lif — no <Tile> layout (final fallback) Under layout="plate" the cascade skips stage-stitch (not wired to the plate writer today) and lands on grid-stitch or bioio-lif per FOV. Validated against a real Leica LIF (Julia's astrocytes acquisition, 48 scenes, 3x3 mosaics, 10% declared overlap). The cascade lands on stage-stitch for every scene; visual comparison against the acquisition software rendering showed stage-stitch and grid-stitch both faithful, stage-stitch marginally better on seam overlap. auto-stitch (old behavior) produced wrong tile arrangement. To opt back into the pre-v0.7.0 default: pass the new lif_mosaic="bioio-lif" value. It's also what the cascade automatically picks on tile-metadata-less scenes. Audit block gains mosaic.cascade_selected=True whenever the cascade picked the concrete stitcher, so downstream analysis can distinguish "grid-stitch was picked because stage was ineligible" from "user asked for grid-stitch". Explicit values (--lif-mosaic stage-stitch, etc.) omit the flag. Implementation: - Cascade selector select_auto_stitch_cascade() in metadata/lif_tiles.py, composed from two new non-throwing predicates (is_stage_layout_complete, is_grid_layout_complete). Shared by _convert_per_scene (api.py) and write_plate (writers/plate.py). - MosaicStitchingWarning text updated: no longer suggests grid-stitch or stage-stitch (cascade already tried them), still names per-tile as the remaining zarrmony alternative. - CLI --lif-mosaic gains "bioio-lif" as a fifth choice; default string stays "auto-stitch" (only the meaning changed). - Tests: new tests/test_lif_cascade.py locks the decision matrix (7 cases: each of the 3 cascade arms + plate skip + 2 explicit-value bypasses). Two prior default-behavior tests rewritten to reflect the new default. Closes #41. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Summary
Resolves #41: pick the new
lif_mosaicdefault based on real-acquisition visual comparison, and ship the cascade + naming cleanup that lets the default do the right thing.Behavior change (BREAKING):
lif_mosaic="auto-stitch"(still the default value) no longer means "use bioio-lif's 1-pixel-overlap M-scan-order stitcher". It now runs a per-scene cascade:stage-stitch— when the scene has per-tilePosX/PosYand both physical pixel sizesgrid-stitch— whenFieldX/FieldYform a complete rectangular gridbioio-lif— no<Tile>metadata (final fallback)Under
layout="plate"the cascade skips stage-stitch (not wired to the plate writer today) and lands ongrid-stitchorbioio-lifper FOV.New escape hatch:
lif_mosaic="bioio-lif"opts back into the pre-v0.7.0 default. Existing scripts passing--lif-mosaic auto-stitchwill produce different (better) pixels.Audit surface:
mosaic.cascade_selected: truedistinguishes cascade-picked from user-picked stitchers.Visual comparison (from #41)
Ran all three modes against
2026-05-14_ODC51_astrocytes.lif(48 scenes, 3x3 mosaics, 10% declared overlap) on scene6hours/B/2. Compared against the acquisition-software rendering (ground truth):Cascade default is
stage-stitchfor these scenes (every scene has complete metadata). Users who need the pre-v0.7.0 pixels can pass--lif-mosaic bioio-lif.Test plan
uv run pytest— 331 passed locally (was 324 pre-Validate LIF mosaic placement on real acquisition + flip default #41; +7 cascade tests, 2 rewrites, 0 regressions)uv run zarrmony convert --help— CLI now lists all 5 values and describes the cascade--lif-mosaicflag; confirm audit showsstitcher=zarrmony-stage+cascade_selected=trueon every scene and noMosaicStitchingWarningfires--lif-mosaic bioio-lifreproduces the pre-v0.7.0 pixels + emits the rewrittenMosaicStitchingWarningFollow-ups (out of scope)
🤖 Generated with Claude Code