Python - Python Image Processing with Pillow

 

1. Introduction to Python Image Processing

Python image processing is the process of using Python programs to open, modify, analyze, and save digital images. Image processing is widely used in web development, photography, medical imaging, computer vision, graphic design, and automation.

Python provides several libraries for working with images, including Pillow, OpenCV, and scikit-image. Among these, Pillow is a popular library for basic and intermediate image manipulation because it provides simple functions for editing and converting images.

Pillow is the modern, actively maintained fork of the Python Imaging Library (PIL). It supports common image formats such as JPEG, PNG, GIF, BMP, TIFF, and WebP, although support for individual formats can depend on the installed build.

For example, a Python program can use Pillow to resize a photograph, crop an unwanted area, rotate an image, apply a filter, or convert a PNG image into JPEG format. These operations can be performed automatically on one image or on thousands of images.

2. Installing the Pillow Library

Before using Pillow, you must install it in your Python environment. Pillow is an external library, so it may not be available by default.

Open a terminal or command prompt and run the following command:

python -m pip install Pillow

After installation, import the Image module from Pillow.

from PIL import Image
 

The Image module provides the main functions required to open, create, modify, and save images.

To verify that Pillow is installed correctly, execute this program:

from PIL import Imageprint("Pillow is installed and ready to use.")
 

If the program runs without an import error, Pillow is available in the current Python environment.

3. Opening and Displaying Images

The first step in image processing is usually opening an existing image file. Pillow provides the Image.open() function for this purpose.

Consider an image named photo.jpg stored in the same directory as your Python program.

from PIL import Imageimg = Image.open("photo.jpg")print("Image opened successfully")print("Image size:", img.size)print("Image format:", img.format)print("Image mode:", img.mode)img.show()
 

In this example, Image.open() loads the image so that it can be processed. The size property returns the width and height in pixels, format identifies the file format, and mode describes how the image represents its pixel data.

Common image modes include:

  • RGB: Represents images using red, green, and blue color channels.

  • RGBA: Represents red, green, blue, and an additional alpha channel for transparency.

  • L: Represents grayscale images.

  • 1: Represents a black-and-white image using one bit per pixel.

The show() method opens the image using an external image viewer. It is mainly useful for checking results during development.

4. Resizing Images

Resizing changes the width and height of an image. This operation is useful when preparing photographs for websites, reducing image dimensions for faster uploads, or creating thumbnails for galleries.

Pillow provides the resize() method.

from PIL import Imageimg = Image.open("photo.jpg")resized_img = img.resize((400, 300))resized_img.save("resized_photo.jpg")print("Image resized successfully")
 

The tuple (400, 300) specifies the new width and height in pixels.

However, directly specifying both dimensions may change the proportions of the original image. For example, a wide photograph could appear stretched if resized to a square.

To create a thumbnail while preserving the aspect ratio, use thumbnail():

from PIL import Imageimg = Image.open("photo.jpg")img.thumbnail((400, 400))img.save("thumbnail.jpg")print("Thumbnail created successfully")
 

The thumbnail() method reduces the image so that it fits within the specified dimensions while maintaining its original proportions. It modifies the image object directly and does not enlarge an image that is already smaller than the specified limits.

5. Cropping Images

Cropping removes unwanted portions of an image. It is useful for focusing on a particular object, creating profile pictures, preparing product photographs, or removing unnecessary background areas.

Pillow uses the crop() method to extract a rectangular region.

from PIL import Imageimg = Image.open("photo.jpg")cropped_img = img.crop((100, 50, 500, 350))cropped_img.save("cropped_photo.jpg")print("Image cropped successfully")
 

The four values represent the crop boundaries in this order:

  • Left coordinate: 100

  • Upper coordinate: 50

  • Right coordinate: 500

  • Lower coordinate: 350

The resulting crop has a width of 400 pixels and a height of 300 pixels.

The coordinates are measured from the upper-left corner of the image. The crop rectangle should be chosen carefully because an incorrect coordinate range may exclude the desired subject.

6. Rotating and Flipping Images

Rotating changes the orientation of an image, while flipping creates a reversed version of it. These operations are helpful when correcting photographs taken at the wrong angle or preparing images for different layouts.

Pillow provides the rotate() method.

from PIL import Imageimg = Image.open("photo.jpg")rotated_img = img.rotate(90, expand=True)rotated_img.save("rotated_photo.jpg")print("Image rotated successfully")
 

The value 90 rotates the image by 90 degrees counterclockwise. The expand=True argument expands the output dimensions when necessary to accommodate the rotated image without cutting off its corners.

Pillow also provides the transpose() method for flipping images.

from PIL import Imageimg = Image.open("photo.jpg")flipped_img = img.transpose(    Image.Transpose.FLIP_LEFT_RIGHT)flipped_img.save("flipped_photo.jpg")
 

This program creates a horizontally flipped image. To flip the image vertically, use Image.Transpose.FLIP_TOP_BOTTOM.

7. Applying Image Filters

Image filters change the visual appearance of an image. They can be used to create artistic effects, improve presentation, or emphasize particular visual details.

Pillow provides several filters through ImageFilter.

from PIL import Image, ImageFilterimg = Image.open("photo.jpg")blurred_img = img.filter(ImageFilter.BLUR)blurred_img.save("blurred_photo.jpg")print("Blur filter applied successfully")
 

The BLUR filter produces a blurred appearance by reducing fine details.

Other commonly used filters include:

  • ImageFilter.SHARPEN: Enhances the appearance of edges and details.

  • ImageFilter.CONTOUR: Highlights outlines in an image.

  • ImageFilter.EMBOSS: Produces a raised or embossed visual effect.

  • ImageFilter.FIND_EDGES: Emphasizes boundaries between image regions.

  • ImageFilter.SMOOTH: Smooths the image and reduces some fine variations.

