'Upsample and Interpolate a NumPy Array

I have an array, something like:

array = np.arange(0,4,1).reshape(2,2)

> [[0 1
    2 3]]

I want to both upsample this array as well as interpolate the resulting values. I know that a good way to upsample an array is by using:

array = eratemp[0].repeat(2, axis = 0).repeat(2, axis = 1)
[[0 0 1 1]
 [0 0 1 1]
 [2 2 3 3]
 [2 2 3 3]]

but I cannot figure out a way to interpolate the values to remove the 'blocky' nature between each 2x2 section of the array.

I want something like this:

[[0 0.4 1 1.1]
 [1 0.8 1 2.1]
 [2 2.3 3 3.1]
 [2.1 2.3 3.1 3.2]]

Something like this (NOTE: these will not be the exact numbers). I understand that it may not be possible to interpolate this particular 2D grid, but using the first grid in my answer, an interpolation should be possible during the upsampling process as you are increasing the number of pixels, and can therefore 'fill in the gaps'.

I am not too fussed on the type of interpolation, providing the final output is a smoothed surface! I have tried to use the scipy.interp2d method but to no avail, would be grateful if someone could share their wisdom!



Solution 1:[1]

You can use SciPy interp2d for the interpolation, you can find the documentation here.

I've modified the example from the documentation a bit:

from scipy import interpolate
x = np.array(range(2))
y = np.array(range(2))
a = np.array([[0, 1], [2, 3]])
f = interpolate.interp2d(x, y, a, kind='linear')

xnew = np.linspace(0, 2, 4)
ynew = np.linspace(0, 2, 4)
znew = f(xnew, ynew)

If you print znew it should look like this:

array([[ 0.        ,  0.66666667,  1.        ,  1.        ],
       [ 1.33333333,  2.        ,  2.33333333,  2.33333333],
       [ 2.        ,  2.66666667,  3.        ,  3.        ],
       [ 2.        ,  2.66666667,  3.        ,  3.        ]])

Solution 2:[2]

I would use scipy.misc.imresize:

array = np.arange(0,4,1).reshape(2,2)
from skimage.transform import resize
out = scipy.misc.imresize(array, 2.0)

The 2.0 indicates that I want the output to be twice the dimensions of the input. You could alternatively supply an int or a tuple to specify a percentage of the original dimensions or just the new dimensions themselves.

This is very easy to use, but there is an extra step because imresize rescales everything so that your max value becomes 255 and your min becomes 0. (And it changes the datatype to np.unit8.) You may need to do something like:

out = out.astype(array.dtype) / 255 * (np.max(array) - np.min(array)) + np.min(array)

Let's look at the output:

>>> out.round(2)
array([[0.  , 0.25, 0.75, 1.  ],
       [0.51, 0.75, 1.26, 1.51],
       [1.51, 1.75, 2.26, 2.51],
       [2.  , 2.25, 2.75, 3.  ]])

imresize comes with a deprecation warning and a substitute, though:

DeprecationWarning: imresize is deprecated! imresize is deprecated in SciPy 1.0.0, and will be removed in 1.2.0. Use skimage.transform.resize instead.

Solution 3:[3]

Form resample method in SciPy. Signal you can up-sample your 2d array sequentially in one axis and then the other axis.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 AMA
Solution 2 JellicleCat
Solution 3 Abraham azizi