# Upsampling with SimpleITK

**URL:** https://discourse.itk.org/t/upsampling-with-simpleitk/6383
**Category:** Beginner Questions
**Created:** [January 4, 2024, 11:27pm UTC](https://discourse.itk.org/t/upsampling-with-simpleitk/6383 "2024-01-04T23:27:27Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![clarkbab](https://discourse.itk.org/user_avatar/discourse.itk.org/clarkbab/32/2305_2.png) [@clarkbab](https://discourse.itk.org/u/clarkbab)
#### Post date: [January 4, 2024, 11:27pm UTC](https://discourse.itk.org/t/upsampling-with-simpleitk/6383/1 "2024-01-04T23:27:27Z")

</div>

Hi there,

I’m running into an issue when upsampling an image with SimpleITK. I’ve created a simple grid to test my upsampling code, and my SimpleITK implementation seems to introduce some shift. Any ideas what I’m doing wrong? I’ve attached a reference (scipy) implementation and my SimpleITK version below.

**Scipy**

```python
import numpy as np
import scipy

# Create data.
spacing = 1
data = np.array([
    [0., 0., 0., 0., 0., 0., 0., 0.],
    [0., 1., 1., 0., 1., 1., 0., 1.],
    [0., 1., 1., 0., 1., 1., 0., 1.],
    [0., 0., 0., 0., 0., 0., 0., 0.],
    [0., 1., 1., 0., 1., 1., 0., 1.],
    [0., 1., 1., 0., 1., 1., 0., 1.],
    [0., 0., 0., 0., 0., 0., 0., 0.],
    [0., 1., 1., 0., 1., 1., 0., 1.]])

# Upsample.
def resample(data, spacing, output_spacing):    
    scale = spacing / output_spacing
    resampled = scipy.ndimage.zoom(data, scale, order=1)
    return resampled

n_upsample = 5
_, axs = plt.subplots(1, n_upsample, figsize=(12, 6))
for ax in axs:
    ax.set_title(f"spacing={spacing}\nsize={data.shape[0]}")
    ax.imshow(np.transpose(data), origin='lower')
    output_spacing = spacing / 2
    data = resample(data, spacing, output_spacing)
    spacing = output_spacing

```

Output:

 ![scipy](https://discourse.itk.org/uploads/default/original/2X/9/9ef13fb4b6e020fcaf031acf5a677cb51271059f.png)

**SimpleITK**

```python
import matplotlib.pyplot as plt
import numpy as np
import SimpleITK as sitk

# Create data.
spacing = (1, 1, 1)
data = np.array([
    [0., 0., 0., 0., 0., 0., 0., 0.],
    [0., 1., 1., 0., 1., 1., 0., 1.],
    [0., 1., 1., 0., 1., 1., 0., 1.],
    [0., 0., 0., 0., 0., 0., 0., 0.],
    [0., 1., 1., 0., 1., 1., 0., 1.],
    [0., 1., 1., 0., 1., 1., 0., 1.],
    [0., 0., 0., 0., 0., 0., 0., 0.],
    [0., 1., 1., 0., 1., 1., 0., 1.]])

# Upsample.
def resample(data, spacing, output_spacing):    
    image = sitk.GetImageFromArray(data)
    image.SetSpacing(spacing)
    size = image.GetSize()
    
    size_scaling = np.array(spacing) / np.array(output_spacing)
    output_size = tuple(int(s * sc) for s, sc in zip(size, size_scaling))
    output_origin = image.GetOrigin()
    
    resampled = sitk.Resample(
        image,
        output_size,
        outputOrigin=output_origin,
        outputSpacing=output_spacing,
    )
    
    return sitk.GetArrayFromImage(resampled)

n_upsample = 5
_, axs = plt.subplots(1, n_upsample, figsize=(12, 6))
for ax in axs:
    ax.set_title(f"spacing={spacing[0]}\nsize={data.shape[0]}")
    ax.imshow(np.transpose(data), origin='lower')
    output_spacing = tuple(np.array(spacing) / 2)
    data = resample(data, spacing, output_spacing)
    spacing = output_spacing

```

Output:

 ![simpleitk](https://discourse.itk.org/uploads/default/original/2X/f/fcf4e7ccf7cf935b74c830aa2c9280fb48d53e8c.png)

Thanks,  
Brett

---

<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: [January 5, 2024, 2:11pm UTC](https://discourse.itk.org/t/upsampling-with-simpleitk/6383/2 "2024-01-05T14:11:03Z")

</div>

Hello,

The has to do with the ITK Image being a geometric object with an origin defined at the center of the 0,0 pixel. Details of the ITK Image geometry can be reviewed here:  
[https://simpleitk.readthedocs.io/en/master/fundamentalConcepts.html](https://simpleitk.readthedocs.io/en/master/fundamentalConcepts.html)

You can also compare the results with the [ExpandImageFilter](https://simpleitk.org/doxygen/latest/html/classitk_1_1simple_1_1ExpandImageFilter.html).

Also look into a [SimpleITKUtilities](https://github.com/SimpleITK/SimpleITKUtilities) function [resize](http://simpleitk.org/SimpleITKUtilities/api.html#SimpleITK.utilities.resize) which parameters operate on pixels, and the spacing is computed with various options and features.

---

<div class="post-metadata">

### Author: ![clarkbab](https://discourse.itk.org/user_avatar/discourse.itk.org/clarkbab/32/2305_2.png) [@clarkbab](https://discourse.itk.org/u/clarkbab)
#### Post date: [January 27, 2024, 3:01am UTC](https://discourse.itk.org/t/upsampling-with-simpleitk/6383/3 "2024-01-27T03:01:56Z")

</div>

Thanks Bradley,

I was aware of the ITK geometry but wasn’t able to find the correct resampling parameters. In the end, adjusting the ‘output\_origin’ worked as shown in the following code. The formula for calculating the output origin works for both upsampling and downsampling.

This was implemented to upsample low-resolution saliency maps from a convolutional neural network back to the input space (reversing the effect of max pooling layers) and worked well 🙂

```auto
import matplotlib.pyplot as plt
import numpy as np
import SimpleITK as sitk

# Create data.
spacing = (1, 1, 1)
data = np.array([
    [0., 0., 0., 0., 0., 0., 0., 0.],
    [0., 1., 1., 0., 1., 1., 0., 1.],
    [0., 1., 1., 0., 1., 1., 0., 1.],
    [0., 0., 0., 0., 0., 0., 0., 0.],
    [0., 1., 1., 0., 1., 1., 0., 1.],
    [0., 1., 1., 0., 1., 1., 0., 1.],
    [0., 0., 0., 0., 0., 0., 0., 0.],
    [0., 1., 1., 0., 1., 1., 0., 1.]])

# Upsample.
def resample(data, spacing, output_spacing):    
    image = sitk.GetImageFromArray(data)
    image.SetSpacing(spacing)
    size = image.GetSize()
    
    size_scaling = np.array(spacing) / np.array(output_spacing)
    output_size = tuple(int(s * sc) for s, sc in zip(size, size_scaling))
    spacing_scaling = np.array(output_spacing) / np.array(spacing)
    output_origin = tuple(sp * (s - 1) / 2 for s, sp in zip(spacing_scaling, spacing))
    
    resampled = sitk.Resample(
        image,
        output_size,
        outputOrigin=output_origin,
        outputSpacing=output_spacing,
    )
    
    return sitk.GetArrayFromImage(resampled)

n_upsample = 5
_, axs = plt.subplots(1, n_upsample, figsize=(12, 6))
for ax in axs:
    ax.set_title(f"spacing={spacing[0]}\nsize={data.shape[0]}")
    ax.imshow(np.transpose(data), origin='lower')
    output_spacing = tuple(np.array(spacing) / 2)
    data = resample(data, spacing, output_spacing)
    spacing = output_spacing

```

 ![Screen Shot 2024-01-27 at 2.01.39 pm](https://discourse.itk.org/uploads/default/original/2X/4/4a55da2679d679da61239335e9bd9a2db2b0b730.png)

Thanks,  
Brett

---

<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: [January 29, 2024, 1:46pm UTC](https://discourse.itk.org/t/upsampling-with-simpleitk/6383/4 "2024-01-29T13:46:17Z")

</div>

Hello,

Your resampling results almost OK. Please be careful converting back and from between numpy and SimpleITK descriptive arrays as they are in different order. The [SimpleITK.Utilities.resize](http://simpleitk.org/SimpleITKUtilities/api.html#SimpleITK.utilities.resize) method contains this functionality. Consider reusing this method:

```auto

data = np.array([
    [0., 0., 0., 0., 0., 0., 0., 0.],
    [0., 1., 1., 0., 1., 1., 0., 1.],
    [0., 1., 1., 0., 1., 1., 0., 1.],
    [0., 0., 0., 0., 0., 0., 0., 0.],
    [0., 1., 1., 0., 1., 1., 0., 1.],
    [0., 1., 1., 0., 1., 1., 0., 1.],
    [0., 0., 0., 0., 0., 0., 0., 0.],
    [0., 1., 1., 0., 1., 1., 0., 1.]])

n_upsample = 5
_, axs = plt.subplots(1, n_upsample, figsize=(12, 6))
img = sitk.GetImageFromArray(data)
for ax in axs:
    ax.set_title(f"spacing={img.GetSpacing()[0]}\nsize={data.shape[0]}")
    ax.imshow(np.transpose(data), origin='lower')
    output_size = tuple(int(s*2) for s in data.shape[::-1])
    img = sitkUtils.resize(img, output_size, sitk.sitkLinear)
    print(img.GetSpacing())
    data = sitk.GetArrayFromImage(img)

```

 ![image](https://discourse.itk.org/uploads/default/original/2X/9/96c8797e7530e6d2457faf19e1ca4c1895e8c228.jpeg)

I suspect the difference between the outputs is that the SimpleITK.utilities.resize method correctly changes the origin of the image so that the extent of the image is the same. This has to do with the origin being defined as the center of the voxel not the corner.
