fix(core): make per-tile labels globally unique before merging - #43
Merged
Conversation
Tiles each emit local labels (1..N), so every tile has a "1". The merge keyed objects by value, fusing unrelated objects from different tiles — multi-object, multi-tile segmentations collapsed (often to a single label). This is the package's core promise, so it must always hold. Add a streaming first pass in zarr_native_merge (_make_globally_unique) that renumbers each chunk's labels into a fresh contiguous global range before the boundary stitch. Unique AND compact: max_label == n_objects, so the relabel LUT stays O(objects), not O(voxels). One chunk in RAM at a time — no OOM (never more than segmentation already loads per tile). The merge output now matches the staged dtype so wide ids never truncate. Fixes both tile_process and the per-tile API (stage_tile). Regression test added: four separate objects across four tiles stay four labels. Co-Authored-By: Claude Opus 4.8 <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.
The bug (core correctness)
Every tile emits local labels `1..N`, so each tile has a `1`. The merge keyed objects by value, so unrelated objects from different tiles that share a value were fused — multi-object, multi-tile segmentations collapsed (in the reported case, everything to a single label → one flat colour in napari, no selectable instances, empty feature table).
Reproduced: 4 separate objects across 4 tiles → 1 label.
Fix
Add a streaming first pass in `zarr_native_merge` (`_make_globally_unique`): renumber each chunk's labels into a fresh contiguous global range before the boundary stitch. Labels become unique and compact (`max_label == n_objects`), so the relabel LUT stays `O(objects)`, not `O(voxels)`.
Tests
🤖 Generated with Claude Code