Albumentations to PIL/Pillow Transform Mapping

On this page

This page maps Albumentations transforms to the closest Pillow operation when Pillow has a practical direct equivalent. Use it as a migration and capability guide, not as a performance page.

How to Read This Page

  • A named Pillow operation means Pillow has a practical direct image operation for the same idea.
  • - means Pillow does not support that transform as an augmentation primitive.
  • The table shows built-in Pillow operations that directly correspond to Albumentations transforms. Custom Pillow implementations are not counted as Pillow support.
  • Pillow mappings are image-only. Target updates are still not supported by Pillow.

Channel and Target Caveats

Pillow operations are built around image modes such as L, RGB, and RGBA. Many color operations either convert to grayscale/RGB or assume RGB-style channels. Albumentations operates on NumPy arrays, so many image-only transforms can preserve arbitrary channel counts. RGB/color-space transforms still have channel-specific constraints.

Pillow transforms do not update masks, bounding boxes, keypoints, oriented bounding boxes (OBB), volumes, or videos. Albumentations transforms are pipeline operations and can update supported targets in the same call.

Pillow also does not provide an augmentation-policy layer comparable to Albumentations Compose, OneOf, SomeOf, or RandomOrder. Combining crop, flip, normalization, and optional branches means writing the policy as Python control flow. In Albumentations, the policy is a serializable pipeline object that works before tensors enter PyTorch, TensorFlow/Keras, JAX, or a custom GPU-training loop.

Direct Pillow Mappings

Albumentations transformPillow operation
ResizeImage.resize
HorizontalFlipImage.transpose(FLIP_LEFT_RIGHT)
VerticalFlipImage.transpose(FLIP_TOP_BOTTOM)
TransposeImage.transpose(TRANSPOSE)
RotateImage.rotate
PadImageOps.expand
AffineImage.transform(AFFINE)
RandomBrightnessContrastImageEnhance.Brightness / ImageEnhance.Contrast
HueSaturationValueImageEnhance.Color
AutoContrastImageOps.autocontrast
EqualizeImageOps.equalize
ToGrayImageOps.grayscale(...).convert("RGB")
InvertImgImageOps.invert
PosterizeImageOps.posterize
SolarizeImageOps.solarize
ColorizeImageOps.colorize
DitheringImage.convert("L").convert("1", dither=FLOYDSTEINBERG).convert("RGB")
GaussianBlurImageFilter.GaussianBlur
MedianBlurImageFilter.MedianFilter
BlurImageFilter.BoxBlur
UnsharpMaskImageFilter.UnsharpMask
EnhanceImageFilter.EDGE_ENHANCE_MORE / ImageFilter.DETAIL
ImageCompressionJPEG save/load roundtrip

No Direct Pillow Mapping

Migration Pattern

Pillow can do the image edits, but the random augmentation policy becomes regular Python code:

import random
from PIL import Image
from PIL import ImageEnhance, ImageFilter

image = Image.open("image.jpg").convert("RGB")

if random.random() < 0.5:
    image = image.transpose(Image.Transpose.FLIP_LEFT_RIGHT)

if random.random() < 0.5:
    angle = random.uniform(-45, 45)
    image = image.rotate(angle, resample=Image.Resampling.BILINEAR, fillcolor=0)

if random.random() < 0.3:
    if random.random() < 0.5:
        image = image.filter(ImageFilter.GaussianBlur(radius=random.uniform(1.5, 3.5)))
    else:
        # Gaussian noise is not a Pillow augmentation primitive.
        pass

if random.random() < 0.5:
    image = ImageEnhance.Brightness(image).enhance(random.uniform(0.8, 1.2))
    image = ImageEnhance.Contrast(image).enhance(random.uniform(0.8, 1.2))

The same policy in Albumentations is a pipeline object:

import numpy as np
from PIL import Image
import albumentations as A

image = np.array(Image.open("image.jpg").convert("RGB"))

pipeline = A.Compose(
    [
        A.HorizontalFlip(p=0.5),
        A.Rotate(angle_range=(-45, 45), border_mode=0, fill=0, p=0.5),
        A.OneOf(
            [
                A.GaussianBlur(blur_range=(3, 7), p=1.0),
                A.GaussNoise(std_range=(0.05, 0.2), p=1.0),
            ],
            p=0.3,
        ),
        A.RandomBrightnessContrast(
            brightness_range=(-0.2, 0.2),
            contrast_range=(-0.2, 0.2),
            p=0.5,
        ),
    ],
)

augmented = pipeline(image=image)["image"]

For non-RGB data, keep the array shape you actually train on and avoid RGB-only transforms unless the conversion is intentional.

Because this is an Albumentations pipeline object, you can serialize it and reuse the same augmentation definition outside the notebook or training script.