Reading the Pillow Docs

I just launched a Flask server where I used the Python Image Library to do some stuff, and I had some trouble initially getting it to work correctly. I quickly read the docs and took some notes so I have a better idea of how the library works / what its capabilities are.

Overview

Pillow is a friendly PIL fork by Jeffrey A Clark and contributors. PIL is the Python Image Library by Fredricj Lundh and contributors. The Python Imaging Library adds image processing capabilities to your Python interpreter. This library provides extensive file format support, an efficient internal representation, and fairly powerful image processing capabilities. The core library is designed for fask access to data stored in a few basic pixel formats. It should provide a solid foundation for a general image processing tool.

Installation

$ python3 -m pip install --upgrade pip
$ python3 -m pip install --upgrade Pillow

Handbook

Overview

The Python Imaging Library adds image processing capabilities to your Python interpreter. This library provides extensive file format support, an efficient internal representation, and fairly powerful image processing capabilities. The core library is designed for fast access to data stored in a few basic pixel formats.

Image Archives

PIL is ideal for image archival and batch processing applications. You can use the library to create thumbnails, convert between file formats, print images, etc. The current version identifies an reads a large number of formats. Write support is intentionally restricted to the most commonly used interchaneg and presentation formats.

Image Processing

The library contains basic image processing functionality, including point operations, filtering with a set of built-in convolution kernels, and color space conversions. The library also supports image resizing, rotation, and arbitrary affine transformations. There are methods to let you pull statistics out of an image.

Tutorial

!pip install pillow
import os
from PIL import Image
path_to_image = os.path.join(os.getcwd(),'Autumn_On _the_Hudson_River.jpg')
im = Image.open(path_to_image)
print(im.format,im.size,im.mode)
display(im) # Jupyter Notebooks built-in method: https://stackoverflow.com/questions/26649716/how-to-show-pil-image-in-ipython-notebook
out[2]

Requirement already satisfied: pillow in /usr/local/lib/python3.10/dist-packages (10.4.0)
JPEG (588, 324) RGB

Jupyter Notebook Image

<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=588x324>

Reading and Writing Images

The PIL supports a wide variety of image formats. To read files from disk, use the open() function in the Image module. The library automatically determined the format based on the contents of the file. To save a file, use the save() method of the Image class. When saving, namesbecome important - the library uses the extension to discover which format to use. You can also provide a second argument to the save() method that specifies the format.

import os, sys
from PIL import Image

for infile in sys.argv[1:]:
  f, e = os.path.splitext(infile)
  outfile = f + ".png"
  if infile != outfile:
    try:
      with Image.open(infile) as im:
        im.save(outfile)
    except OSError:
      print("cannot convert",infile)
out[4]

cannot convert -f
cannot convert /root/.local/share/jupyter/runtime/kernel-55756d89-422d-4254-8f1c-1f6cfdaa4e91.json

When you open a file, teh file header is read to determine the file format and extract things like mode, size, and other properties required to decode the file, but the rest of the file is not processed until later.

Cutting, Pasting, and Merging Images

The Image class provides methods allowing you to manipulate regions within an image - i.e., to extract a rectange, use the crop() method.

box = (0,0,im.size[0],100) # (left, upper, right, lower)
region = im.crop(box)
display(region)
region_new = region.transpose(Image.Transpose.ROTATE_180)
im.paste(region,box)
display(im)
out[6]
Jupyter Notebook Image

<PIL.Image.Image image mode=RGB size=588x100>

Jupyter Notebook Image

<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=588x324>

"""
Merging Images


"""
def merge(im1: Image.Image, im2: Image.Image) -> Image.Image:
    w = im1.size[0] + im2.size[0]
    h = max(im1.size[1], im2.size[1])
    im = Image.new("RGBA", (w, h))

    im.paste(im1)
    im.paste(im2, (im1.size[0], 0))

    return im
out[7]

Spliting and Merging Bands

Note that for a single-band image, split() returns the image itself. To work with individual color bands, you may want to convert the image to "RBG" first.

r, g, b = im.split()
im = Image.merge("RGB", (b,g,r))
display(im)
out[9]
Jupyter Notebook Image

