88

I have about 200 grayscale PNG images stored within a directory like this.

1.png
2.png
3.png
...
...
200.png

I want to import all the PNG images as NumPy arrays. How can I do this?

9 Answers 9

124

According to the doc, scipy.misc.imread is deprecated starting SciPy 1.0.0, and will be removed in 1.2.0. Consider using imageio.v3.imread instead.

Example:

import imageio.v3 as iio

im = iio.imread('my_image.png')
print(im.shape)

You can also use imageio to load from fancy sources:

im = iio.imread('http://upload.wikimedia.org/wikipedia/commons/d/de/Wikipedia_Logo_1.0.png')

Edit:

To load all of the *.png files in a specific folder, you could use the glob package:

import imageio.v3 as iio
import glob

for im_path in glob.glob("path/to/folder/*.png"):
     im = iio.imread(im_path)
     print(im.shape)
     # do whatever with the image here
10
  • 5
    Downvoter, if you could please help me make this answer better by telling me what to improve, it would be very appreciated!
    – Charles
    Commented May 22, 2018 at 21:55
  • I'm not downvoter but the question is to load a list of images in a folder. Can you modify your answer to reflect that, not just 1 - 200.png but what if the png have random names, that would help me a lot. I'm sure I can use os to ls and get the file names but is there a better way? Perhaps you should edit to add glob
    – devssh
    Commented Sep 18, 2018 at 14:23
  • Also, remember to add a try catch as imread may throw ValueError. I don't have privileges to edit or I would have updated it for you. :)
    – devssh
    Commented Sep 18, 2018 at 14:37
  • 4
    The developer should choose if, in this context, the exception should be raised and halt execution or handled in a specific way. Without context, raising is preferred.
    – Charles
    Commented Sep 18, 2018 at 14:42
  • 1
    the doc link is broken
    – liang
    Commented Jun 24, 2021 at 9:18
40

Using just scipy, glob and having PIL installed (pip install pillow) you can use scipy's imread method:

from scipy import misc
import glob

for image_path in glob.glob("/home/adam/*.png"):
    image = misc.imread(image_path)
    print image.shape
    print image.dtype

UPDATE

According to the doc, scipy.misc.imread is deprecated starting SciPy 1.0.0, and will be removed in 1.2.0. Consider using imageio.imread instead. See the answer by Charles.

1
  • Just change to glob.glob("./train/*.png")
    – pbu
    Commented Jul 13, 2015 at 14:53
39

This can also be done with the Image class of the PIL library:

from PIL import Image
import numpy as np

im_frame = Image.open(path_to_file + 'file.png')
np_frame = np.array(im_frame.getdata())

Note: The .getdata() might not be needed - np.array(im_frame) should also work

