Pillow: Resize images while loading into Python using Pillow

Created on 18 Sep 2018  路  7Comments  路  Source: python-pillow/Pillow

What did you do?

Hi: I would like load some 2400 images from a folder into python 3.6 for Neural Networks, the following code works, however, it loads images in its original size, which is (2443, 320, 400, 3), after converting into an array. How do I resize it to 64x96? so it is (2443, 64, 96, 3) and less of a load on memory. I tried two different ways, as written below.:

# this works, however it uploads images in its original size which is 320x400.

IMAGE_PATH = 'drive/xyz/data/'
file_paths = glob.glob(path.join(IMAGE_PATH, '*.gif'))

# Load the images
images = [misc.imread(path) for path in file_paths]
images = np.asarray(images)

Inspired by this link, I tried to do the following:

from PIL import Image

basewidth = 96
IMAGE_PATH = 'drive/xyz/data/' 
file_paths = glob.glob(path.join(IMAGE_PATH, '*.gif'))

# Load the images img = [misc.imread(path) for path in file_paths]

wpercent = (basewidth/float(img.size[0])) 
hsize = int((float(img.size[1])*float(wpercent))) 
img = img.resize((basewidth,hsize), Image.ANTIALIAS) 
images = np.asarray(img)

What did you expect to happen?

Convert the 2400 images to numpy array, of size (2443, 64, 96, 3) so that I can further process it for autoencoders.

What actually happened?

The first code manages to upload all the images in its current size, which is (2443, 320, 400, 3).

The error for the second code:

AttributeError                            Traceback (most recent call last)
<ipython-input-7-56ac1d841c56> in <module>()
      9 img = [misc.imread(path) for path in file_paths]
     10 
---> 11 wpercent = (basewidth/float(img.size[0]))
     12 hsize = int((float(img.size[1])*float(wpercent)))
     13 img = img.resize((basewidth,hsize), Image.ANTIALIAS)

AttributeError: 'list' object has no attribute 'size'

What versions of Pillow and Python are you using?

I just added the package, thus, it must be the latest package. Thank you very much. Highly appreciate it.

Question

All 7 comments

First, img is a list of images, and not an image, so you can't call .size to get the width and height on the list.

Second, each "image" in the list isn't a Pillow image, but is actually an array as returned by scipy.misc.imread. So you can't call .size or .resize on that either.

One way is to proceed is to (1) load the images as Pillow images, then (2) resize them using Pillow, and then (3) convert them into the array format needed.

Here's (1) and (2), with (3) left as an exercise.

This assumes the input images are all the same size, because it makes calculations using the first image in the list, imgs[0].

import glob
from os import path

from PIL import Image

basewidth = 96
IMAGE_PATH = 'drive/xyz/data/' 
file_paths = glob.glob(path.join(IMAGE_PATH, '*.gif'))

# Load the images
imgs = [Image.open(path) for path in file_paths]

wpercent = (basewidth/float(imgs[0].size[0]))
hsize = int((float(imgs[0].size[1])*float(wpercent)))
imgs = [img.resize((basewidth,hsize), Image.ANTIALIAS) for img in imgs]

# imgs is now a list of resized Pillow images
print(imgs)

# TODO: convert into array

Hi @hugovk, I managed to get it almost right below. There's one final issue: how do I change the shape from (2443, 96, 120) to (2443, 96, 120,3)? Thank you very much.

update: it is fixed now. Thanks. Sorry about that.

import glob
from os import path
from PIL import Image
import numpy as np

basewidth = 120
IMAGE_PATH = 'drive/xyz/data/'
file_paths = glob.glob(path.join(IMAGE_PATH, '*.gif'))

# Load the images
imgs = [Image.open(path) for path in file_paths]

wpercent = (basewidth/float(imgs[0].size[0]))
print(wpercent)
hsize = int((float(imgs[0].size[1])*float(wpercent)))
imgs = [img.resize((basewidth,hsize), Image.ANTIALIAS) for img in imgs]
images = np.array([np.array(img) for img in imgs])

print(np.shape(images))

# imgs is now a list of resized Pillow images
print(imgs)

I tried the following, it did not work.

