An Intro to the Python Imaging Library / Pillow

The Python Imaging Library or PIL allowed you to do image processing in Python. The original author, Fredrik Lundh, wrote one of my favorite Python blogs when I first started learning Python. However PIL’s last release was way back in 2009 and the blog also stopped getting updated. Fortunately, there were some other Python folks that came along and forked PIL and called their project Pillow. The Pillow project is a drop-in replacement for PIL that also supports Python 3, something PIL never got around to doing.

Please note that you cannot have both PIL and Pillow installed at the same time. There are some warnings in their documentation that list some differences between PIL and Pillow that get updated from time to time, so I’m just going to direct you there instead of repeating them here since they will likely become out of date.


Install Pillow

You can install Pillow using pip or easy_install. Here’s an example using pip:

pip install Pillow

Note that if you are on Linux or Mac, you may need to run the command with sudo.


Opening Images

jelly

Pillow makes it easy to open an image file and display it. Let’s take a look:

from PIL import Image
 
image = Image.open('/path/to/photos/jelly.jpg')
image.show()

Here we just import the Image module and ask it to open our file. If you go and read the source, you will see that on Unix, the open method saves the images to a temporary PPM file and opens it with the xv utility. On my Linux machine, it opened it with ImageMagick, for example. On Windows, it will save the image as a temporary BMP and open it in something like Paint.


Getting Image Information

You can get a lot of information about an image using Pillow as well. Let’s look at just a few small examples of what we can extract:

>>> from PIL import Image
>>> image = Image.open('/path/to/photos/jelly.jpg')
>>> r, g, b = image.split()
>>> histogram = image.histogram()
[384761, 489777, 557209, 405004, 220701, 154786, 55807, 35806, 21901, 16242]
>>> exif = image._getexif()
exif
{256: 1935,
 257: 3411,
 271: u'Panasonic',
 272: u'DMC-LX7',
 274: 1,
 282: (180, 1),
 283: (180, 1),
 296: 2,
 305: u'PaintShop Pro 14.00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
 306: u'2016:08:21 07:54:57',
 36867: u'2016:08:21 07:54:57',
 36868: u'2016:08:21 07:54:57',
 37121: '\x01\x02\x03\x00',
 37122: (4, 1),
 37381: (124, 128),
 37383: 5,
 37384: 0,
 37385: 16,
 37386: (47, 10),
 40960: '0100',
 40961: 1,
 40962: 3968,
 40963: 2232,
 41495: 2,
 41728: '\x03',
 41729: '\x01',
 41985: 0,
 41986: 0,
 41987: 0,
 41988: (0, 10),
 41989: 24,
 41990: 0,
 41991: 0,
 41992: 0,
 41993: 0,
 41994: 0}

In this example, we show how to extract the RGB (red, green, blue) values from the image. We also learn how to get a histrogram from the image. Note that I truncated the output a bit as the histogram’s output was much larger. You could graph the histrogram using another Python package, such as matplotlib. Finally, the example above demonstrates how to extract the EXIF information from the image. Again, I have shortened the output from this method a bit as it contained way too much information for this article.


Cropping Images

You can also crop images with Pillow. It’s actually quite easy, although it may take you a little trial and error to figure it out. Let’s try cropping our jellyfish photo:

>>> from PIL import Image
>>> image = Image.open('/path/to/photos/jelly.jpg')
>>> cropped = image.crop((0, 80, 200, 400))
>>> cropped.save('/path/to/photos/cropped_jelly.png')

You will note that all we need to do is open the image and then call its crop method. You will need to pass in the x/y coordinates that you want to crop too, i.e. (x1, y1, x2, y2). In Pillow, the 0 pixel is the top left pixel. As you increase your x value, it goes to the right. As you increase the y value, you go down the image. When you run the code above, you’ll end up with the following image:

cropped_jelly

That’s a pretty boring crop. I want to crop the jellyfish’s “head”. To get the right coordinates quickly, I used Gimp to help me figure out what coordinates to use for my next crop.

>>> from PIL import Image
>>> image = Image.open('/path/to/photos/jelly.jpg')
>>> cropped = image.crop((177, 882, 1179, 1707))
>>> cropped.save('/path/to/photos/cropped_jelly2.png')

If we run this code, we’ll end up with the following cropped version:

cropped_jelly2

That’s much better!


Using Filters

Original Jellyfish
Original Jellyfish

There are a variety of filters that you can use in Pillow to apply to your images. They are contained in the ImageFilter module. Let’s look at a couple of them here:

>>> from PIL import ImageFilter
>>> from PIL import Image
>>> image = Image.open('/path/to/photos/jelly.jpg')
>>> blurred_jelly = image.filter(ImageFilter.BLUR)
>>> blurred_jelly.save('/path/to/photos/blurry_jelly.png')

This will blur the jellyfish photo slightly. Here’s the result I got:

Blurry Jellyfish
Blurry Jellyfish

Of course, most people like their images sharper rather than blurrier. Pillow has your back. Here’s one way to sharpen the image:

>>> from PIL import ImageFilter
>>> from PIL import Image
>>> image = Image.open('/path/to/photos/jelly.jpg')
>>> blurred_jelly = image.filter(ImageFilter.SHARPEN)
>>> blurred_jelly.save('/path/to/photos/sharper_jelly.png')

When you run this code, you’ll end up with the following:

Sharper Jellyfish
Sharper Jellyfish

You can also use the ImageEnhance module for sharpening your photos, among other things.

There are other filters that you can apply too, such as DETAIL, EDGE_ENHANCE, EMBOSS, SMOOTH, etc. You can also write your code in such a way that you can apply multiple filters to your image.

You will likely need to download the images above to really be able to compare the differences in the filters.


Wrapping Up

You can do much more with the Pillow package than what is covered in this short article. Pillow supports image transforms, processing bands, image enhancements, the ability to print your images and much more. I highly recommend reading the Pillow documentation to get a good grasp of everything you can do.


Related Reading

Print Friendly, PDF & Email
  • Nice! A few nits, for whatever it’s worth: there was only one folk-who-forked (yours truly) and while I wish I had lowercased Pillow, the “official” name remains “Pillow” (i.e. Not “pillow”). Thanks for writing about Pillow.

  • Whoops! Yours is one of the only Python packages I’ve seen where it was capitalized. Sorry about that. I went ahead and updated the article. By the way, would you be interested in being a part of the PyDev of the Week series?

  • Thanks! Sure, I’d love to participate.

  • Pingback: How to Crop a Photo With Python – scribdbook()