<PIL.Image.Image image mode=RGB size=588x324>

Geometrical Transforms

The PIL.Image.Image class contains methods to resize() and rotate() an image. The former takes a tuple giving the new size, and the latter the angle in degrees counter-clockwise:

You can easily tanspose a width the transpose() method. You can use Image.Transpose.ROTATE_[90|180|270].

im = Image.open(path_to_image)
out = im.resize((128, 128))
display(out)
out = im.rotate(45) # degrees counter-clockwise
display(out)
out[11]
Jupyter Notebook Image

<PIL.Image.Image image mode=RGB size=128x128>

Jupyter Notebook Image

<PIL.Image.Image image mode=RGB size=588x324>

Relative Resizing

Relative Resizing

Color Transforms

PIL allows you to convert images between different pixel representations using the convert() method. The library supports transforms between each supported mode and the "L" and "RBG" modes.

Image Enhacement

There are a number of methods and modules that can be used to enhance images. The ImageFilter module contains a number of pre-defined enhancement filters that can be used with the filter() method.

from PIL import ImageFilter
out = im.filter(ImageFilter.DETAIL)
display(out)
out = im.filter(ImageFilter.BLUR)
display(out)
out = im.filter(ImageFilter.FIND_EDGES)
display(out)
# And Others
out[13]
Jupyter Notebook Image

<PIL.Image.Image image mode=RGB size=588x324>

Jupyter Notebook Image

<PIL.Image.Image image mode=RGB size=588x324>

Jupyter Notebook Image

<PIL.Image.Image image mode=RGB size=588x324>

The point method can be used to translate pixel values of an image. In most cases, a function object expecting one argument can be passed to this method.

out = im.point(lambda x: (x * 6 - 70)  / 2)
display(out)
out[15]
Jupyter Notebook Image

<PIL.Image.Image image mode=RGB size=588x324>

Image Sequences

The PIL library contains some basic support for image sequences (also called animation formats). Supported sequence formats includeFIL/FLC, GIF, and a few experimental formats. When you open a sequence file, PIL automatically loads the first frame in the sequence. You can use the seek and tell methods to move between different frames:

path_to_gif = os.path.join(os.getcwd(),"standard_convolution.gif")
with Image.open("animation.gif") as im:
    im.seek(1)  # skip to the second frame

    try:
        while 1:
            im.seek(im.tell() + 1)
            # do something to im
    except EOFError:
        pass  # end of sequence
out[17]

Other ways to Read Files

  • From a URL
from PIL import Image
from urllib.request import urlopen
url = "https://python-pillow.org/assets/images/pillow-logo.png"
img = Image.open(urlopen(url))
  • From a tar archive
from PIL import Image, TarIO
fp = TarIO.TarIO("hopper.tar", "hopper.jpg")
im = Image.open(fp)
  • From binary data
from PIL import Image
import io
im = Image.open(io.BytesIO(buffer))

Concepts

PIL handles raster images; that is, rectangles of pixel data.

Bands

An image can consist of one or more bands of data. The PIL allows you to store several bands in a single image, provioded they all have the same dimensions and depth - i.e., a PNG image might have 'R', 'G', 'B', and 'A' bands. To get the number and names of bands in an image, use the getbands() method.

Modes

The mode of an image is a string which defines the type and depth of a pixel in the image. Each pixel uses the full range of the bit depth. So a 1-bit pixel has a range of 0-1, an 8-bitpixel has a range of 0-255, a 32-signed integer pixel has the range of INT32 and a 32-bit floating point pixel has the range of FLOAT32. Supported Modes

Size

You can read the image size through the size attribute. This is a 2-tuple, containing the horizontal and vertical size in pixels.

Coordinate System

The PIL uses a Cartesian coordinate system, with (0,0) in the upper left corner. Note that the coordinates refer to the implied pixel corders.

Info

You can attach auxialry information to an image using the info attribute. This is a dictionary object. How much information is handled when loading and saving image files is up to the file format handler.

Transparency

If an image does not have an alpha band, transparency may be specified in the info attribute with a “transparency” key.

Appendices