Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rescale a numpy array

I have a 2D numpy array that represents a monochrome image from a CCD that has been binned 3x3 (that is, each value in the array represents 9 pixels (3x3) on the physical CCD).

I want to rescale it to match the original CCD layout (so I can easily overlay it with a non-binned image from the same CCD).

I saw Resampling a numpy array representing an image, but that doesn't seem to do what I want.

Suppose I have an array g:

import numpy as np
import scipy.ndimage

 g = np.array([[0, 1, 2],
               [3, 4, 5],
               [6, 7, 8]])

When I try to scale it by a factor of 2:

o = scipy.ndimage.zoom(g, 2, order=0)

I get exactly what I expect - each value is now 2x2 identical values:

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]])

But when I try to scale by a factor of 3, I get this:

o = scipy.ndimage.zoom(g, 3, order=0)

Gives me:

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

I wanted each value in the original array to become a set of 3x3 values...that's not what I get.

How can I do it? (And why do I get this unintuitive result?)

like image 637
nerdfever.com Avatar asked Sep 04 '14 22:09

nerdfever.com


People also ask

How do I resize an array in NumPy?

With the help of Numpy numpy. resize(), we can resize the size of an array. Array can be of any shape but to resize it we just need the size i.e (2, 2), (2, 3) and many more. During resizing numpy append zeros if values at a particular place is missing.

Can NumPy array size be changed?

Size of a numpy array can be changed by using resize() function of the NumPy library. refcheck- It is a boolean that checks the reference count. It checks if the array buffer is referenced to any other object.

How do I rescale an image in NumPy?

While it might be possible to use numpy alone to do this, the operation is not built-in. That said, you can use scikit-image (which is built on numpy) to do this kind of image manipulation. Scikit-Image rescaling documentation is here. This will take care of things like interpolation, anti-aliasing, etc.

What is the difference between reshape () and resize ()?

reshape() and numpy. resize() methods are used to change the size of a NumPy array. The difference between them is that the reshape() does not changes the original array but only returns the changed array, whereas the resize() method returns nothing and directly changes the original array.


1 Answers

You can use np.kron:

In [16]: g
Out[16]: 
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

In [17]: np.kron(g, np.ones((3,3), dtype=int))
Out[17]: 
array([[0, 0, 0, 1, 1, 1, 2, 2, 2],
       [0, 0, 0, 1, 1, 1, 2, 2, 2],
       [0, 0, 0, 1, 1, 1, 2, 2, 2],
       [3, 3, 3, 4, 4, 4, 5, 5, 5],
       [3, 3, 3, 4, 4, 4, 5, 5, 5],
       [3, 3, 3, 4, 4, 4, 5, 5, 5],
       [6, 6, 6, 7, 7, 7, 8, 8, 8],
       [6, 6, 6, 7, 7, 7, 8, 8, 8],
       [6, 6, 6, 7, 7, 7, 8, 8, 8]])

The output of zoom(g, 3, order=0) is a bit surprising. Consider the first row: [0, 0, 1, 1, 1, 1, 2, 2, 2]. Why are there four 1s?

When order=0 zoom (in effect) computes np.linspace(0, 2, 9), which looks like

In [80]: np.linspace(0, 2, 9)
Out[80]: array([ 0.  ,  0.25,  0.5 ,  0.75,  1.  ,  1.25,  1.5 ,  1.75,  2.  ])

and then rounds the values. If you use np.round(), you get:

In [71]: np.round(np.linspace(0, 2, 9)).astype(int)
Out[71]: array([0, 0, 0, 1, 1, 1, 2, 2, 2])

Note that np.round(0.5) gives 0, but np.round(1.5) gives 2. np.round() uses the "round half to even" tie-breaking rule. Apparently the rounding done in the zoom code uses the "round half down" rule: it rounds 0.5 to 0 and 1.5 to 1, as in the following

In [81]: [int(round(x)) for x in np.linspace(0, 2, 9)]
Out[81]: [0, 0, 1, 1, 1, 1, 2, 2, 2]

and that's why there are four 1s in there.

like image 167
Warren Weckesser Avatar answered Sep 30 '22 09:09

Warren Weckesser