Skip to content

fix(omero): default channel window to array dtype range, not 0-255#59

Merged
ferrinm merged 3 commits into
mainfrom
fix/issue-50-omero-window-dtype-range
Jul 23, 2026
Merged

fix(omero): default channel window to array dtype range, not 0-255#59
ferrinm merged 3 commits into
mainfrom
fix/issue-50-omero-window-dtype-range

Conversation

@ferrinm

@ferrinm ferrinm commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Summary

  • omero.channels[i].window was hardcoded to {min: 0, max: 255, start: 0, end: 255} on every store because the three bioio_ome_zarr.writers.Channel(...) construction sites in zarrmony passed no window= argument. uint16 / uint32 / float32 stores therefore appeared black on first open in napari / OMERO — the display window clamped intensities into an 8-bit band while the acquisition's real pixels lived far outside it.
  • Fix derives the window from the reader's dtype at all three call sites (api._lif_scene_channels, api._channels_for_scene, writers.scene._default_channels) via a new _dtype_window(dtype) helper. Integer dtypes use np.iinfo(min, max); float dtypes use 0.0/1.0 (OMERO convention for normalized floats). start / end mirror min / max — percentile-based auto-contrast is a separate concern, out of scope for this fix.
  • FakeReader now honors a dtype= kwarg and exposes a .dtype property mirroring bioio's Reader.dtype, so tests can vary the array dtype without allocating the pixel buffer.

Test plan

  • uv run pytest -q — 347 tests pass
  • Unit tests for _dtype_window covering uint8, uint16, uint32, int16, float32, float64
  • Integration test via write_scene (parametrized on uint8 / uint16 / float32) reads back zarr.json's attributes.ome.omero.channels[i].window and asserts it matches the dtype range — the acceptance-criteria fixture from the issue
  • Integration test via convert() covering the _channels_for_scene name-based path (parametrized dtypes)
  • Integration test via convert() covering the LIF _lif_scene_channels path with the 7-channel confocal fixture (parametrized dtypes)
  • Regression guard: uint8 still ships {0, 255, 0, 255} (asserted in every parametrized batch)
  • CHANGELOG updated under [Unreleased] / Fixed

Closes #50.

🤖 Generated with Claude Code

The OME-Zarr `omero.channels[i].window` block was hardcoded to
`{min: 0, max: 255, start: 0, end: 255}` on every store because
zarrmony constructed `bioio_ome_zarr.writers.Channel(...)` without
passing `window=`. Every uint16 / uint32 / float32 store therefore
shipped with a display window clamped to 8-bit range and appeared
black on first open in napari and OMERO — the acquisition's real
intensities lived far outside the window, so viewers rendered
everything above 255 as saturated white and everything else as noise
near zero.

Fix: derive the window from the reader's dtype at the three
`Channel(...)` construction sites (`api._lif_scene_channels`,
`api._channels_for_scene`, `writers.scene._default_channels`). Integer
dtypes use `np.iinfo(min, max)`; float dtypes use `0.0`/`1.0` (OMERO
convention for normalized floats). `start` / `end` mirror `min` / `max`
so first-open viewers see the full range unclipped — percentile-based
auto-contrast is a separate concern, not this bug.

Closes #50.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ferrinm added 2 commits July 23, 2026 15:01
…ndow-dtype-range

# Conflicts:
#	CHANGELOG.md
#	src/zarrmony/api.py
…ndow-dtype-range

# Conflicts:
#	CHANGELOG.md
#	src/zarrmony/api.py
#	src/zarrmony/writers/scene.py
@ferrinm
ferrinm merged commit df36933 into main Jul 23, 2026
5 checks passed
@ferrinm
ferrinm deleted the fix/issue-50-omero-window-dtype-range branch July 23, 2026 22:29
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.

fix(omero): default window to array dtype range instead of hardcoded 0–255

1 participant