Velcorn
Velcorn

Reputation: 60

Getting rid of for loops in Python with Numpy

So, I have the following code for resizing an image using nearest neighbor interpolation. The solution seems straightforward to me using 2 for loops, but I can't think of any way to do this while taking advantage of numpy to avoid those pesky loops. Here is my code:

def scale(img, factor):
    # Calculate new image shape and create new image with it.
    height, width = img.shape[:2]
    new_height, new_width = (int(height * factor), int(width * factor))[:2]
    scaled_img = np.zeros([new_height, new_width])

    # Iterate over all pixels and set their values based on the input image.
    for x in range(new_height):
        for y in range(new_width):
            scaled_img[x, y] = img[int(x / factor), int(y / factor)]

    return scaled_img

Any input on how to avoid the for loops?

Upvotes: 0

Views: 155

Answers (3)

Richard
Richard

Reputation: 3394

While the first answer is really great from a "how do I do this in numpy" point of view, I'd second Nils L's answer: if what you're wanting to do is resize an image, then you're likely much better off using one of the image processing libraries.

Pillow works well, as does ndimage: http://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.zoom.html#scipy.ndimage.zoom

Both will likely be faster than numpy, and also give you a lot more options in the details of how you want the resizing to work, and let you do different interpolation methods if that's what you need.

Upvotes: 0

V. Ayrat
V. Ayrat

Reputation: 2719

You can calculate the mapping of indices of new image to old indices and then use numpy.ix_ to unite them

import numpy as np

def scale(img, factor):
    """
    >>> img = np.arange(9).reshape(3, 3)
    >>> print(img)
    [[0 1 2]
     [3 4 5]
     [6 7 8]]
    >>> print(scale(img, 1.67))
    [[0 0 1 1 2]
     [0 0 1 1 2]
     [3 3 4 4 5]
     [3 3 4 4 5]
     [6 6 7 7 8]]
    """
    x_indices = (np.arange(int(img.shape[1] * factor)) / factor).astype(int) # [0 0 1 1 2]
    y_indices = (np.arange(int(img.shape[0] * factor)) / factor).astype(int)
    return img[np.ix_(y_indices, x_indices)]

Upvotes: 2

Nils L.
Nils L.

Reputation: 776

I would avoid writing this code entirely and use the Pillow image processing library to resize the image. Not sure about the performance, but I would think they would have optimized such basic tasks quite well.

Upvotes: 2

Related Questions