Quick Way to Upsample Numpy Array by Nearest Neighbor Tiling

Quick way to upsample numpy array by nearest neighbor tiling

One option is

>>> a.repeat(2, axis=0).repeat(2, axis=1)
array([[0, 0, 1, 1, 2, 2],
[0, 0, 1, 1, 2, 2],
[3, 3, 4, 4, 5, 5],
[3, 3, 4, 4, 5, 5],
[6, 6, 7, 7, 8, 8],
[6, 6, 7, 7, 8, 8]])

This is slightly wasteful due to the intermediate array but it's concise at least.

How to repeat a numpy array on both axis?

You can do it with the kronicker product, np.kron and a ones array of the size of the block.

a = np.arange(6).reshape(2,3) + 1
np.kron(a, np.ones((3,3), dtype = a.dtype))

Out[]:
array([[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3],
[4, 4, 4, 5, 5, 5, 6, 6, 6],
[4, 4, 4, 5, 5, 5, 6, 6, 6],
[4, 4, 4, 5, 5, 5, 6, 6, 6]])

How to upsample an array to arbitrary sizes?

Without a clear idea about the final result you would like to achieve, your question opens multiple paths and solutions. Just to name a few:

  1. Using numpy.resize:
import numpy as np

input_array=np.array([[1.,2],[3,4]])

np.resize(input_array, (3,3))

you get:

array([[1., 2., 3.],
[4., 1., 2.],
[3., 4., 1.]])

  1. Using cv2.resize:
import cv2
import numpy as np

input_array=np.array([[1.,2],[3,4]])

cv2.resize(input_array,
(3,3),
interpolation=cv2.INTER_NEAREST)

you get:

array([[1., 1., 2.],
[1., 1., 2.],
[3., 3., 4.]])

Depending on your objective, you can use different interpolation methods.

Creating a block array from a given array

A.repeat(2, axis=1).repeat(2, axis=0)

First repeat the elements along the first axis to get:

array([[1, 1, 2, 2, 3, 3],
[4, 4, 5, 5, 6, 6],
[7, 7, 8, 8, 9, 9]])

Then repeat the elements along the zeroth axis to get:

array([[1, 1, 2, 2, 3, 3],
[1, 1, 2, 2, 3, 3],
[4, 4, 5, 5, 6, 6],
[4, 4, 5, 5, 6, 6],
[7, 7, 8, 8, 9, 9],
[7, 7, 8, 8, 9, 9]])

(The order of repetition axes doesn't matter.)

You can change 2s to the desired block size.

How to inflate an array in numpy?

Consider using numpy.kron - the Kronecker product of two matrices. The first matrix will be the original one that you have, and second matrix is simply a 3 x 3 np.ones array:

In [3]: import numpy as np

In [4]: A = np.array([[0, 1], [2, 3]])

In [5]: B = np.kron(A, np.ones((3, 3), dtype=A.dtype))

In [6]: B
Out[6]:
array([[ 0., 0., 0., 1., 1., 1.],
[ 0., 0., 0., 1., 1., 1.],
[ 0., 0., 0., 1., 1., 1.],
[ 2., 2., 2., 3., 3., 3.],
[ 2., 2., 2., 3., 3., 3.],
[ 2., 2., 2., 3., 3., 3.]])

Note that I'm ensuring that the output matrix B respects the original type of data that A was created with. I'm not sure what type your original matrix was, so I've put that in to respect whatever the type was originally so I've made sure to create the ones matrix to respect the same type as A to ensure that B also conforms to the same type.

In general, to create a N x N repeated tile of each element in your input matrix, change the 3 in the np.ones call to N.

Expanding a matrix

Since what you're describing is the Kronecker product:

Use np.kron

Computes the Kronecker product, a composite array made of blocks of the second array scaled by the first.

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

np.kron(x, np.ones((3, 3)))

array([[1., 1., 1., 0., 0., 0., 0., 0., 0.],
[1., 1., 1., 0., 0., 0., 0., 0., 0.],
[1., 1., 1., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 1., 1., 1., 1., 1., 1.],
[0., 0., 0., 1., 1., 1., 1., 1., 1.],
[0., 0., 0., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 0., 0., 0.],
[1., 1., 1., 1., 1., 1., 0., 0., 0.],
[1., 1., 1., 1., 1., 1., 0., 0., 0.]])


Related Topics



Leave a reply



Submit