Skip to content

smartspim: prefer SmartSPIM's stitched All_Channels volume - #31

Merged
stevevanhooser merged 3 commits into
mainfrom
claude/spim-all-channels
Oct 12, 2026
Merged

stevevanhooser merged 3 commits into
mainfrom
claude/spim-all-channels

Conversation

@stevevanhooser

@stevevanhooser stevevanhooser commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This ports VH-Lab/NDR-matlab#142 (branch claude/spim-all-channels). ferret-lightsheet established that All_Channels/ contains SmartSPIM AutoStitch's stitched, flat-field-corrected and blended volume, which is what Imaris is built from. With this PR, ndr_reader_smartspim reads it first.

New format functions (ndr.format.smartspim, bridged as regular_port)

  • readAllChannelsInfo: indexes <Y>_<X>_<z*10>_ch<k>.tiff and maps each channel to its ch<k>, taken from <channel>_MIP_stitched or else from the filter-channel rank. Slices are sorted by numeric z. Also returns the canvas size and class, and the voxel size from metadata.json.
  • hasAllChannels: a non-throwing probe. It returns true only when every channel has slices.
  • readAllChannelsVolume: reads one channel as (z, y, x), with an optional ZRange.

Reader epochs

Epochstream Reads
[root] stitched volume, all channels on the C axis (ch<k> order)
[root, channel] stitched volume, one channel
[root, channel, tile] destriped Ex_* tile (unchanged)

Fallback: when All_Channels is missing or incomplete, [root] and [root, channel] raise the same "does not pin a channel / tile" errors as before. The Ex_* tiles remain the source of truth.

Bridge syncs (MATLAB commits recorded)

Entry Hash Python change
smartspim reader + 3 new format functions b8f0e4b the All_Channels support above
readTileInfo 3e300e5 none: MATLAB fixed uint16 TIFFs that store SampleFormat being read as int16; Python reads the type from tifffile and was never affected
tiffstack 8f870c1 none: MATLAB fixed float TIFFs being read as uint32; Python was never affected (float32 and int16 round-trips checked)

Other changes

  • imagecodecs is added to the dev and formats extras. Real All_Channels slices are LZW-compressed, and tifffile needs imagecodecs to decode them; the new tests also write LZW fixtures.

Testing

  • tests/test_smartspim_all_channels.py (new) and tests/test_smartspim_reader.py: 45 passed.
  • Strict bridge completeness and conventions checks, run against the NDR-matlab branch: 191 passed.
  • black --check and ruff check are clean.
  • CI on 0013532: all checks green.

Merge order: merge NDR-matlab#142 first, as a merge commit rather than a squash. The bridge YAML records that PR's commit hashes, and a squash would change them.

🤖 Generated with Claude Code

https://claude.ai/code/session_01U33UPxYJWPpcQimNu5t5Cb

Port of NDR-matlab b8f0e4b. ferret-lightsheet established that
All_Channels/ holds SmartSPIM AutoStitch's TeraStitcher merge of the
destriped tiles with flat-field / left-right correction and blended
overlaps -- the better-stitched, harmonized data Imaris is built from.

Format layer (new, bridged regular_port):
  * readAllChannelsInfo - index <Y>_<X>_<z*10>_ch<k>.tiff, map channels
    to ch<k> via <channel>_MIP_stitched, else filter-channel rank;
    numeric z order; canvas size / class; voxel size from metadata.json.
  * hasAllChannels - non-throwing probe, usable only if every channel
    has slices.
  * readAllChannelsVolume - one channel as (z, y, x), optional ZRange.

Reader epochs:
  [root]                 stitched volume, all channels on C (ch<k> order)
  [root, channel]        stitched volume, one channel
  [root, channel, tile]  destriped Ex_* tile, unchanged
Without a usable All_Channels, the first two keep the "does not pin a
channel / tile" errors (the Ex_* tiles are not obsolete).

imagecodecs joins the dev and formats extras: real All_Channels slices
are LZW, and the new tests write LZW fixtures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U33UPxYJWPpcQimNu5t5Cb
NDR-matlab fixed readTileInfo reporting int16 for TIFFs that store
SampleFormat = 1 (imfinfo's 'Unsigned integer' contains 'signed
integer'). The Python port takes the numpy dtype straight from tifffile
and never had the bug -- checked against a hand-built TIFF carrying
SampleFormat = 1 -- so only the sync hash and decision_log change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U33UPxYJWPpcQimNu5t5Cb
NDR-matlab fixed tiffclass reading float TIFFs ('IEEE floating point')
as uint32. The Python port takes the dtype from tifffile and was never
affected -- float32 and int16 stacks round-trip -- so only the sync hash
and decision_log change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U33UPxYJWPpcQimNu5t5Cb
@stevevanhooser
stevevanhooser merged commit 4998139 into main Oct 12, 2026
7 checks passed
@stevevanhooser
stevevanhooser deleted the claude/spim-all-channels branch October 12, 2026 13:15
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.

2 participants