Skip to content

Effortlessly Enhance your Images using PIL

[

Image Processing With the Python Pillow Library

By Stephen Gruppetta Intermediate

When you look at an image, you see the objects and people in it. However, when you read an image programmatically with Python or any other language, the computer sees an array of numbers. In this tutorial, you’ll learn how to manipulate images and perform basic image processing using the Python Pillow library.

Pillow and its predecessor, PIL, are the original Python libraries for dealing with images. Even though there are other Python libraries for image processing, Pillow remains an important tool for understanding and dealing with images.

To manipulate and process images, Pillow provides tools that are similar to ones found in image processing software such as Photoshop. Some of the more modern Python image processing libraries are built on top of Pillow and often provide more advanced functionality.

In this tutorial, you’ll learn how to:

  • Read images with Pillow
  • Perform basic image manipulation operations
  • Use Pillow for image processing
  • Use NumPy with Pillow for further processing
  • Create animations using Pillow

This tutorial provides an overview of what you can achieve with the Python Pillow library through some of its most common methods. Once you gain confidence using these methods, then you can use Pillow’s documentation to explore the rest of the methods in the library. If you’ve never worked with images in Python before, this is a great opportunity to jump right in!

Basic Image Operations With the Python Pillow Library

The Image Module and Image Class in Pillow

Pillow provides an Image class that represents an image as a whole and an Image module that provides a set of functions to manipulate images. Here’s how you can use these two:

from PIL import Image
# Open an image file
with Image.open('path/to/image.jpg') as img:
# Do something with the image
img.show()

The code above opens an image file using the Image object and then displays it using the show() method. You can also save the modified image to a file using the save() method.

Basic Image Manipulation

Pillow provides a wide range of image manipulation functions. Some common operations include:

  • Rotating an image
  • Cropping an image
  • Resizing an image
  • Flipping an image

Here’s an example of rotating an image by 90 degrees:

from PIL import Image
with Image.open('path/to/image.jpg') as img:
rotated_img = img.rotate(90)
rotated_img.show()

The code above opens an image file, rotates it by 90 degrees using the rotate() method, and then displays the rotated image.

Bands and Modes of an Image in the Python Pillow Library

In Pillow, an image is composed of multiple bands, where each band represents a color channel. The number of bands and their meanings depend on the mode of the image. The most common modes are:

  • RGB (Red, Green, Blue)
  • RGBA (Red, Green, Blue, Alpha)
  • L (Grayscale)

You can check the mode and number of bands of an image using the mode and bands attributes, respectively.

from PIL import Image
with Image.open('path/to/image.jpg') as img:
mode = img.mode
bands = img.getbands()
print(f"Image mode: {mode}")
print(f"Number of bands: {len(bands)}")

The code above opens an image file and prints out the image mode and number of bands.

Image Processing Using Pillow in Python

Image Filters Using Convolution Kernels

Image filters are used to modify the pixel values of an image based on a predefined kernel. Pillow provides several built-in image filters that you can apply to an image. Here’s an example of applying a blur filter:

from PIL import Image
from PIL import ImageFilter
with Image.open('path/to/image.jpg') as img:
blurred_img = img.filter(ImageFilter.BLUR)
blurred_img.show()

The code above opens an image file, applies a blur filter using the filter() method, and then displays the blurred image.

Image Blurring, Sharpening, and Smoothing

In addition to using image filters, Pillow provides specific functions for blurring, sharpening, and smoothing images. These functions allow you to control the strength and radius of the effect. Here’s an example of blurring an image:

from PIL import Image
from PIL import ImageFilter
with Image.open('path/to/image.jpg') as img:
blurred_img = img.filter(ImageFilter.GaussianBlur(radius=5))
blurred_img.show()

The code above opens an image file, applies a Gaussian blur filter using the GaussianBlur() function, and then displays the blurred image.

Edge Detection, Edge Enhancement, and Embossing

Pillow also provides functions for detecting edges, enhancing edges, and embossing images. These functions modify the image to highlight or create a 3D-like effect. Here’s an example of enhancing the edges of an image:

from PIL import Image
from PIL import ImageFilter
with Image.open('path/to/image.jpg') as img:
edges_img = img.filter(ImageFilter.EDGE_ENHANCE)
edges_img.show()

The code above opens an image file, enhances the edges using the EDGE_ENHANCE filter, and then displays the enhanced image.

Image Segmentation and Superimposition: An Example

Image Thresholding

Image thresholding is a technique used to divide an image into different regions based on pixel intensity values. Thresholding can be used for image segmentation and object recognition. Pillow provides a point() method that allows you to apply a threshold function to each pixel in the image. Here’s an example of applying thresholding to an image:

from PIL import Image
with Image.open('path/to/image.jpg') as img:
thresholded_img = img.point(lambda p: p > 128 and 255)
thresholded_img.show()

The code above opens an image file, applies a threshold function using the point() method, and then displays the thresholded image.

Erosion and Dilation

Erosion and dilation are morphological operations used for image segmentation and noise reduction. Pillow provides functions to perform erosion and dilation on images. Here’s an example of performing erosion on an image:

from PIL import Image
from PIL import ImageFilter
with Image.open('path/to/image.jpg') as img:
eroded_img = img.filter(ImageFilter.MinFilter(size=3))
eroded_img.show()

The code above opens an image file, applies a minimum filter using the MinFilter() function, and then displays the eroded image.

Image Segmentation Using Thresholding

By combining image thresholding, erosion, and dilation techniques, you can perform image segmentation to separate objects from the background. Here’s an example of segmenting an image using thresholding:

from PIL import Image
from PIL import ImageFilter
with Image.open('path/to/image.jpg') as img:
thresholded_img = img.point(lambda p: p > 128 and 255)
segmented_img = thresholded_img.filter(ImageFilter.MinFilter(size=3))
segmented_img.show()

The code above opens an image file, applies thresholding using the point() method, performs erosion using the MinFilter() function, and then displays the segmented image.

Superimposition of Images Using Image.paste()

Pillow provides the paste() method to superimpose one image onto another. This can be useful for watermarking an image or overlaying an image with another image. Here’s an example of superimposing an image onto another:

from PIL import Image
with Image.open('path/to/image.jpg') as img:
with Image.open('path/to/watermark.png') as watermark:
img.paste(watermark, (0, 0), watermark)
img.show()

The code above opens an image file and a watermark file, pastes the watermark onto the image at the specified position, and then displays the superimposed image.

Creation of A Watermark

You can create a watermark image using Pillow by manipulating the pixel values or adding text or a logo to the image. Here’s an example of creating a watermark:

from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
with Image.open('path/to/image.jpg') as img:
watermark_img = img.copy()
draw = ImageDraw.Draw(watermark_img)
font = ImageFont.truetype('path/to/font.ttf', size=30)
draw.text((10, 10), 'Watermark', fill=(255, 255, 255), font=font)
watermark_img.show()

The code above opens an image file, creates a copy of the image, draws text onto the copy using the ImageDraw module, and then displays the watermarked image.

Image Manipulation With NumPy and Pillow

Using NumPy to Subtract Images From Each Other

NumPy is a powerful Python library for numerical computations. You can use NumPy with Pillow to perform advanced image manipulation operations. Here’s an example of subtracting two images using NumPy:

import numpy as np
from PIL import Image
with Image.open('path/to/image1.jpg') as img1:
with Image.open('path/to/image2.jpg') as img2:
img1_arr = np.array(img1)
img2_arr = np.array(img2)
subtracted_img_arr = np.abs(img1_arr - img2_arr)
subtracted_img = Image.fromarray(subtracted_img_arr)
subtracted_img.show()

The code above opens two image files, converts them to NumPy arrays, subtracts one array from the other, converts the resulting array back to an image using the fromarray() method, and then displays the subtracted image.

Using NumPy to Create Images

NumPy can also be used to create images from scratch. You can create an empty NumPy array and fill it with pixel values to create an image. Here’s an example of creating a red square image:

import numpy as np
from PIL import Image
# Create an empty red square image
image_arr = np.zeros((100, 100, 3), dtype=np.uint8)
image_arr[:, :, 0] = 255
# Convert the NumPy array to a Pillow image
image = Image.fromarray(image_arr)
image.show()

The code above creates an empty NumPy array with dimensions 100x100x3, sets all the red channel values to 255, converts the array to an image using the fromarray() method, and then displays the created image.

Creating Animations

You can use Pillow and NumPy together to create animations by manipulating multiple images and saving them as a GIF file. Here’s an example of creating a simple animated blinking effect:

import numpy as np
from PIL import Image
from PIL import ImageSequence
# Create multiple frames for the animation
frames = []
for i in range(10):
image_arr = np.zeros((100, 100, 3), dtype=np.uint8)
image_arr[:, :, 1] = 255
frames.append(Image.fromarray(image_arr))
# Save the frames as an animated GIF
frames[0].save('animation.gif', save_all=True, append_images=frames[1:], duration=200, loop=0)
# Open the saved animation
with Image.open('animation.gif') as animation:
animation.show()

The code above creates an array of frames by setting the green channel to 255 for each frame, saves the frames as an animated GIF using the save() method, and then displays the created animation.

Conclusion

In this tutorial, you have learned how to manipulate images and perform basic image processing using the Python Pillow library. You have also seen how to use NumPy with Pillow for more advanced image processing and how to create animations using multiple frames.

Pillow provides a wide range of functions and methods for image manipulation, and it is a powerful tool for working with images in Python. With the knowledge gained from this tutorial, you can now explore the Pillow documentation and continue learning about the various methods and functionalities it offers.

Don’t be afraid to experiment with different images and techniques to further develop your skills in image processing with Pillow!