Skip to main content
Open in Kaggle  Open in Colab  Download Notebook
This documentation page is also available as an interactive notebook. You can launch the notebook in Kaggle or Colab, or download it for use with an IDE or local Jupyter installation, by clicking one of the above links.

Problem

You need to apply filters to hundreds of images—blur, sharpen, edge detection, and other enhancements.

Solution

What’s in this recipe:
  • Apply common image filters
  • Test filters before applying
  • Process multiple images in batch
You apply image filters (blur, sharpen, edge detection) to images in your table using custom UDFs that wrap Pillow’s ImageFilter module (relies on PIL/Pillow). This gives you control over filter parameters. You can iterate on transformations before adding them to your table. Use .select() with .collect() to preview results on sample images—nothing is stored in your table. If you want to collect only the first few rows, use .head(n) instead of .collect(). Once you’re satisfied, use .add_computed_column() to apply the filter to all images in your table. For more on this workflow, see Get fast feedback on transformations.

Setup

%pip install -qU pixeltable
import pixeltable as pxt
from PIL import ImageFilter

Load images

# Create a fresh directory (drop existing if present)
pxt.drop_dir('image_demo', force=True)
pxt.create_dir('image_demo')
Connected to Pixeltable database at: postgresql+psycopg://postgres:@/pixeltable?host=/Users/alison-pxt/.pixeltable/pgdata
Created directory ‘image_demo’.
<pixeltable.catalog.dir.Dir at 0x143ea0770>
t = pxt.create_table('image_demo.filters', {'image': pxt.Image})
Created table ‘filters’.
t.insert([
    {'image': 'https://raw.githubusercontent.com/pixeltable/pixeltable/main/docs/resources/images/000000000090.jpg'},
    {'image': 'https://raw.githubusercontent.com/pixeltable/pixeltable/main/docs/resources/images/000000000106.jpg'},
    {'image': 'https://raw.githubusercontent.com/pixeltable/pixeltable/main/docs/resources/images/000000000285.jpg'},
])
Inserting rows into `filters`: 3 rows [00:00, 912.14 rows/s]
Inserted 3 rows with 0 errors.
3 rows inserted, 6 values computed.

Iterate: Apply filters to a few images first

@pxt.udf
def apply_blur(img: pxt.Image) -> pxt.Image:
    """Apply blur filter."""
    return img.filter(ImageFilter.BLUR)

@pxt.udf
def apply_sharpen(img: pxt.Image) -> pxt.Image:
    """Apply sharpen filter."""
    return img.filter(ImageFilter.SHARPEN)

@pxt.udf
def apply_find_edges(img: pxt.Image) -> pxt.Image:
    """Apply edge detection filter."""
    return img.filter(ImageFilter.FIND_EDGES)

@pxt.udf
def apply_edge_enhance(img: pxt.Image) -> pxt.Image:
    """Apply edge enhancement filter."""
    return img.filter(ImageFilter.EDGE_ENHANCE)
# Test blur and sharpen
t.select(
    t.image,
    apply_blur(t.image),
    apply_sharpen(t.image)
).head(1)

Add: Apply filters to all images in your table

# Add filter columns
t.add_computed_column(blurred=apply_blur(t.image))
t.add_computed_column(sharpened=apply_sharpen(t.image))
t.add_computed_column(edges=apply_find_edges(t.image))
t.add_computed_column(edge_enhanced=apply_edge_enhance(t.image))
Added 3 column values with 0 errors.
Added 3 column values with 0 errors.
Added 3 column values with 0 errors.
Added 3 column values with 0 errors.
3 rows updated, 3 values computed.

View results

Compare original and filtered images.
# Compare blur and sharpen
t.select(t.image, t.blurred, t.sharpened).collect()
# Compare edge detection filters
t.select(t.image, t.edges, t.edge_enhanced).collect()

Explanation

How the filter technique works: The UDFs wrap PIL’s ImageFilter module to apply convolution-based filters to images. Each filter uses a predefined kernel that processes pixel neighborhoods to achieve different effects. Blur averages surrounding pixels to reduce detail, Sharpen enhances pixel differences to increase detail, Find Edges detects boundaries between contrasting regions, and Edge Enhance strengthens edges while preserving the full image. You can apply multiple filters to the same image to create different versions for analysis or visual effects. To customize the UDFs: - Blur intensity: Use ImageFilter.BoxBlur(radius) or ImageFilter.GaussianBlur(radius) for adjustable blur strength - Edge detection: Combine with grayscale conversion for clearer edge maps - Filter stacking: Apply multiple filters in sequence for complex effects - Custom kernels: Use ImageFilter.Kernel() to define your own convolution filters The Pixeltable workflow: In traditional databases, .select() just picks which columns to view. In Pixeltable, .select() also lets you compute new transformations on the fly—define new columns without storing them. This makes .select() perfect for testing transformations before you commit them. When you use .select(), you’re creating a query that doesn’t execute until you call .collect(). You must use .collect() to execute the query and return results—nothing is stored in your table. If you want to collect only the first few rows, use .head(n) instead of .collect() to test on a subset before processing your full dataset. Once satisfied, use .add_computed_column() with the same expression to persist results permanently. For more on this workflow, see Get fast feedback on transformations.

See also