Pillow Advanced
## Image Filters and Enhancement
### Built-in Filter Application (filter())
Pillow provides multiple built-in filters using the ImageFilter module:
## Example
from PIL import Image, ImageFilter
# Open image
image = Image.open("input.jpg")
# Apply blur filter
blurred = image.filter(ImageFilter.BLUR)
blurred.save("blurred.jpg")
# Apply contour filter
contour = image.filter(ImageFilter.CONTOUR)
contour.save("contour.jpg")
# Apply emboss filter
emboss = image.filter(ImageFilter.EMBOSS)
emboss.save("emboss.jpg")
# Find edges
edges = image.filter(ImageFilter.FIND_EDGES)
edges.save("edges.jpg")
# Sharpen filter
sharpen = image.filter(ImageFilter.SHARPEN)
sharpen.save("sharpen.jpg")
# Smooth filter
smooth = image.filter(ImageFilter.SMOOTH)
smooth.save("smooth.jpg")
# Detail enhancement
detail = image.filter(ImageFilter.DETAIL)
detail.save("detail.jpg")
### Image Enhancement (ImageEnhance Module)
The ImageEnhance module provides tools to control brightness, contrast, color, and sharpness:
## Example
from PIL import Image, ImageEnhance
# Open image
image = Image.open("input.jpg")
# Enhance brightness (factor > 1 increases brightness, < 1 decreases brightness)
enhancer = ImageEnhance.Brightness(image)
brightened = enhancer.enhance(1.5)# Increase brightness by 50%
brightened.save("brightened.jpg")
# Enhance contrast
enhancer = ImageEnhance.Contrast(image)
contrast = enhancer.enhance(1.8)# Increase contrast by 80%
contrast.save("contrast.jpg")
# Enhance color saturation
enhancer = ImageEnhance.Color(image)
saturated = enhancer.enhance(1.5)# Increase saturation by 50%
saturated.save("saturated.jpg")
# Enhance sharpness
enhancer = ImageEnhance.Sharpness(image)
sharpened = enhancer.enhance(2.0)# Increase sharpness by 100%
sharpened.save("sharpened.jpg")
Custom Convolution Kernels
Pillow allows creating special effects using custom convolution kernels:
pythonimport numpy as np
from PIL import Image, ImageFilter
# Open image
image = Image.open("input.jpg")
# Create custom convolution kernel
# This is a sharpening convolution kernel
kernel = ImageFilter.Kernel(
size=(3,3),
kernel=[-1, -1, -1, -1,9, -1, -1, -1, -1],
scale=1
)
sharpened = image.filter(kernel)
sharpened.save("custom_sharpen.jpg")
# Emboss effect convolution kernel
emboss_kernel = ImageFilter.Kernel(
size=(3,3),
kernel=[-2, -1,0, -1,1,1,0,1,2],
scale=1,
offset=128
)
embossed = image.filter(emboss_kernel)
embossed.save("custom_emboss.jpg")
# Gaussian blur convolution kernel
gaussian_kernel = ImageFilter.Kernel(
size=(5,5),
kernel=[1,4,6,4,1,4,16,24,16,4,6,24,36,24,6,4,16,24,16,4,1,4,6,4,1],
scale=256
)
gaussian_blur = image.filter(gaussian_kernel)
gaussian_blur.save("custom_gaussian.jpg")
### Edge Detection and Sharpening
Beyond built-in filters, more advanced edge detection and sharpening effects can be implemented:
## Example
from PIL import Image, ImageFilter, ImageChops, ImageOps
# Open image
image = Image.open("input.jpg")
# Sobel edge detection
# Horizontal Sobel filter
h_sobel = ImageFilter.Kernel(
size=(3,3),
kernel=[-1,0,1, -2,0,2, -1,0,1],
scale=1
)
# Vertical Sobel filter
v_sobel = ImageFilter.Kernel(
size=(3,3),
kernel=[-1, -2, -1,0,0,0,1,2,1],
scale=1
)
h_edges = image.filter(h_sobel)
v_edges = image.filter(v_sobel)
# Merge horizontal and vertical edges
edges = ImageChops.add(
ImageChops.multiply(h_edges, h_edges),
ImageChops.multiply(v_edges, v_edges)
)
edges.save("sobel_edges.jpg")
# Using high-frequency enhancement for sharpening (USM - Unsharp Masking)
def unsharp_mask(image, radius=2, percent=150, threshold=3):
"""Apply USM sharpening filter
Parameters:
radius: Gaussian blur radius
percent: Sharpening intensity percentage
threshold: Minimum brightness change threshold for applying sharpening
"""
blurred = image.filter(ImageFilter.GaussianBlur(radius=radius))
sharpened = Image.blend(image, ImageChops.subtract(image, blurred), percent/100)
return sharpened
usm_image = unsharp_mask(image, radius=2, percent=200, threshold=5)
usm_image.save("usm_sharpened.jpg")
* * *
## Drawing and Text Addition
### Basic Shape Drawing (ImageDraw Module)
## Example
from PIL import Image, ImageDraw
# Create blank canvas
width, height =800,600
image = Image.new("RGB",(width, height), color="white")
draw = ImageDraw.Draw(image)
# Draw lines
draw.line([(100,100),(700,500)], fill="black", width=5)
# Draw rectangle
draw.rectangle([(200,200),(600,400)], outline="red", width=3, fill="yellow")
# Draw ellipse
draw.ellipse([(300,150),(500,350)], outline="blue", width=3, fill="lightblue")
# Draw circle
draw.ellipse([(550,50),(650,150)], outline="green", width=2, fill="lightgreen")
# Draw polygon
draw.polygon([(100,500),(300,450),(500,550),(250,600)],
outline="purple", fill="lavender")
# Draw arc
draw.arc([(400,400),(600,500)], start=0, end=180, fill="orange", width=3)
# Draw points
for i in range(50):
import random
x =random.randint(0, width)
y =random.randint(0, height)
draw.point((x, y), fill="black")
image.save("drawings.png")
### Add Text (text())
## Example
from PIL import Image, ImageDraw, ImageFont
# Create blank canvas
image = Image.new("RGB",(800,600), color="white")
draw = ImageDraw.Draw(image)
# Use default font
draw.text((100,100),"Hello, Pillow!", fill="black")
# Load custom TrueType font
try:
# Attempt to load system font
# Windows: "arial.ttf", "simhei.ttf"
# Mac: "Arial.ttf", "STHeiti Light.ttc"
# Linux: "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
font = ImageFont.truetype("arial.ttf", size=36)
except IOError:
# If system font not found, use default font
font = ImageFont.load_default()
# Draw text with custom font
draw.text((100,200),"Custom Font Text", font=font, fill="blue")
# Draw text with outline
def draw_text_with_outline(draw, text, position, font, text_color, outline_color):
"""Draw text with outline"""
x, y = position
# Draw outline
draw.text((x-1, y-1), text, font=font, fill=outline_color)
draw.text((x+1, y-1), text, font=font, fill=outline_color)
draw.text((x-1, y+1), text, font=font, fill=outline_color)
draw.text((x+1, y+1), text, font=font, fill=outline_color)
# Draw main text
draw.text((x, y), text, font=font, fill=text_color)
draw_text_with_outline(draw,"Outline Text Effect",(100,300), font,"red","black")
# Get text size and center drawing
text ="Centered Text"
text_width, text_height = draw.textsize(text, font=font)
position =((800 - text_width) // 2,400)
draw.text(position, text, font=font, fill="purple")
# Draw multiline text
multiline_text ="""This is a
Multiline Text Example
Using Pillow Library
For Drawing"""
draw.multiline_text((100,450), multiline_text, font=font, fill="green", spacing=10, align="center")
image.save("text_drawings.png")
### Draw Complex Shapes
## Example
from PIL import Image, ImageDraw
import math
# Create blank canvas
width, height =800,800
image = Image.new("RGB",(width, height), color="white")
draw = ImageDraw.Draw(image)
# Draw star
def draw_star(draw, center, points=5, outer_radius=100, inner_radius=50, rotation=0, **kwargs):
"""Draw star
Parameters:
center: Center point coordinate tuple (x, y)
points: Number of star points
outer_radius: Outer circle radius
inner_radius: Inner circle radius
rotation: Rotation angle (degrees)
**kwargs: Parameters passed to polygon()
"""
cx, cy = center
angle =math.pi / points
rotation_rad =math.radians(rotation)
vertices =[]
for i in range(2 * points):
radius = outer_radius if i % 2==0 else inner_radius
theta = i * angle + rotation_rad
x = cx + radius * math.sin(theta)
y = cy - radius * math.cos(theta)
vertices.append((x, y))
draw.polygon(vertices, **kwargs)
# Draw stars
draw_star(draw, center=(200,200), fill="gold", outline="orange", width=2)
draw_star(draw, center=(500,200), points=8, rotation=22.5,
outer_radius=120, inner_radius=40, fill="blue", outline="navy", width=2)
# Draw heart
def draw_heart(draw, center, size=100, **kwargs):
"""Draw heart
Parameters:
center: Center point coordinate tuple (x, y)
size: Heart size
**kwargs: Parameters passed to polygon()
"""
cx, cy = center
vertices =[]
for t in range(100):
angle = t / 100 * 2 * math.pi
x =16 * math.sin(angle) ** 3
y =13 * math.cos(angle) - 5 * math.cos(2*angle) - 2 * math.cos(3*angle) - math.cos(4*angle)
# Scale and translate
vertices.append((cx + x * size / 16, cy - y * size / 16))
draw.polygon(vertices, **kwargs)
draw_heart(draw, center=(200,500), size=150, fill="red", outline="darkred", width=3)
# Draw spiral
def draw_spiral(draw, center, loops=3, radius_start=5, radius_end=100, points=500, **kwargs):
"""Draw spiral
Parameters:
center: Center point coordinate tuple (x, y)
loops: Number of spiral loops
radius_start: Starting radius
radius_end: Ending radius
points: Number of points
**kwargs: Parameters passed to line()
"""
cx, cy = center
vertices =[]
for i in range(points + 1):
# Calculate current angle and radius
angle = i / points * loops * 2 * math.pi
radius = radius_start + (radius_end - radius_start) * i / points
x = cx + radius * math.cos(angle)
y = cy + radius * math.sin(angle)
vertices.append((x, y))
# Draw polyline
for i in range(len(vertices) - 1):
draw.line([vertices, vertices[i+1]], **kwargs)
draw_spiral(draw,
YouTip