Why image and mask resampling must differ
Tonight · ~30 min · read + a code example · energy: medium · setup: optional Python
You resample a CT and its tumour mask to a common 1 mm grid. You use the same
interpolator for both. The mask now contains voxel values of 0.4 and 0.7 —
“40% tumour, 60% liver” — and every shape and boundary feature is silently wrong.
This lesson is why image and mask resampling are deliberately asymmetric, and why
that asymmetry is the punchline of the whole chapter.
The anchor: continuous values vs discrete labels
Resampling means computing an image’s values on a new grid (different spacing, origin, or direction). It is unavoidable in radiomics (pipelines normalise to a common spacing) and in mask transfer. To compute a new voxel’s value you look at the input voxels around the corresponding physical location and combine them. The question is how you combine them — and the answer depends on what the numbers mean.
The image holds a continuous quantity (HU, a roughly meaningful scalar field), so interpolating between neighbouring voxel values is legitimate: the true value at a point between two voxels is plausibly between their values.
The mask holds discrete labels. Interpolating “half tumour, half liver” between two label voxels is nonsense — a voxel is one structure or another, not a mixture. So the two objects must be resampled with different interpolators:
- Images: linear (or B-spline) interpolation — smooth, physically reasonable.
- Masks: nearest-neighbour — every output voxel takes the label of the nearest input voxel, preserving discrete labels.
Hard rule: never feed a binary mask through linear/B-spline interpolation for radiomics. It blurs the label into fractional values, breaks label integrity, and silently changes every boundary-related feature.
The interpolators, compared
| Interpolator | Use for | Behaviour | Risk |
|---|---|---|---|
| Linear (trilinear) | image (safe default) | fast, no overshoot | mild smoothing |
| B-spline | image (radiomics preference) | smoother, less interpolation noise | overshoot past the input range at sharp boundaries |
| Nearest-neighbour | mask / labels | preserves integer labels | blocky boundary (expected) |
B-spline overshoot matters at sharp high-contrast boundaries (bone/air): it can
create values outside the input range. That is why TRACE-CT resamples the CT to a
1 mm isotropic grid with B-spline and clips HU afterward ([-1000, +400]) —
the clip tames the overshoot. The mask, in the same pipeline, takes
nearest-neighbour.
The asymmetric resample, in code
import SimpleITK as sitk# image: B-spline; mask: nearest-neighbour — to the SAME reference geometryresampled_img = sitk.Resample(img, ref_img, sitk.Transform(), sitk.sitkBSpline, 0.0, sitk.sitkInt16)resampled_mask = sitk.Resample(mask, ref_img, sitk.Transform(), sitk.sitkNearestNeighbor, 0, sitk.sitkUInt8)Note the deliberate asymmetry: same reference, same transform, different interpolator and background value for image vs mask. This is the SimpleITK bridge (lesson 1) doing its job — it carries geometry with the image, so resampling is a geometric operation, not an array reshuffle.
Partial volume: expected physics, not a bug
When you resample to a coarser spacing, each output voxel averages a region of the input. At a boundary (tumour/normal) the output voxel becomes a mixture of tissues — a partial volume. For the image this is a smooth average; for the mask it is an ambiguous boundary (nearest-neighbour assigns it to one side). Partial volume changes volumes, edge sharpness, and texture features. This is expected physics, not a bug — but it is why the resampling target must be reported in every radiomics result, or the feature is irreproducible.
The chapter’s punchline
Everything in this chapter converges here:
A radiomic feature is a function of (image, mask, geometry). Change the geometry — spacing, interpolation, discretisation — and the feature value changes, even though the underlying anatomy did not. Resampling is a preprocessing choice, and every preprocessing choice is a feature-determining variable.
This is why IBSI fixes a processing workflow, why PyRadiomics lets you pin
resampling parameters, and why TRACE-CT commits a parameter file
(configs/pyradiomics_params.yaml) with fixed binWidth and spacing rather than
leaving them to defaults. The feature is not a property of the tumour; it is a
property of the tumour under a stated pipeline. Chapter 3
exists to make that statement precise.
Stop and think — then reveal
You resample both image and mask to 2 mm isotropic (from 1 mm) using nearest-neighbour for the mask and B-spline for the image, then recompute a texture feature. The value changes. Is the new value “wrong”?
No — it is the feature under a different geometry, which is a legitimately different quantity. The error would be to report the new value without recording the new spacing/interpolator, or to compare it to a value computed at 1 mm as if they were the same measurement. Resampling changes features by construction; the discipline is to pin and report the target geometry so that any comparison is between like and like. A feature “changed by resampling” is only a problem if you did not notice you changed the pipeline.
What to retain
- Images hold continuous values → interpolate (linear/B-spline). Masks hold discrete labels → resample nearest-neighbour. Never linear-interpolate a mask.
- B-spline can overshoot at sharp boundaries; clip afterward (TRACE-CT clips
HU to
[-1000, +400]). - Coarser resampling produces partial volume at boundaries — expected physics, but it changes volumes and features, so report the target.
- The punchline: a feature is a function of (image, mask, geometry). Change the geometry and you change the feature — pin and report every preprocessing choice.
Next: stop reading and look. A Visual-QC pass in 3D Slicer that turns every concept above into something you can verify with your eyes.