Ben Chuanlong Du's Blog

It is never too late to learn.

Load Images into Pillow

In [6]:
import numpy as np
from PIL import Image, ImageChops

Image.open

Opens and identifies the given image file. Even though the method Image.open takes a mode argument, it must take the value "r".

Notice that the method Image.open is lazy which means that the image file remains open and the actual image data is not read from the file until needed. This behavior might cause issue sometimes. For example, let's say that you load many images using the following code and try to combine them into one picke file for easy access.

images = [Image.open(path) for path in Path(".").glob("*.png")]

You will likely encouter an error saying "too many files opened" because all image files are opened and not closed. One simple way to fix this problem is to call the method Image.copy to use the underlying image data, which makes the underlying image file closed automatically.

images = [Image.open(path).copy() for path in Path(".").glob("*.png")]

Of course, you can also manually call the method Image.load to load the image data and close the image file.

def read_image(path: Path) -> Image:
    img = Image.open(path)
    img.load()
    return img      


images = [read_image(path) for path in Path(".").glob("*.png")
In [2]:
img = Image.open("../../home/media/poker/4h.png")
img
Out[2]:

Load Corruppted Image

You will encounter "IOError: image file truncated" if an image you try to load is corrupted. However, you can still load the image (and fill the truncated part as black pixles) with the following settings. For more details, please refer to Python PIL “IOError: image file truncated” with big images .

In [ ]:
from PIL import ImageFile

ImageFile.LOAD_TRUNCATED_IMAGES = True

Image.fromarray

  1. When loading a boolean numpy array (representing a black/white image), you can either use mode=None (default, auto detect the mode) or mode="L" (gray scale). Notice that using mode="1" (black/white) doesn't load the numpy array correct (which sounds like a bug to me). It is worth noting that when using mode=None the underlying numpy array for the image is still boolean while when using mode="L" the underlying numpy array is float and the boolean values are converted to 0 or 255.

  2. If you every encounter the error "TypeError: Cannot handle this data type" when loading an image using Image.fromarray, it means that the type of elements in the array is not support and you need to manually cast the type of elments in the numpy array (to numpy.uint8) before calling Image.fromarray on it. It is suggested that you always ensure the data type of a numpy array is the desired one before loading it as an image. If the data type of an numpy array is correct, you do not have to specify a mode (the default works well). Otherwise, if the data type is not correct it might not help even if you try to specify different modes. The most commonly used data types when dealing with images are numpy.uint8 and bool (for black/white images).

     :::python
     import numpy as np
     Imagee.fromarray(arr.astype(np.uint8))
  3. NOTE: Even if Image.fromarray accepts a mode parameter, it seems that the mode BGR;24 doesn't work with Image.fromarray. As an alternative way, you can manually flip a numpy array which is the BGR representation of an image.

     Image.fromarray(np.flip(arr, 2))
In [4]:
arr = np.array(img)
In [5]:
Image.fromarray(arr)
Out[5]:
In [10]:
img_bw = img.convert("1", dither=False)
img_bw
Out[10]:
In [12]:
arr_bw = np.array(img_bw)
arr_bw
Out[12]:
array([[False,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       ...,
       [False,  True,  True, ...,  True,  True,  True],
       [False, False, False, ..., False, False, False],
       [False, False, False, ..., False, False, False]])
In [13]:
Image.fromarray(arr_bw)
Out[13]:
In [16]:
np.array(Image.fromarray(arr_bw))
Out[16]:
array([[False,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       ...,
       [False,  True,  True, ...,  True,  True,  True],
       [False, False, False, ..., False, False, False],
       [False, False, False, ..., False, False, False]])
In [14]:
Image.fromarray(arr_bw, mode="L")
Out[14]:
In [17]:
np.array(Image.fromarray(arr_bw, mode="L"))
Out[17]:
array([[  0, 255, 255, ..., 255, 255, 255],
       [255, 255, 255, ..., 255, 255, 255],
       [255, 255, 255, ..., 255, 255, 255],
       ...,
       [  0, 255, 255, ..., 255, 255, 255],
       [  0,   0,   0, ...,   0,   0,   0],
       [  0,   0,   0, ...,   0,   0,   0]], dtype=uint8)
In [15]:
Image.fromarray(arr_bw, mode="1")
Out[15]:
In [ ]:
 

Comments