5
  • 4
    I don't think the .getdata() is even needed. np.array(im_frame) should also work.
    – Rob
    Commented Feb 28, 2020 at 12:21
  • Thanks for the contribution: I added your remark as a comment to my answer for highlighting.
    – mrk
    Commented Mar 4, 2020 at 8:47
  • i had vote up, but .getdata() cause error, so had to use without .getdata() (Rob's method) both code is not same! : raise TypeError('Input type {} is not supported'.format(npimg.dtype)) TypeError: Input type int64 is not supported Commented Apr 7, 2020 at 7:19
  • seems as if you were having an issue with your input type.
    – mrk
    Commented Apr 7, 2020 at 10:38
  • 3
    To get it as RGB use img = np.asarray(Image.open('file.png').convert('RGB'))
    – Brandon
    Commented Mar 1, 2022 at 1:52
30

Using a (very) commonly used package is prefered:

import matplotlib.pyplot as plt
im = plt.imread('image.png')
5
  • 4
    I already have matplotlib imported most of the time, so this has basically no extra cost. Did matplotlib not always have imread or something? What's the advantage of the packages used in other answers?
    – EL_DON
    Commented Jan 30, 2020 at 22:50
  • no advantage. Just a convenience wrapper over pillow (PIL) to sparse one extra line of code.
    – duburcqa
    Commented Mar 31, 2022 at 12:29
  • @milembar as EL_DON mentioned many scripts already have matplotlib imported
    – Nir
    Commented Apr 1, 2022 at 14:36
  • 1
    In the official matplotlib docs, they state: This function exists for historical reasons. It is recommended to use PIL.Image.open instead for loading images.
    – c0mr4t
    Commented Sep 9, 2022 at 20:00
  • 1
    In a tutorial, or for educational purposes, when the main point is not PIL, this is a useful way to abstract away some packaging complexity.
    – Tim D
    Commented Jul 5 at 21:53
8

If you are loading images, you are likely going to be working with one or both of matplotlib and opencv to manipulate and view the images.

For this reason, I tend to use their image readers and append those to lists, from which I make a NumPy array.

import os
import matplotlib.pyplot as plt
import cv2
import numpy as np

# Get the file paths
im_files = os.listdir('path/to/files/')

# imagine we only want to load PNG files (or JPEG or whatever...)
EXTENSION = '.png'

# Load using matplotlib
images_plt = [plt.imread(f) for f in im_files if f.endswith(EXTENSION)]
# convert your lists into a numpy array of size (N, H, W, C)
images = np.array(images_plt)

# Load using opencv
images_cv = [cv2.imread(f) for f in im_files if f.endswith(EXTENSION)]
# convert your lists into a numpy array of size (N, C, H, W)
images = np.array(images_cv)

The only difference to be aware of is the following:

  • opencv loads channels first
  • matplotlib loads channels last.

So a single image that is 256*256 in size would produce matrices of size (3, 256, 256) with opencv and (256, 256, 3) using matplotlib.

5

To read in one image:

import PIL.Image
im = PIL.Image.open('path/to/your/image')
im = np.array(im)

Iterate to read in multiple images.

This answer is similar to this but simpler (no need for .getdata()).

2

I changed a bit and it worked like this, dumped into one single array, provided all the images are of same dimensions.

png = []
for image_path in glob.glob("./train/*.png"):
    png.append(misc.imread(image_path))    

im = np.asarray(png)

print 'Importing done...', im.shape
2
  • 1
    Perfect. Great All-In-One Solution. I had stored images into an np.array, but then ran into trouble as the array had (shape == (num_images,) with each image (shape == (32,32,3)). Your solution (plus im = np.reshape(num_images,32,32,3) works brilliantly! :-) Commented Mar 29, 2017 at 2:15
  • typo: I don't even need the reshape call above. In mine vexed hack, massaging it into that desired shape was getting messy. Thanks for the direct path. Commented Mar 29, 2017 at 2:24
0

I like the build-in pathlib libary because of quick options like directory= Path.cwd() Together with opencv it's quite easy to read pngs to numpy arrays. In this example you can even check the prefix of the image.

from pathlib import Path
import cv2
prefix = "p00"
suffix = ".png"
directory= Path.cwd()
file_names= [subp.name for subp in directory.rglob('*') if  (prefix in subp.name) & (suffix == subp.suffix)]
file_names.sort()
print(file_names)

all_frames= []
for file_name in file_names:
    file_path = str(directory / file_name)
    frame=cv2.imread(file_path)
    all_frames.append(frame)
print(type(all_frames[0]))
print(all_frames[0] [1][1])

Output:

['p000.png', 'p001.png', 'p002.png', 'p003.png', 'p004.png', 'p005.png', 'p006.png', 'p007.png', 'p008.png', 'p009.png']
<class 'numpy.ndarray'>
[255 255 255]
0

If you prefer the standard library:

#IMPORTANT: This Code only works with Python>=3.6
Directory="."#Your directory
import os
import tkinter
import numpy
tk=tkinter.Tk()
tk.overrideredirect(1)
tk.geometry("0x0")
Items=[]
for i in os.listdir(Directory):
    fn=Directory+os.sep+i
    imgArray=[]
    image=tkinter.PhotoImage(file=fn)
    for w in range(image.width()):
        entry=[]
        for h in range(image.height()):
            entry.append(image.get(w,h))
        imgArray.append(entry)
    imgArray=numpy.array(imgArray)
    Items.append(imgArray)
tk.destroy()

Not the answer you're looking for? Browse other questions tagged or ask your own question.