DEV Community

Cover image for Pillow, the python image manipulation module
Ali Sherief
Ali Sherief

Posted on

Pillow, the python image manipulation module

You know there are ways to edit images online. Maybe you just want to caption it, or crop or rescale it. Up until now you only knew of online tools and standalone programs that were able to do this. Maybe you were relying on Photoshop for a long time to edit an image.

But anyone who has a bunch of images can tell you how difficult it is to find a program to edit a bunch of images at once, the so-called "batch editing". So instead of trying to find a tool that does that, it may be worthwhile to write a script in a programming language that you know.

In Python there is a package called Pillow that can manipulate several image types programmatically. Pillow is a fork of a now-abandoned package called PIL. Pillow runs on both Python 3 and 2, but given that Python 2 is unsupported now you probably should consider migrating.

Installation

Usualy, pip3 install Pillow should do the trick. Although I have experienced some cases where you can't open any image file with Pillow because it throws an exception. If this happens it's probably because Pillow wasn't compiled with support for that image format, and you should compile pillow yourself. But this problem doesn't appear on Windows.

Operating system distribution-provided installations of Pillow should work out of the box, but I have not verified this.

I should also mention that you can't have PIL and Pillow installed in the same python environment, which could be a venv or a literal python installation. They are incompatible with each other. But you won't run into this problem on Python 3 because PIL was never ported to Python 3.

Usage

Quick and dirty now, to open an image, you use the Image.open() function.

>>> from PIL import Image
>>> im = Image.open("lena.ppm")
Enter fullscreen mode Exit fullscreen mode

This returns a handle to an image. Inside im.format is a human-readable extension name for the file type, something like PPM. im.size is a tuple with width and height elements, like (512, 512). im.mode contains the color system used in the image, such as RGB or CMYK.

To display the image, you could use im.show(). This uses the xv program to display the image on the screen so if you don't have that installed, then this method won't work. Admittingly, I haven't even heard of xv before this so this is as far as I will cover it in this article.

show() is mainly useful for testing and debugging purposes, but you should use the im.save("pathfilename") method to save the read image somewhere so that you can open it with any image viewer.

Effects

A non-exhaustive list of operations that you can perform on Pillow images is:

  • Creating thumbnails
  • Cropping
  • Pasting regions of image elsewhere
  • Rotating regions of images
  • Resizing
  • Flipping regions of images
  • General transformations
  • Color mode conversion
  • Per-pixel color manipulations
  • Processing individual color bands (such as red)
  • Enhancing image contrast and brightness
  • Operating on each GIF frame independently

So you see, it's very powerful, if you can get the images to open that is. And as I said earlier, compiling from source usually solves these problems. Pillow has to link with a few C libraries and so that's where the compilation kicks in - it links the libraries with the main Pillow code written in C that has Python bindings.

I will go over the most common operations one by one. The Pillow documentation is an excellent place to learn the more advanced operations.

Also I'm more of the "learn by example" kind of person so you'll be seeing more examples here than explanations of what they do. Where things are unclear I will clarify them though.

All of these snippets assume you import Image first: from PIL import Image. If you are getting errors such as Image is not defined, you need to run the aforementioned command to import it.

Creating thumbnails

Thumbnails are stored inside the image file, not separately. They are the small pictures you see in file managers.

import os, sys
from PIL import Image

size = (128, 128)

for infile in sys.argv[1:]:
    outfile = os.path.splitext(infile)[0] + ".thumbnail"
    if infile != outfile:
        try:
            im = Image.open(infile)
            im.thumbnail(size)         # This creates the thumbnal.
            im.save(outfile, "JPEG")
        except IOError:
            print("cannot create thumbnail for", infile)
Enter fullscreen mode Exit fullscreen mode

Cropping

The crop() method also returns an Image object.

box = (100, 100, 400, 400)
region = im.crop(box)
Enter fullscreen mode Exit fullscreen mode

Pasting

Likewise, it's also possible to paste an Image object on another one using the paste() method.

im.paste(region, box)
Enter fullscreen mode Exit fullscreen mode

Rotating and flipping

As a general rule, methods do not modify the input image. They return the modified image as the output. And, rotating and flipping is accomplished by using the transpose() function. It may sound like an odd name considering the purpose of it, but you can pass a value such as Image.ROTATE_180 to direct it to do the corresponding operation.

region = region.transpose(Image.ROTATE_180)
# Transforms it again
region = region.transpose(Image.FLIP_LEFT_RIGHT)
Enter fullscreen mode Exit fullscreen mode

You can also use rotate() to rotate the image at an arbitrary amount of degrees.

