Python Image Manipulation with PIL: Essential Techniques and Examples

The Python Imaging Library (PIL) provides robust tools for image processing tasks. Let's explore fundamental operations inclduing loading, displaying, modifying, and saving images.

# Import necessary modules
from PIL import Image

# Load an image file
source_image :Image.Image = Image.open("./media/sample_001.jpg")   # Load image from disk

source_image.show()                        # Display the image in default viewer
resized_image = source_image.resize((1000,2000))    # Create a resized version
resized_image.save("./media/resized_002.jpg")     # Save the modified image

Image Format Conversion

Changing image formats is straightforward with PIL, allowing seamless conversion between different image types.

from PIL import Image

# Load image in one format
input_image: Image.Image = Image.open("./media/sample_099.jfif")
# Convert and save in another format
input_image.save("./media/converted_099.jpg")

Adding Text to Images

Text annotations can be added to images using PIL's drawing capabilities, which support custom fonts and positioning.

from PIL import Image, ImageDraw, ImageFont

# Load the base image
base_image: Image.Image = Image.open("./media/sample_099.jfif")

# Create drawing context
draw_context = ImageDraw.Draw(base_image)
# Define font properties
annotation_font = ImageFont.truetype("D:/iFontsClientFileCache/HYXieNTJ.ttf", 240)

# Add text annotations at specified coordinates
draw_context.text((50, 30), "ID: 541913460XXX", fill='blue', font=annotation_font)
draw_context.text((50, 250), "Name: Zhang XX", fill='red', font=annotation_font)
base_image.show()

Extracting Image Metadata

Understanding image data structure is crucial for advanced processing. PIL provides methods to access pixel information in various formats.

from PIL import Image
import numpy as np

# Load and convert image to RGB
target_image: Image = Image.open("./media/sample_001.jpg")
target_image = target_image.convert("RGB")

# Access pixel data
pixel_data = target_image.getdata()

# Convert to Python list
pixel_list = list(pixel_data)
print(pixel_list)

# Convert to NumPy array for numerical operations
pixel_array = np.asarray(pixel_data)
print(pixel_array)

Creating Images from Data Arrrays

Images can be programmatically generated from numerical arrays, enabling data visualization and synthetic image creation.

from PIL import Image
import numpy as np

# Generate a gradient pattern
value = 0
gradient_matrix = []

for row in range(0, 8):
    current_row = []
    gradient_matrix.append(current_row)
    
    for col in range(0, 8):
        current_row.append(value)
        value = value + 2

# Print generated matrix for verification
for row in gradient_matrix:
    print(row)

# Convert matrix to grayscale image
synthetic_image = Image.fromarray(np.asarray(gradient_matrix)).convert("L")
synthetic_image.save("./media/gradient_099.jpg")

Single Channel Extraction

Isolating individual color channels is a common image processing operation that can reveal hidden information.

from PIL import Image
import numpy as np

# Load and convert image
source_image: Image.Image = Image.open("./media/sample_000.png")
source_image = source_image.convert("RGB")

# Convert to numpy array for manipulation
numpy_array = np.array(source_image)

# Extract red channel by zeroing other channels
for row in numpy_array:  # Iterate through rows
    for pixel in row:     # Iterate through pixels
        pixel[1] = 0  # Zero green channel
        pixel[2] = 0  # Zero blue channel

# Convert back to image and save
red_channel_image = Image.fromarray(numpy_array).convert("RGB")
red_channel_image.save("./media/red_channel_test.jpg")

Extracting Color Channels

A more modular approach to color channel extraction using reusable functions.

from PIL import Image
import numpy as np

def extract_red_channel(img):
    """Extract and save the red channel of an image"""
    numpy_array = np.array(img)
    
    for row in numpy_array:
        for pixel in row:
            pixel[1] = 0  # Zero green
            pixel[2] = 0  # Zero blue
    
    result_image = Image.fromarray(numpy_array).convert("RGB")
    result_image.save("./media/red_channel_result.jpg")

def extract_green_channel(img):
    """Extract and save the green channel of an image"""
    numpy_array = np.array(img)
    
    for row in numpy_array:
        for pixel in row:
            pixel[0] = 0  # Zero red
            pixel[2] = 0  # Zero blue
    
    result_image = Image.fromarray(numpy_array).convert("RGB")
    result_image.save("./media/green_channel_result.jpg")

