10

I have the following array:

import numpy as np
a = np.array([[2, 3, 5],
              [4, 6, 7],
              [1, 5, 7]])

I want to expand it to this array:

b = [[2 2 2 3 3 3 5 5 5]
     [2 2 2 3 3 3 5 5 5]
     [2 2 2 3 3 3 5 5 5]
     [4 4 4 6 6 6 7 7 7]
     [4 4 4 6 6 6 7 7 7]
     [4 4 4 6 6 6 7 7 7]
     [1 1 1 5 5 5 7 7 7]
     [1 1 1 5 5 5 7 7 7]
     [1 1 1 5 5 5 7 7 7]]

So I'm using the following command:

import scipy.ndimage
b = scipy.ndimage.interpolation.zoom(a, 3, order=0)

based on this question and answer here Resampling a numpy array representing an image.

However, what I'm getting is this:

b = [[2 2 3 3 3 3 5 5 5]
     [2 2 3 3 3 3 5 5 5]
     [4 4 6 6 6 6 7 7 7]
     [4 4 6 6 6 6 7 7 7]
     [4 4 6 6 6 6 7 7 7]
     [4 4 6 6 6 6 7 7 7]
     [1 1 5 5 5 5 7 7 7]
     [1 1 5 5 5 5 7 7 7]
     [1 1 5 5 5 5 7 7 7]]

I want the expansion to be exactly by 3, or whatever the zoom factor is, but currently it's different for each element of the array.

Is there a direct way to do this? Or shall I do it manually with some coding?

MSeifert
  • 145,886
  • 38
  • 333
  • 352
philippos
  • 1,142
  • 5
  • 20
  • 41

3 Answers3

14

Maybe a little late, but for the sake of completness: Numpy Kron does the job perfectly

>>> import numpy as np
>>> a = np.array([[2,3,5], [4,6,7], [1,5,7]])
>>> np.kron(a, np.ones((3,3)))
array([[ 2.,  2.,  2.,  3.,  3.,  3.,  5.,  5.,  5.],
       [ 2.,  2.,  2.,  3.,  3.,  3.,  5.,  5.,  5.],
       [ 2.,  2.,  2.,  3.,  3.,  3.,  5.,  5.,  5.],
       [ 4.,  4.,  4.,  6.,  6.,  6.,  7.,  7.,  7.],
       [ 4.,  4.,  4.,  6.,  6.,  6.,  7.,  7.,  7.],
       [ 4.,  4.,  4.,  6.,  6.,  6.,  7.,  7.,  7.],
       [ 1.,  1.,  1.,  5.,  5.,  5.,  7.,  7.,  7.],
       [ 1.,  1.,  1.,  5.,  5.,  5.,  7.,  7.,  7.],
       [ 1.,  1.,  1.,  5.,  5.,  5.,  7.,  7.,  7.]])
thilo_dual
  • 158
  • 1
  • 7
  • 2
    Never late! To be fair, this answer is more complete and easier to implement than the answer by @MSeifert . That answer worked perfect for a 2D array, however, I found difficulties applying it on my 3D array. Another good point about your answer, is that you can decide the expansion value on each dimension separately, and that's in the case where you don't want to expand the array in all direction by the same value. For the moment I would definitely say: this is the answer. – philippos Aug 31 '17 at 05:19
  • 1
    could you specify or give an example what you meant by "I found difficulties applying it on my 3D array"? – thilo_dual Sep 17 '17 at 11:05
  • 2
    You'll want to use something like `np.kron(a, np.ones((4,4,1)))` with an optional `.astype(np.uint8)` as a suffix since kron automatically returns an array of floats. – chenjesu Nov 11 '19 at 08:29
1

I don't know if there's a function that does exactly what you want in NumPy or SciPy but it's easy to create one yourself:

from __future__ import division
import numpy as np

def zoom(a, factor):
    a = np.asarray(a)
    slices = [slice(0, old, 1/factor) for old in a.shape]
    idxs = (np.mgrid[slices]).astype('i')
    return a[tuple(idxs)]

It gives the expected result:

>>> a = [[2,3,5], [4,6,7], [1,5,7]]

>>> zoom(a,3)
array([[2, 2, 2, 3, 3, 3, 5, 5, 5],
       [2, 2, 2, 3, 3, 3, 5, 5, 5],
       [2, 2, 2, 3, 3, 3, 5, 5, 5],
       [4, 4, 4, 6, 6, 6, 7, 7, 7],
       [4, 4, 4, 6, 6, 6, 7, 7, 7],
       [4, 4, 4, 6, 6, 6, 7, 7, 7],
       [1, 1, 1, 5, 5, 5, 7, 7, 7],
       [1, 1, 1, 5, 5, 5, 7, 7, 7],
       [1, 1, 1, 5, 5, 5, 7, 7, 7]])

I haven't tested it for all factors and shapes, maybe that approach could have trouble because of floating point accuracy (the step argument in the slices).

MSeifert
  • 145,886
  • 38
  • 333
  • 352
  • 1
    That is exactly what I wanted! Thanks. I am still not familiar with `slice` and `np.ngrid` so I would have solved it in completely different way according to my current knowledge, but your function did exactly what I wanted. I tested it for non-square shaped, float array, and it worked perfect. – philippos Jul 11 '17 at 12:24
1

Here is my approach, which uses simple numpy functions. It returns the same dtype as the input.

import numpy as np

def zoom(a, factor):
    sx, sy = (factor * dim for dim in a.shape)
    X, Y = np.ogrid[0:sx, 0:sy]
    return a[X//factor, Y//factor]
Mike T
  • 41,085
  • 18
  • 152
  • 203