Skip to content

feat(lif)!: auto-stitch is now a cascade default (closes #41)#45

Merged
ferrinm merged 1 commit into
mainfrom
feat/issue-41-lif-mosaic-cascade
Jul 2, 2026
Merged

feat(lif)!: auto-stitch is now a cascade default (closes #41)#45
ferrinm merged 1 commit into
mainfrom
feat/issue-41-lif-mosaic-cascade

Conversation

@ferrinm

@ferrinm ferrinm commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Summary

Resolves #41: pick the new lif_mosaic default 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:

  1. stage-stitch — when the scene has per-tile PosX/PosY and both physical pixel sizes
  2. grid-stitch — when FieldX/FieldY form a complete rectangular grid
  3. bioio-lif — no <Tile> metadata (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.

New escape hatch: lif_mosaic="bioio-lif" opts back into the pre-v0.7.0 default. Existing scripts passing --lif-mosaic auto-stitch will produce different (better) pixels.

Audit surface: mosaic.cascade_selected: true distinguishes 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 scene 6hours/B/2. Compared against the acquisition-software rendering (ground truth):

  • auto-stitch (pre-v0.7.0 default): wrong tile arrangement (M-scan-order bug)
  • grid-stitch: matches acquisition software; acceptable with butt joints at seams
  • stage-stitch: marginally better than grid on overlap registration; residual feature duplication at seams is an optical artifact, not metadata/processing error

Cascade default is stage-stitch for 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
  • After merge + v0.7.0 tag + sandbox upgrade, re-run against the astrocytes LIF with no --lif-mosaic flag; confirm audit shows stitcher=zarrmony-stage + cascade_selected=true on every scene and no MosaicStitchingWarning fires
  • Same host with --lif-mosaic bioio-lif reproduces the pre-v0.7.0 pixels + emits the rewritten MosaicStitchingWarning

Follow-ups (out of scope)

  • Wire stage-stitch to the plate writer so plate cascades can pick it too (currently plate cascade tops out at grid-stitch)

🤖 Generated with Claude Code

…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>
@ferrinm
ferrinm merged commit b363aa4 into main Jul 2, 2026
5 checks passed
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.

Validate LIF mosaic placement on real acquisition + flip default

1 participant