Dithering
Reduce the number of colors in an image using dithering techniques.
Dithering is like creating a newspaper photo - it uses patterns of dots to create the illusion of more colors than are actually present. When you have a limited color palette (like only black and white), dithering arranges these limited colors in patterns that trick your eye into seeing intermediate shades.
Think of it like pointillist paintings - up close you see individual dots, but from a distance they blend together to create smooth gradients and subtle color variations.
This transform works with ANY number of channels - it processes each channel independently, whether you have a standard RGB image (3 channels), RGBA with transparency (4 channels), multispectral satellite imagery (dozens of channels), or even single-channel grayscale images.
methodWhich dithering algorithm to use. Each has different characteristics:
- "random": Adds random noise before quantization. Creates a grainy, film-like texture. Good for artistic effects or simulating old photographs.
- "ordered": Uses a repeating pattern (Bayer matrix) to decide which pixels to darken. Creates distinctive crosshatch patterns. Fast and predictable. Common in old computer graphics and newspaper printing.
- "error_diffusion": Most sophisticated method. When a pixel is made darker or lighter than it should be, the "error" is spread to neighboring pixels. Creates the most natural-looking results. Like using a fine brush. Default: "error_diffusion"
n_colorsHow many different color levels to keep per channel. Must be between 2 and 256.
- 2 = only black and white (or min/max values for each channel)
- 4 = 4 levels of gray (or 4 levels per color channel)
- 16 = 16 shades, creating a retro computer graphics look
- 256 = full range, no reduction (but patterns still visible from dithering process) Lower values create more dramatic effects. Default: 2
color_modeHow to handle color channels:
- "per_channel": Each color channel (R, G, B, etc.) is dithered separately. Maintains color relationships but each channel gets its own pattern. Works with any number of channels.
- "grayscale": First converts the image to grayscale (using standard luminance weights), then applies dithering, then expands back to the original number of channels. All color information is lost, but the dithering pattern is consistent across channels. Default: "grayscale"
error_diffusion_algorithmUsed only in "error_diffusion" method. Which specific algorithm:
- "floyd_steinberg": The classic, invented in 1976. Spreads error to 4 neighbors. Good balance of quality and speed. Industry standard.
- "jarvis": Jarvis-Judice-Ninke algorithm. Spreads error to 12 neighbors. Higher quality but 3x slower than Floyd-Steinberg.
- "stucki": Similar to Jarvis but with different weights. Also 12 neighbors.
- "atkinson": Created by Bill Atkinson for original Macintosh. Only spreads 75% of error, creating lighter images with more contrast.
- "burkes": Spreads to 7 neighbors. Faster than Jarvis, better than Floyd-Steinberg.
- "sierra": Spreads to 10 neighbors. Good quality, moderate speed.
- "sierra_2row": Simplified Sierra using only 2 rows. Faster.
- "sierra_lite": Minimal Sierra using only 3 neighbors. Very fast. Default: "floyd_steinberg"
bayer_matrix_sizeUsed only in "ordered" method. The size of the repeating pattern (2, 4, 8, or 16).
- 2x2: Very visible checkerboard pattern
- 4x4: Standard, good balance
- 8x8: Finer pattern, less visible
- 16x16: Very fine pattern, almost noise-like Default: 4
serpentineUsed only in "error_diffusion" method. Whether to process rows in alternating directions (left-to-right, then right-to-left). This can reduce visible "worm" artifacts that sometimes appear as diagonal lines. Slightly slower. Default: False
noise_rangeUsed only in "random" method. How much random noise to add before quantization. Larger range = more variation in the dithering pattern. Range: (-1.0, 1.0). Default: (-0.5, 0.5)
pProbability of applying this transform. Default: 0.5
>>> import numpy as np
>>> import albumentations as A
>>> # Prepare sample data
>>> image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
>>>
>>> # Black and white dithering with Floyd-Steinberg
>>> transform = A.Compose([
... A.Dithering(
... method="error_diffusion",
... n_colors=2,
... error_diffusion_algorithm="floyd_steinberg",
... color_mode="grayscale",
... p=1.0
... )
... ])
>>> transformed = transform(image=image)
>>> dithered_image = transformed['image'] # Black and white dithered image
>>>
>>> # Ordered dithering with 16 colors per channel
>>> transform = A.Compose([
... A.Dithering(
... method="ordered",
... n_colors=16,
... bayer_matrix_size=8,
... color_mode="per_channel",
... p=1.0
... )
... ])
>>> transformed = transform(image=image)
>>> dithered_image = transformed['image'] # Reduced color depth with Bayer pattern
>>>
>>> # Random dithering
>>> transform = A.Compose([
... A.Dithering(
... method="random",
... n_colors=4,
... noise_range=(-0.3, 0.3),
... p=1.0
... )
... ])
>>> transformed = transform(image=image)
>>> dithered_image = transformed['image'] # Noisy dithered appearance- Wikipediahttps://en.wikipedia.org/wiki/Dither
- Floyd-Steinberg ditheringhttps://en.wikipedia.org/wiki/Floyd%E2%80%93Steinberg_dithering
- Ordered ditheringhttps://en.wikipedia.org/wiki/Ordered_dithering
- Error diffusion ditheringhttps://en.wikipedia.org/wiki/Error_diffusion