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