For example, the following program sharpens an image:

from PIL import Image, ImageFilterimg = Image.open("photo.jpg")sharp_img = img.filter(ImageFilter.SHARPEN)sharp_img.save("sharpened_photo.jpg")
 

The choice of filter depends on the desired result. Filters can change the appearance of the image significantly, so it is good practice to preserve the original file and save the processed result separately.

8. Converting Images Between Formats

Different image formats serve different purposes. JPEG is commonly used for photographs, PNG supports lossless compression and transparency, and WebP can provide efficient compression for web images.

Pillow makes it possible to convert images between supported formats.

from PIL import Imageimg = Image.open("photo.png")rgb_img = img.convert("RGB")rgb_img.save("photo.jpg", quality=90)print("Image converted to JPEG format")
 

This program opens a PNG file, converts its pixel representation to RGB, and saves it as a JPEG image with a quality setting of 90.

Converting to RGB is important when the original image contains an alpha channel or another mode that JPEG cannot store directly. However, converting an image with transparency to RGB discards the alpha channel, so transparent areas may no longer remain transparent.

When transparency must be preserved, PNG or another suitable format should be used instead.

9. Working with Image Colors and Pixels

An image consists of pixels, and each pixel stores information about color or brightness. Pillow allows programmers to inspect and modify this information.

For example, the getpixel() method retrieves the color value at a particular coordinate.

from PIL import Imageimg = Image.open("photo.jpg").convert("RGB")pixel_color = img.getpixel((10, 20))print("Pixel color:", pixel_color)
 

For an RGB image, the returned value is a tuple containing red, green, and blue intensity values, generally ranging from 0 to 255.

A value such as (255, 0, 0) represents red, while (0, 0, 0) represents black and (255, 255, 255) represents white.

The putpixel() method can change a pixel's color.

from PIL import Imageimg = Image.open("photo.jpg").convert("RGB")img.putpixel((10, 20), (255, 0, 0))img.save("modified_photo.jpg")print("Pixel color modified successfully")
 

This program changes the pixel at coordinate (10, 20) to red. Although individual pixel operations are useful for learning and specialized tasks, processing large images pixel by pixel in Python can be slow. For large-scale numerical image operations, array-based approaches may be more efficient.

10. Automating Image Processing for Multiple Files

One important advantage of Pillow is that image-processing tasks can be automated. Instead of editing every image manually, a Python program can process an entire directory of photographs.

The following example resizes supported image files in a folder and saves the results in a separate output folder.

from pathlib import Pathfrom PIL import Image, ImageOpsinput_folder = Path("images")output_folder = Path("processed_images")output_folder.mkdir(parents=True, exist_ok=True)supported_formats = {".jpg", ".jpeg", ".png", ".webp"}for file_path in input_folder.iterdir():    if file_path.suffix.lower() not in supported_formats:        continue    try:        with Image.open(file_path) as img:            img = ImageOps.exif_transpose(img)            img.thumbnail((800, 800))            output_path = output_folder / file_path.name            img.save(output_path)            print(f"Processed: {file_path.name}")    except (OSError, ValueError) as error:        print(f"Could not process {file_path.name}: {error}")
 

In this program, Path helps manage file and folder paths. The iterdir() method retrieves the files in the input directory, and the program processes files with supported extensions.

The ImageOps.exif_transpose() function corrects orientation based on EXIF metadata when such information is present. The thumbnail() method reduces each image to fit within 800 by 800 pixels without changing its aspect ratio.

The try and except statements allow the program to report certain file-processing errors without immediately stopping the entire batch.

Before running the program, create a folder named images and place the images inside it. The processed images will be saved in processed_images.

For production use, it is also important to consider output formats, transparency, file naming, and whether existing files should be overwritten.

11. Practical Applications of Pillow

Pillow is useful in many real-world applications because it can perform image operations automatically and integrate with other Python programs.

Web development: Websites can use Pillow to create thumbnails, resize uploaded photographs, and prepare images for different screen sizes.

E-commerce: Online stores can standardize product image dimensions, convert image formats, and create smaller previews for product listings.

Document processing: Pillow can open and manipulate scanned documents, convert them to grayscale, rotate pages, and prepare images for optical character recognition systems.

Photography: Photographers can automate resizing, cropping, format conversion, and basic filter application across large collections of photographs.

Data preparation: Developers working on machine learning projects can use Pillow to load images, normalize their dimensions, and prepare files for further processing.

Content management: Publishing systems can automatically create image versions for article previews, galleries, and featured images.

Pillow is primarily an image manipulation library. More advanced tasks, such as object detection, image segmentation, and real-time computer vision, generally require specialized libraries or models.

12. Advantages and Limitations of Pillow

Pillow offers a simple interface for common image operations and supports many widely used file formats. It integrates well with Python scripts, making it suitable for automation, web applications, and image preparation workflows. Its functions for resizing, cropping, filtering, and format conversion are especially useful for beginners and intermediate developers.

However, Pillow is not designed to replace every image-processing or computer-vision framework. Complex operations involving object recognition, advanced image segmentation, or GPU-based processing may require OpenCV, scikit-image, or deep-learning libraries. Processing very large images also requires attention to memory usage, execution time, and safe handling of untrusted image files.

Conclusion

Python image processing with Pillow enables programmers to manipulate digital images through clear and reusable Python code. By learning how to open, resize, crop, rotate, flip, filter, convert, and modify images, developers can automate tasks that would otherwise require repeated manual effort.

Understanding Pillow is a valuable skill for Python learners because it combines basic programming concepts such as variables, functions, loops, file handling, and exception handling with practical image-processing techniques. With these foundations, learners can develop image utilities, automate content preparation, and build more advanced applications that work with visual data.