PIL Image Filters
Filters transform images by modifying pixel values based on their neighbors. PIL provides built-in filters (blur, sharpen, edge detect) and tools to build custom filters pixel by pixel.
Learning Objectives
- 12.6.2.4 Create filters for image processing
Conceptual Anchor
The Instagram Filter Analogy
Every photo filter on your phone is code that reads pixel values, applies a mathematical formula, and writes new pixel values. PIL gives you the same power — blur, sharpen, edge detection, color adjustments — all from Python.
Rules & Theory
Built-in Filters (ImageFilter)
| Filter | Effect | Usage |
|---|---|---|
BLUR |
Smooths image, reduces noise | img.filter(ImageFilter.BLUR) |
GaussianBlur(r) |
Gaussian blur with radius r | img.filter(ImageFilter.GaussianBlur(5)) |
SHARPEN |
Enhances edges, makes image crisp | img.filter(ImageFilter.SHARPEN) |
CONTOUR |
Extracts contour lines | img.filter(ImageFilter.CONTOUR) |
DETAIL |
Enhances fine details | img.filter(ImageFilter.DETAIL) |
EDGE_ENHANCE |
Subtly enhances edges | img.filter(ImageFilter.EDGE_ENHANCE) |
FIND_EDGES |
Finds all edges (like a sketch) | img.filter(ImageFilter.FIND_EDGES) |
EMBOSS |
3D embossed effect | img.filter(ImageFilter.EMBOSS) |
SMOOTH |
Light smoothing | img.filter(ImageFilter.SMOOTH) |
Pixel-Level Adjustments (ImageEnhance)
| Enhancer | What It Adjusts | Factor |
|---|---|---|
ImageEnhance.Brightness |
Light/dark | 0.0 = black, 1.0 = original, 2.0 = 2× bright |
ImageEnhance.Contrast |
Difference between darks and lights | 0.0 = gray, 1.0 = original, 2.0 = 2× contrast |
ImageEnhance.Color |
Color saturation | 0.0 = grayscale, 1.0 = original |
ImageEnhance.Sharpness |
Edge definition | 0.0 = blurred, 2.0 = extra sharp |
from PIL import Image, ImageFilter, ImageEnhance
img = Image.open("photo.jpg")
# Apply built-in filter
blurred = img.filter(ImageFilter.GaussianBlur(3))
# Adjust brightness
enhancer = ImageEnhance.Brightness(img)
bright = enhancer.enhance(1.5) # 50% brighterWorked Examples
1 Applying Multiple Filters
from PIL import Image, ImageFilter
img = Image.open("photo.jpg")
# Chain filters: sharpen then find edges
result = img.filter(ImageFilter.SHARPEN)
result = result.filter(ImageFilter.FIND_EDGES)
result.save("sketch_effect.png")2 Custom Grayscale Filter (Pixel by Pixel)
from PIL import Image
img = Image.open("photo.jpg")
w, h = img.size
# Convert to grayscale manually
for x in range(w):
for y in range(h):
r, g, b = img.getpixel((x, y))
# Weighted average (human eye sensitivity)
gray = int(0.299 * r + 0.587 * g + 0.114 * b)
img.putpixel((x, y), (gray, gray, gray))
img.save("manual_gray.png")3 Custom Sepia Tone Filter
from PIL import Image
img = Image.open("photo.jpg")
w, h = img.size
for x in range(w):
for y in range(h):
r, g, b = img.getpixel((x, y))
# Sepia formula
tr = min(255, int(0.393*r + 0.769*g + 0.189*b))
tg = min(255, int(0.349*r + 0.686*g + 0.168*b))
tb = min(255, int(0.272*r + 0.534*g + 0.131*b))
img.putpixel((x, y), (tr, tg, tb))
img.save("sepia.png")4 Threshold (Black & White) Filter
from PIL import Image
img = Image.open("photo.jpg")
w, h = img.size
threshold = 128
for x in range(w):
for y in range(h):
r, g, b = img.getpixel((x, y))
avg = (r + g + b) // 3
if avg > threshold:
img.putpixel((x, y), (255, 255, 255)) # white
else:
img.putpixel((x, y), (0, 0, 0)) # black
img.save("bw_threshold.png")5 Custom Color Channel Filter
from PIL import Image
img = Image.open("photo.jpg")
w, h = img.size
# Keep only the red channel
for x in range(w):
for y in range(h):
r, g, b = img.getpixel((x, y))
img.putpixel((x, y), (r, 0, 0))
img.save("red_only.png")Common Pitfalls
filter() Returns a New Image
img.filter() does NOT modify the original. Always assign the result:
blurred = img.filter(ImageFilter.BLUR).
Pixel Values Must Be 0–255
When computing new pixel values, always clamp them: min(255, max(0, value)). Going
above 255 or below 0 causes errors.
Tasks
Write a program that applies Gaussian Blur, then saves the blurred version of any image.
Write a custom "negative" filter that inverts all pixel colors (255 – value).
Create your own "warm" filter: increase red by 20, decrease blue by 20, keep green the same. Apply it pixel-by-pixel.
Self-Check Quiz
Q1: What module provides BLUR, SHARPEN, FIND_EDGES?
ImageFilter from
PIL — used with img.filter(ImageFilter.BLUR).Q2: How would you make an image 50% brighter?
enhancer = ImageEnhance.Brightness(img)bright = enhancer.enhance(1.5)
Q3: What does a threshold filter do?