out = im.rotate(45) # degrees counter-clockwise
Enter fullscreen mode Exit fullscreen mode

Resizing

Tuple is specified as (width, height).

out = im.resize((128, 128))
Enter fullscreen mode Exit fullscreen mode

Getting the image bands

All images are composed of red, green and blue values. You can retrieve each of them separately from an image by calling the split() function. When you're done modifying them individually, you can call the merge() function to put them back together.

r, g, b = im.split()
# ...

# Adjust the red values, the green values and blue values

# ...
im = Image.merge("RGB", (b, g, r))
Enter fullscreen mode Exit fullscreen mode

Color mode conversion

You can convert any color mode to RGB and vice versa. You can also convert any color mode to L (the grayscale mode) and vice versa.

# PPM is not a color mode, it's an image format (way the image is stored on disk)
im = Image.open("lena.ppm")

# Convert this PPM-file-format image to grayscale
im.convert("L")
Enter fullscreen mode Exit fullscreen mode

Applying filters to images

A filter is a post-processing effect that is added to the image to make it look different. There are several filters in Pillow. All of them are in the ImageFilter module, not the Image module, so you need to import ImageFilter from PIL to use them.

  • BLUR
  • CONTOUR
  • DETAIL
  • EDGE_ENHANCE
  • EDGE_ENHANCE_MORE
  • EMBOSS
  • FIND_EDGES
  • SMOOTH
  • SMOOTH_MORE
  • SHARPEN

Use the filters like this:

from PIL import ImageFilter
im1 = im.filter(ImageFilter.BLUR)  # Blurs the image
Enter fullscreen mode Exit fullscreen mode

Per-point manipulation

You can pass a function to the point() method that takes a single number as input and applies a math expression to it.

# multiply each pixel by 1.2
# This example indiscriminately adjusts the red, green and blue values. See below to modify them individually.
out = im.point(lambda i: i * 1.2)
Enter fullscreen mode Exit fullscreen mode

One of the benefits of having split() and merge() is they can be used in situations like this, where an image is expected by the point() function, but you can pass three different images with each color band so you can run those images/color-bands through three different functions. A function that does that would look something like this:

# split the image into individual bands
source = im.split()

R, G, B = 0, 1, 2

# select regions where red is less than 100
mask = source[R].point(lambda i: i < 100 and 255)

# process the green band
out = source[G].point(lambda i: i * 0.7)

# paste the processed band back, but only where red was < 100
source[G].paste(out, None, mask)

# build a new multiband image
im = Image.merge(im.mode, source)
Enter fullscreen mode Exit fullscreen mode

Image enhancement

You can use the ImageEnhancement module to give your images more contrast, brightness, or sharpness, or change the color balance. It is not a substitute for careful and accurate drawing, however.

Each of the items in ImageEnhancement is a class that takes an image in the constructor, and contains a method to return a modified version of the image. Currently the classes are:

  • PIL.ImageEnhance.Color(image)
  • PIL.ImageEnhance.Contrast(image)
  • PIL.ImageEnhance.Brightness(image)
  • PIL.ImageEnhance.Sharpness(image)

They all have an enhance() method that takes a single number as its argument.

from PIL import ImageEnhance

enh = ImageEnhance.Contrast(image)
enh.enhance(1.3).show("30% more contrast")

enhancer = ImageEnhance.Sharpness(image)

for i in range(8):
    factor = i / 4.0
    enhancer.enhance(factor).show("Sharpness %f" % factor)
Enter fullscreen mode Exit fullscreen mode

Neat example

This examples were taken from the documentation. It moves an image to the left, putting the end of the image on the right.

def roll(image, delta):
    "Roll an image sideways"

    xsize, ysize = image.size

    delta = delta % xsize
    if delta == 0: return image

    part1 = image.crop((0, 0, delta, ysize))
    part2 = image.crop((delta, 0, xsize, ysize))
    image.paste(part2, (0, 0, xsize-delta, ysize))
    image.paste(part1, (xsize-delta, 0, xsize, ysize))

    return image
Enter fullscreen mode Exit fullscreen mode

And we're done

I'm never perfect, but in this particular article I'm dependent on what I see in the documentation, having failed to get Pillow running, which means there is a higher chance that errors have cropped up (no pun intended) in this article. so if you spot errors, let me know in the comments so I can correct them.

Image by PublicDomainPictures from Pixabay

Top comments (1)

Collapse
 
andrewkeyboardwarrior profile image
Andrew Gibson

I played with this Pillow library to do some automatic photo comparison hobby project, it can also help with preparing the image for OCR, by making it black-and-white and more sharp.