Skip to content

fix: state whether the second channel is labels instead of guessing - #108

Open
Hendrik-code wants to merge 1 commit into
mainfrom
hm/fix-tio-channel-dispatch
Open

Hendrik-code wants to merge 1 commit into
mainfrom
hm/fix-tio-channel-dispatch

Conversation

@Hendrik-code

Copy link
Copy Markdown
Collaborator

The defect

if img.shape[0] == 2:
    subject = transform(tio.Subject(
        image=tio.ScalarImage(tensor=img[0:1]),
        discs=tio.LabelMap(tensor=img[1:2]),   # <- decided by channel count alone
        seg=tio.LabelMap(tensor=seg)))

The totalspineseg "step 2" layout really does carry an odd-disc segmentation in channel 1. But a genuine two-modality input — T1+T2, in-phase/out-of-phase — has exactly the same shape, and got its second modality registered as a tio.LabelMap. torchio then resamples it nearest-neighbour and skips every intensity artifact on it, so the two modalities diverge in both interpolation and augmentation while the caller believes both were augmented together.

Channel count cannot distinguish the two cases; nothing in the tensor can.

The fix

second_channel_is_labels, threaded from ArtifactTransform / SpatialCustomTransform through apply_enabled into apply_tio, where a config can set it.

It defaults to True — the long-standing behaviour — so the step 2 pipeline is unchanged and test_the_second_channel_is_treated_as_labels passes untouched. A multi-modality caller now has a way to say so, which was previously impossible to express.

all_augmentations.json is regenerated for the new parameter.

Tests

Added to unit_tests/test_torchio_ops.py: the default still treats channel 1 as labels; second_channel_is_labels=False lets an intensity artifact reach it (the case that used to be inexpressible); the default leaves it alone under the same call, as the control; and a single-channel image is unaffected either way.

Verified failing before the fix (3 failed) and passing after. Full suite unchanged against baseline; ruff check . clean.

🤖 Generated with Claude Code

`apply_tio` dispatched on `img.shape[0] == 2` alone. The totalspineseg "step 2"
layout really does carry an odd-disc segmentation there, but a genuine
two-modality input -- T1+T2, in-phase/out-of-phase -- has the same shape, and it
was registered as a `tio.LabelMap`: resampled nearest-neighbour, and skipped by
every intensity artifact, so the two modalities came out of the pipeline
differing in both respects.

Channel count cannot tell those apart, so `second_channel_is_labels` says which
it is, threaded through `apply_enabled` to `ArtifactTransform` and
`SpatialCustomTransform` where a config can set it. It defaults to True, so the
step 2 pipeline is unchanged; the existing test that pins that behaviour still
passes untouched.

all_augmentations.json is regenerated for the new parameter.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

1 participant