Motivation
On Leica widefield mosaics where the acquisition's declared overlap didn't translate to overlapped stage motion (i.e. stage-stitch produces essentially butt joints), the dominant visible seam artifact is photometric, not geometric — vignetting and shading falloff at each tile's edge produces feature "duplication" and brightness discontinuities that no better stitcher can fix.
The astrocytes acquisition (surfaced in the follow-up to #41) is exactly this shape:
- Stage positions describe butt joints (~2 px overlap between adjacent 2048-px tiles).
OverlapPercentageX=0.10 is UI-configured but not actualized.
- Adjacent tile pixel content therefore doesn't overlap — no external stitcher (ASHLAR, m2stitch, BigStitcher) can register on content that isn't there.
- The visible seams are edge-of-field vignetting + shading falloff, not misalignment.
The LIF file already references the shading correction that the acquisition software applies at capture time, per-camera-lane:
<InScanProcessing Application="LAS AF">
<CameraLane0>
<ShadingProcessingStep>
<ShadingReferenceID_UsedSetting_0>1431</ShadingReferenceID_UsedSetting_0>
<ShadingReference>CA21M726010K8 (b/w), 2048x2048, O10x11506537, MagChanger , FLUO</ShadingReference>
</ShadingProcessingStep>
</CameraLane0>
<CameraLane1>...</CameraLane1>
...
</InScanProcessing>
If zarrmony (or bioio-lif) can apply this correction at conversion time, seam appearance improves dramatically on this class of acquisition without changing anything geometric.
What to build
Investigate whether bioio-lif already applies shading correction on read (I suspect not — the raw tile pixels look uncorrected). If it doesn't:
- Extractor: parse the
<InScanProcessing>/<CameraLane*>/<ShadingProcessingStep> block per-scene from the LIF XML. Surface per-channel-lane shading reference identifiers.
- Reference lookup: figure out how the
ShadingReferenceID_UsedSetting_0 value resolves to actual shading reference image data. It might be:
- Stored elsewhere in the same LIF (an internal reference image the extractor should also read)
- Stored in a sidecar
.lif shading library the user has separately
- Referenced by ID only, with pixels living in a Leica database (in which case: not recoverable, at least document the limitation)
- Correction pass: if reference data is available, apply per-tile flat-field correction (
tile_corrected = (tile - dark) / (flat - dark) * mean(flat - dark) or the equivalent Leica convention) BEFORE stitching.
- Cascade integration: correction is orthogonal to stitcher choice — should apply under
stage-stitch, grid-stitch, per-tile, and bioio-lif alike. New lif_shading_correction: bool = True (default on when reference data is available) with clear docstring naming when it silently no-ops.
- Audit surface: record whether shading correction ran (
mosaic.shading_correction: {applied: true, reference_id: 1431, source: "lif-internal"} or {applied: false, reason: "no shading reference in scene XML"}).
Acceptance criteria
Notes / open questions
- May be worth lifting the extractor into
bioio-lif upstream if the reference data is reachable from LIF alone — benefits all bioio-lif consumers, not just zarrmony.
- Interacts with the "true overlap requires an external stitcher" answer in ways worth documenting: shading correction addresses PHOTOMETRIC seams; external stitchers address GEOMETRIC seams. On acquisitions with real content overlap, both matter and can compose.
- Not urgent for the Aperture pipeline unless quantitative analysis at tile boundaries becomes a requirement — the audit currently correctly surfaces the mismatch, downstream can defer or filter.
Discovered while
Diagnosing tile-seam appearance on the 2026-05-14_ODC51_astrocytes.lif conversion (follow-up to #41).
Motivation
On Leica widefield mosaics where the acquisition's declared overlap didn't translate to overlapped stage motion (i.e. stage-stitch produces essentially butt joints), the dominant visible seam artifact is photometric, not geometric — vignetting and shading falloff at each tile's edge produces feature "duplication" and brightness discontinuities that no better stitcher can fix.
The astrocytes acquisition (surfaced in the follow-up to #41) is exactly this shape:
OverlapPercentageX=0.10is UI-configured but not actualized.The LIF file already references the shading correction that the acquisition software applies at capture time, per-camera-lane:
If zarrmony (or
bioio-lif) can apply this correction at conversion time, seam appearance improves dramatically on this class of acquisition without changing anything geometric.What to build
Investigate whether
bioio-lifalready applies shading correction on read (I suspect not — the raw tile pixels look uncorrected). If it doesn't:<InScanProcessing>/<CameraLane*>/<ShadingProcessingStep>block per-scene from the LIF XML. Surface per-channel-lane shading reference identifiers.ShadingReferenceID_UsedSetting_0value resolves to actual shading reference image data. It might be:.lifshading library the user has separatelytile_corrected = (tile - dark) / (flat - dark) * mean(flat - dark)or the equivalent Leica convention) BEFORE stitching.stage-stitch,grid-stitch,per-tile, andbioio-lifalike. Newlif_shading_correction: bool = True(default on when reference data is available) with clear docstring naming when it silently no-ops.mosaic.shading_correction: {applied: true, reference_id: 1431, source: "lif-internal"}or{applied: false, reason: "no shading reference in scene XML"}).Acceptance criteria
lif_shading_correction=Falsecleanly disables the pass (backward-compat escape hatch).MosaicShadingWarning(new warning class) naming what's missing; conversion still succeeds.Notes / open questions
bioio-lifupstream if the reference data is reachable from LIF alone — benefits all bioio-lif consumers, not just zarrmony.Discovered while
Diagnosing tile-seam appearance on the 2026-05-14_ODC51_astrocytes.lif conversion (follow-up to #41).