def extract_blue_channel(img):
    """Extract and save the blue channel of an image"""
    numpy_array = np.array(img)
    
    for row in numpy_array:
        for pixel in row:
            pixel[0] = 0  # Zero red
            pixel[1] = 0  # Zero green
    
    result_image = Image.fromarray(numpy_array).convert("RGB")
    result_image.save("./media/blue_channel_result.jpg")

# Load image and extract all channels
input_image: Image.Image = Image.open("./media/sample_000.png")
input_image = input_image.convert("RGB")

extract_red_channel(input_image)
extract_green_channel(input_image)
extract_blue_channel(input_image)

Understanding Image Color Modes

Different color modes represent images in various ways, each suited for different applications.

from PIL import Image

# Load an RGB image
original_image: Image = Image.open("./media/sample_001.jpg")

# Convert to different color modes
cmyk_image = original_image.convert("CMYK")
rgb_image = original_image.convert("RGB")
ycbcr_image = original_image.convert("YCbCr")

# Save each version
cmyk_image.save("./media/cmyk_version.jpg")
rgb_image.save("./media/rgb_version.jpg")
ycbcr_image.save("./media/ycbcr_version.jpg")

# Display the color mode of each image
print("Original mode:", original_image.mode)
print("CMYK mode:", cmyk_image.mode)
print("RGB mode:", rgb_image.mode)
print("YCbCr mode:", ycbcr_image.mode)

Image Mirroring and Flipping

Geometric transformations like mirroring are useful for data augmentation and image correction.

from PIL import Image

# Load the source image
source_image = Image.open("./media/sample_000.png")

# Horizontal flip (left-right mirror)
horizontal_mirror = source_image.transpose(Image.FLIP_LEFT_RIGHT)
horizontal_mirror.save("./media/horizontal_mirror.png")

# Vertical flip (top-bottom mirror)
vertical_mirror = source_image.transpose(Image.FLIP_TOP_BOTTOM)
vertical_mirror.save("./media/vertical_mirror.png")

# Combined flip (both horizontal and vertical)
vertical_flipped = source_image.transpose(Image.FLIP_TOP_BOTTOM)
horizontal_vertical_mirror = vertical_flipped.transpose(Image.FLIP_LEFT_RIGHT)
horizontal_vertical_mirror.save("./media/hv_mirror.png")

Image Concatenation

Combining multiple images into a single composite is useful for creating panoramas, comparisons, or layouts.

from PIL import Image

# Load images to be concatenated
first_image = Image.open("./media/sample_000.png")
second_image = Image.open("./media/hv_mirror.png")

# Check image dimensions
print("First image size:", first_image.size)  # Returns (width, height)
                   
# Create a new canvas with appropriate dimensions
combined_width = first_image.width + second_image.width
combined_height = first_image.height
canvas = Image.new('RGB', (combined_width, combined_height), (255, 255, 255))
    
# Paste images onto the canvas
canvas.paste(first_image, (0, 0))
canvas.paste(second_image, (first_image.width, 0))
canvas.save("./media/combined_image.png")

Image Cropping

Selecting regions of interest through cropping is essential for focusing on specific image features.

from PIL import Image

# Load the composite image
composite_image = Image.open("./media/combined_image.png")
print("Original size:", composite_image.size)   # Returns (width, height)

# Define crop coordinates (left, top, right, bottom)
crop_box = (100, 20, 370, 100)
cropped_image = composite_image.crop(crop_box)
cropped_image.save("./media/cropped_region.png")

Image Scaling and Resizing

Adjusting image dimensions while maintaining aspect ratio is important for responsive design and standardization.

from PIL import Image

# Load the image to be scaled
source_image = Image.open("./media/combined_image.png")
print("Original dimensions:", source_image.size)         # Returns (width, height)

# Scale image while maintaining aspect ratio
max_dimension = 100
source_image.thumbnail((max_dimension, max_dimension))  # Preserves aspect ratio
source_image.save("./media/scaled_image.png")

Tags: python PIL image-processing computer-vision image-manipulation

Posted on Thu, 13 Aug 2026 16:56:05 +0000 by slimsam1