14

I used to use scipy which would load an image from file straight into an ndarray.

from scipy import misc
img = misc.imread('./myimage.jpg')
type(img)
>>> numpy.ndarray

But now it gives me a DeprecationWarning and the docs say it will be removed in 1.2.0. and I should use imageio.imread instead. But:

import imageio
img = imageio.imread('./myimage.jpg')
type(img)
>>> imageio.core.util.Image

I could convert it by doing

img = numpy.array(img)

But this seems hacky. Is there any way to load an image straight into a numpy array as I was doing before with scipy's misc.imread (other than using OpenCV)?

Nic
  • 637
  • 2
  • 6
  • 19

2 Answers2

12

The result of imageio.imread is already a NumPy array; imageio.core.util.Image is an ndarray subclass that exists primarily so the array can have a meta attribute holding image metadata.

If you want an object of type exactly numpy.ndarray, you can use asarray:

array = numpy.asarray(img)

Unlike numpy.array(img), this will not copy img's data.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • Suppose you do this and you end up with two images in that array. How do you get the ith item of that array, meaning a specific image (e.g. the second)? – Sander W. van der Laan Dec 29 '20 at 00:26
  • @SanderW.vanderLaan: The docs say `imread` reads *an* image, so I don't know how you could end up with two. – user2357112 Dec 29 '20 at 02:57
  • Ah yes! Of course! I have this piece of code `for level in args.levels.split(","): if level == 'm': img = fimage.associated_images["macro"] else: level = int(level) img = fimage.read_region((0, 0), level, fimage.level_dimensions[level]) img = np.asarray(img)[:,:, 0:3]` but I was totally not realising the for-loop. So for each item it will produce an image and put it in an array. Weirdly enough you helped me a lot @user2357112-supports-monica! – Sander W. van der Laan Dec 29 '20 at 13:37
0

If it was a bitmap or even jpeg, you can do:

import matplotlib.pyplot as plt
import numpy as np
# 'pip install pillow' but import PIL
from PIL import Image

png_filepath = 'somepng.png'
png_pil_img = Image.open(png_filepath)
# this will print info about the PIL object
print(png_pil_img.format, png_pil_img.size, png_pil_img.mode)
png_np_img = np.asarray(png_pil_img)
plt.imshow(png_np_img) # this will graphit in a jupyter notebook
# or if its grayscale plt.imshow(png_np_img, cmap='gray')
# FWIW, this will show the np characteritics
print("shape is ", png_np_img.shape)
print("dtype is ", png_np_img.dtype)
print("ndim is ", png_np_img.ndim)
print("itemsize is ", png_np_img.itemsize) # size in bytes of each array element
print("nbytes is ", png_np_img.nbytes) # size in bytes of each array element

If you have a jpg, it works the same. PIL.image will decode the compressed JPG, and convert it to an array for you. Literally it will do all this for you. Perhaps you could load the raw bitmap with file io skipping the header, yadda yadda, but PIL is popular for a reason.

The output for a grayscale png will look like this:

PNG (3024, 4032) L
shape is  (4032, 3024)
dtype is  uint8
ndim is  2
itemsize is  1
nbytes is  12192768

The output for a color jpeg will look like this:

JPEG (704, 480) RGB
shape is  (480, 704, 3)
dtype is  uint8
ndim is  3
itemsize is  1
nbytes is  1013760

In either case, the pixel values range 0-255 as ints. They are not floats. The color image has three channels corresponding to red green and blue. The grayscale image is much greater resolution and the jpg.

netskink
  • 4,033
  • 2
  • 34
  • 46