x = np.expand_dims(images, axis=0)
x.shape

(1, 2443, 96, 120)

Hi, I fixed it as followed. Thanks!

images = np.array([image.img_to_array(img) for img in imgs])

Hi @hugovk , I had colored images. However, it is turning into black and white. How do I change from (2443, 96, 120, 1) to (2443, 96, 120, 3) to account for RGB? Thank you.

Hi @hugovk, when you have time, would you be able to write why the second code which you helped me out with changes number of channels from 3 (RGB) to 1 (grayscale). And how to get back (2443, 96, 120, 3) instead of (2443, 96, 120, 1). These are heatmaps, I will lose out info, if I convert them them grayscale. Thank you so much. Sorry to bother you.

# this code generated a numpy array of  2443x320x400x3.

IMAGE_PATH = 'drive/xyz/data/'
file_paths = glob.glob(path.join(IMAGE_PATH, '*.gif'))

# Load the images
images = [misc.imread(path) for path in file_paths]
images = np.asarray(images)

While this one does (2443, 96, 120, 1)

import glob
from os import path
from PIL import Image
import numpy as np
from keras.preprocessing import image 

basewidth = 120
IMAGE_PATH = 'drive/xyz/data/'
file_paths = glob.glob(path.join(IMAGE_PATH, '*.gif'))

# Load the images
imgs = [Image.open(path) for path in file_paths]

wpercent = (basewidth/float(imgs[0].size[0]))
print(wpercent)
hsize = int((float(imgs[0].size[1])*float(wpercent)))
imgs = [img.resize((basewidth,hsize), Image.ANTIALIAS) for img in imgs]
images = np.array([image.img_to_array(img) for img in imgs])

print(np.shape(images))

# imgs is now a list of resized Pillow images
print(imgs)

The first array must be number-of-images x width x height x rgb.

The second must be number-of-images x width x height x mono.

It could be that your images are P mode: "8-bit pixels, mapped to any other mode using a color palette", and RGB would be better: "3x8-bit pixels, true color".

https://pillow.readthedocs.io/en/5.2.x/handbook/concepts.html#modes

Here's a demo:

>>> from PIL import Image
>>> import numpy as np

>>> im = Image.open("hopper.gif")
>>> im.show()  # Confirm it's colour
>>> print(im)
<PIL.Image.Image image mode=P size=120x120 at 0x11100C6A0>

>>> # Convert to array
>>> im2arr = np.array(im)
>>> print(np.shape(im2arr))
(120, 120)

>>> # Convert array back to image
>>> arr2im = Image.fromarray(im2arr)
>>> arr2im.show()  # It's now greyscale :(

>>> # Instead, let's convert the image to RGB first
>>> im2 = im.convert("RGB")
>>> im2.show()  # Confirm it's colour
>>> print(im2)
<PIL.Image.Image image mode=RGB size=120x120 at 0x111020C18>

>>> # Convert to array
>>> im2arr2 = np.array(im2)
>>> print(np.shape(im2arr2))
(120, 120, 3)

>>> # Convert array back to image
>>> arr2im2 = Image.fromarray(im2arr2)
>>> arr2im2.show()  # It's colour :)

So perhaps something like this:

imgs = [img.resize((basewidth,hsize), Image.ANTIALIAS) for img in imgs]
imgs = [img.convert("RGB") for img in imgs]
images = np.array([np.array(img) for img in imgs])

print(imgs)
# [<PIL.Image.Image image mode=RGB size=120x120 at 0x111020FD0>, <PIL.Image.Image image mode=RGB size=120x120 at 0x111035080>]
print(np.shape(images))
# (2, 120, 120, 3)

Hi @hugovk that worked very well. Thank you. I will go through this: https://pillow.readthedocs.io/en/5.2.x/handbook/concepts.html#modes

Was this page helpful?
0 / 5 - 0 ratings

Related issues

naaaargle picture naaaargle  路  3Comments

HansHirse picture HansHirse  路  3Comments

thinrhino picture thinrhino  路  3Comments

indirectlylit picture indirectlylit  路  4Comments

Larivact picture Larivact  路  4Comments