# Faster interpolation using sitkLabelGaussian

**URL:** <https://discourse.itk.org/t/faster-interpolation-using-sitklabelgaussian/6183>\
**Category:** Algorithms\
**Tags:** simpleitk\
**Created:** [September 6, 2023, 3:08pm UTC](https://discourse.itk.org/t/faster-interpolation-using-sitklabelgaussian/6183 "2023-09-06T15:08:06Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![dyoll](https://discourse.itk.org/user_avatar/discourse.itk.org/dyoll/32/2311_2.png) [@dyoll](https://discourse.itk.org/u/dyoll)\
**Post date:** [September 6, 2023, 3:08pm UTC](https://discourse.itk.org/t/faster-interpolation-using-sitklabelgaussian/6183/1 "2023-09-06T15:08:06Z")

</div>

Hi

I am working on a MONAI-based whole head segmentation tool, which predicts close to 30 tissue labels.

Currently all post-processing is implemented in Python using SimpleITK. Once we have done some clean-up operations at 1mm resolution, we need to insert thin layers of Dura and Cerebrospinal fluid. For this purpose we resample the segmentation to 0.3-0.5mm using the `ResampleImageFilter` (sitkLabelGaussian option).

Unfortunately, this gets very slow (it is using all CPUs). Is there any way to get smooth interpolation (i.e. not nearest neighbor) but better performance. I doubt computing the signed distance transform and smoothing for each label will scale nicely (approx. 30 labels).

---

<div class="post-metadata">

**Author:** ![dyoll](https://discourse.itk.org/user_avatar/discourse.itk.org/dyoll/32/2311_2.png) [@dyoll](https://discourse.itk.org/u/dyoll)\
**Post date:** [September 7, 2023, 8:58am UTC](https://discourse.itk.org/t/faster-interpolation-using-sitklabelgaussian/6183/2 "2023-09-07T08:58:42Z")

</div>

To implement a similar behavior, we could

- convert labels to one-hot (e.g. 10 channels for labels in range [0, 9]).
- smooth the one-hot “vector” image
- resample the smoothed on-hot image
- perform argmax to get resampled & smoothed labels

The problem is that this will explode memory usage (at least GPU)). For 600x600x600 images, with 30 labels, using 32-bit float we would need 24 GB (600 x 600 x 600 x 30 x 4 B) per one-hot image.

```auto
def test_LabelGaussianInterpolation():
    """Example code implementing the label gaussian with MONAI/pytorch"""
    labels = sitk.Image(100, 110, 80, sitk.sitkUInt16)
    labels[:] = 0
    labels[3:40, 80:90, 25:60] = 1
    labels[15:35, 30:95, 50:70] = 2
    labels[30:35, 30:35, 30:35] = 3

    num_classes = 4
    file_path = Path.cwd() / "labels.nii.gz"
    sitk.WriteImage(labels, file_path)

    reader = LoadImage(reader="ITKReader", ensure_channel_first=True, image_only=False)
    to_tensor = EnsureType(dtype=torch.half)
    to_one_hot = AsDiscrete(to_onehot=num_classes, dtype=torch.half)

    labels_tuple = reader(filename=[file_path])

    labels_tensor = to_tensor(labels_tuple[0])
    log_tensor("input", labels_tensor)

    onehot_tensor = to_one_hot(labels_tensor)
    log_tensor("onehot", onehot_tensor)

    smooth = GaussianSmooth(sigma=1.5)
    smooth_onehot_tensor = smooth(onehot_tensor)
    log_tensor("smooth", smooth_onehot_tensor)

    resample = Spacing(pixdim=0.5)
    hires_onehot_tensor = resample(smooth_onehot_tensor)
    log_tensor("hires", hires_onehot_tensor)

    to_argmax = AsDiscrete(argmax=True)
    hires_argmax_tensor = to_argmax(hires_onehot_tensor)
    log_tensor("argmax", hires_argmax_tensor)

    saver = SaveImage(
        resample=False,
        output_postfix="hr",
        output_dir=Path.cwd(),
        separate_folder=False,
    )
    saver(hires_argmax_tensor)

```

To solve the memory issue, we could maybe use 16-bit float (torch.half). A much more drastic saving would be to iterate over the channels, and update the current maximum of the smooth indicator functions and corresponding label.

Note: Of course the CPU memory might be enough, but then the performance will not be better than the current sitkLabelGaussian.

---

<div class="post-metadata">

**Author:** ![blowekamp](https://discourse.itk.org/user_avatar/discourse.itk.org/blowekamp/32/79_2.png) [@blowekamp](https://discourse.itk.org/u/blowekamp)\
**Post date:** [September 7, 2023, 12:36pm UTC](https://discourse.itk.org/t/faster-interpolation-using-sitklabelgaussian/6183/3 "2023-09-07T12:36:13Z")

</div>

The above may more efficiently be implemented in SimpleITK/ITK using the LabelMap representation. The LabelMap “Images” a represented as sparse RLE. Each label could be extracted the smoothing/resampling performed and then converted to a LabelMap and merged together.

Alternatively consider using morphological operations to smooth the results after nearest neighbor interpolation? Performing opening and closing may yield acceptable results.

There is a ITK remove module [ITKLabelErodeDilate](https://github.com/InsightSoftwareConsortium/ITKLabelErodeDilate) which efficiently operates on multi-labeled images. I demoed it once a while ago, but have not used it recently.

The author of the module @richard.beare who may have more information on if its suitable for this application.

---

<div class="post-metadata">

**Author:** ![dyoll](https://discourse.itk.org/user_avatar/discourse.itk.org/dyoll/32/2311_2.png) [@dyoll](https://discourse.itk.org/u/dyoll)\
**Post date:** [September 7, 2023, 2:30pm UTC](https://discourse.itk.org/t/faster-interpolation-using-sitklabelgaussian/6183/4 "2023-09-07T14:30:32Z")

</div>

Thanks for the suggestion @blowekamp!

I have used the LabeErodeDilate module quite a lot. I guess you are proposing to:

- convert to LabelMap representation
- smooth each label
- merge with some priority (for overlapping voxels)
- fill holes with the LabelSetDilateImageFilter (from LabeErodeDilate), or with my [ITKDissolve](https://pypi.org/project/itk-dissolve/) module

I will give it a try and see what is faster.

---

<div class="post-metadata">

**Author:** ![ntustison](https://discourse.itk.org/user_avatar/discourse.itk.org/ntustison/32/462_2.png) [@ntustison](https://discourse.itk.org/u/ntustison)\
**Post date:** [September 7, 2023, 9:02pm UTC](https://discourse.itk.org/t/faster-interpolation-using-sitklabelgaussian/6183/5 "2023-09-07T21:02:29Z")

</div>

Have you looked at the more general [GenericLabelInterpolator](https://itk.org/Doxygen/html/group__GenericLabelInterpolator.html) where you can substitute the linear analog? The related IJ article shows evidence improvement in terms of both accuracy and computational performance over the Gaussian version that I wrote. For what it’s worth, it’s what we’ve been using in ANTs for years.

---

<div class="post-metadata">

**Author:** ![dyoll](https://discourse.itk.org/user_avatar/discourse.itk.org/dyoll/32/2311_2.png) [@dyoll](https://discourse.itk.org/u/dyoll)\
**Post date:** [September 8, 2023, 9:08am UTC](https://discourse.itk.org/t/faster-interpolation-using-sitklabelgaussian/6183/6 "2023-09-08T09:08:00Z")

</div>

True. Thanks @ntustison! I have only used the GenericLabelInterpolator from C++ but I see could try the GenericLabelInterpolator via the [python remote module](https://pypi.org/project/itk-genericlabelinterpolator/#history).

Maybe I will create a PR to add it as sitkLabelLinear to SimpleITK.

---

<div class="post-metadata">

**Author:** ![blowekamp](https://discourse.itk.org/user_avatar/discourse.itk.org/blowekamp/32/79_2.png) [@blowekamp](https://discourse.itk.org/u/blowekamp)\
**Post date:** [September 8, 2023, 11:31am UTC](https://discourse.itk.org/t/faster-interpolation-using-sitklabelgaussian/6183/7 "2023-09-08T11:31:41Z")

</div>

> [@dyoll](#):
>
> Maybe I will create a PR to add it as sitkLabelLinear to SimpleITK.

The contribution will be most welcomed.

---

<div class="post-metadata">

**Author:** ![dyoll](https://discourse.itk.org/user_avatar/discourse.itk.org/dyoll/32/2311_2.png) [@dyoll](https://discourse.itk.org/u/dyoll)\
**Post date:** [September 9, 2023, 3:46pm UTC](https://discourse.itk.org/t/faster-interpolation-using-sitklabelgaussian/6183/8 "2023-09-09T15:46:25Z")

</div>

@ntustison thanks for the GenericLabelInterpolator suggestion. The speed-up is not bad, especially if the labelmap doesn’t have too many labels.

[![image](https://discourse.itk.org/uploads/default/original/2X/4/494862c4411065da4c6d42c65ea1f5f89c5eec11.png)](https://github.com/SimpleITK/SimpleITK/pull/1986)

---

<div class="post-metadata">

**Author:** ![ntustison](https://discourse.itk.org/user_avatar/discourse.itk.org/ntustison/32/462_2.png) [@ntustison](https://discourse.itk.org/u/ntustison)\
**Post date:** [September 9, 2023, 7:52pm UTC](https://discourse.itk.org/t/faster-interpolation-using-sitklabelgaussian/6183/9 "2023-09-09T19:52:26Z")

</div>

Interesting. Thanks for posting this.

---

<div class="post-metadata">

**Author:** ![fepegar](https://discourse.itk.org/user_avatar/discourse.itk.org/fepegar/32/1664_2.png) [@fepegar](https://discourse.itk.org/u/fepegar)\
**Post date:** [July 30, 2025, 8:40pm UTC](https://discourse.itk.org/t/faster-interpolation-using-sitklabelgaussian/6183/10 "2025-07-30T20:40:22Z")

</div>

Did you ever create that PR? 🙂 I’d love to have this in SimpleITK.

---

<div class="post-metadata">

**Author:** ![zivy](https://discourse.itk.org/user_avatar/discourse.itk.org/zivy/32/1726_2.png) [@zivy](https://discourse.itk.org/u/zivy)\
**Post date:** [July 30, 2025, 9:33pm UTC](https://discourse.itk.org/t/faster-interpolation-using-sitklabelgaussian/6183/11 "2025-07-30T21:33:18Z")

</div>

Hello @fepegar,

The `sitkLabelLinear` is available in SimpleITK, just use that InterpolatorEnum in your code.

---

<div class="post-metadata">

**Author:** ![fepegar](https://discourse.itk.org/user_avatar/discourse.itk.org/fepegar/32/1664_2.png) [@fepegar](https://discourse.itk.org/u/fepegar)\
**Post date:** [August 1, 2025, 10:13pm UTC](https://discourse.itk.org/t/faster-interpolation-using-sitklabelgaussian/6183/12 "2025-08-01T22:13:22Z")

</div>

Thanks, @zivy. I’ll give that a try.
