Filters, enhancement and ImageOps

Pillow · Practical · 10 min

These three modules cover most photo-editing and data-augmentation needs without writing pixel code.

`ImageFilter` provides filters applied with im.filter(...):

  • GaussianBlur(radius), BoxBlur(radius)
  • UnsharpMask(radius, percent, threshold): the standard sharpening tool; SHARPEN is a simpler fixed kernel
  • FIND_EDGES, CONTOUR, EMBOSS, SMOOTH, DETAIL
  • MedianFilter(size), MinFilter, MaxFilter: rank filters, good against speckle noise
  • Kernel(size, kernel): your own 3x3 or 5x5 convolution

`ImageEnhance` classes each wrap an image and expose enhance(factor), where 1.0 returns the original, below 1 reduces and above 1 increases: Brightness, Contrast, Color (saturation; 0 gives grayscale) and Sharpness.

`ImageOps` has ready-made operations: grayscale, invert, autocontrast(im, cutoff=2) (stretch the histogram, ignoring the extreme 2%), equalize, posterize, solarize, expand(im, border, fill) for borders, pad, and colorize for tinting grayscale images.

All of these return new images. Some filters work only on certain modes: most need L or RGB, and palette images should be converted first. im.point(func_or_table) maps each pixel value through a function or lookup table, which is how you build custom curves efficiently.

Example

from PIL import Image, ImageEnhance, ImageFilter, ImageOps

im = Image.linear_gradient("L").resize((64, 64)).convert("RGB")
im.paste((200, 30, 30), (16, 16, 48, 48))           # red square

blur = im.filter(ImageFilter.GaussianBlur(3))
sharp = im.filter(ImageFilter.UnsharpMask(radius=2, percent=150, threshold=3))
edges = im.convert("L").filter(ImageFilter.FIND_EDGES)
print(blur.size == im.size, edges.mode)             # True L

gray = ImageEnhance.Color(im).enhance(0.0)          # saturation 0 = gray look
r, g, b = gray.getpixel((32, 32))
print(r == g == b)                                  # True
darker = ImageEnhance.Brightness(im).enhance(0.5)
print(darker.getpixel((32, 32)))                    # (100, 15, 15)

dull = Image.new("L", (10, 1))
dull.putdata(list(range(100, 110)))
print(ImageOps.autocontrast(dull).getextrema())     # (0, 255)
print(ImageOps.invert(im).getpixel((32, 32)))       # (55, 225, 225)
print(dull.point(lambda v: 255 if v > 104 else 0).getextrema())  # (0, 255)

Remember

  • im.filter(ImageFilter.X) applies blurs, sharpening, edges, rank filters
  • ImageEnhance.<Kind>(im).enhance(f): 1.0 = unchanged
  • ImageOps has autocontrast, equalize, invert, expand, pad and more
  • im.point maps pixel values through a function or table

Watch out for

  • Applying filters to a P-mode image and getting errors or odd results; convert to RGB or L first.

Check yourself

  1. What does `ImageEnhance.Contrast(im).enhance(1.0)` return?
  2. Which filter is the usual choice for sharpening photos with control over strength?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: pillow.readthedocs.io/en/stable/reference/ImageFilter.html

Builds on

Unlocks

Nothing builds on this yet.