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")