SciPy Cheatsheet

Image Processing (ndimage)

Use this SciPy reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Core Import

from scipy import ndimage
import numpy as np

# Common direct imports
from scipy.ndimage import (
    gaussian_filter, median_filter, uniform_filter,
    maximum_filter, minimum_filter, percentile_filter,
    sobel, laplace, gaussian_laplace,
    convolve, correlate,
    binary_erosion, binary_dilation, binary_opening, binary_closing,
    binary_fill_holes,
    label, find_objects, center_of_mass, sum_labels,
    distance_transform_edt,
    zoom, rotate, shift, affine_transform, map_coordinates
)

scipy.ndimage works on arrays of ANY dimension — the same gaussian_filter smooths a 1-D signal, a 2-D image, or a 3-D volume.

Smoothing & Rank Filters

img = np.random.rand(256, 256)

# Gaussian blur (sigma in pixels; can differ per axis)
smooth = gaussian_filter(img, sigma=2)
smooth = gaussian_filter(img, sigma=(3, 1))     # anisotropic

# Median filter (great for salt-and-pepper noise)
den = median_filter(img, size=3)

# Uniform (box) filter
box = uniform_filter(img, size=5)

# Rank filters
mx = maximum_filter(img, size=3)
mn = minimum_filter(img, size=3)
p90 = percentile_filter(img, percentile=90, size=5)

# Boundary handling (all filters): mode = 'reflect' (default),
# 'constant', 'nearest', 'mirror', 'wrap'
smooth = gaussian_filter(img, sigma=2, mode='constant', cval=0.0)

Edges & Derivatives

from scipy.ndimage import sobel, laplace, gaussian_laplace, gaussian_gradient_magnitude

# Sobel edge detection (per axis)
sx = sobel(img, axis=0)     # vertical gradient
sy = sobel(img, axis=1)     # horizontal gradient
edges = np.hypot(sx, sy)    # gradient magnitude

# Laplacian
lap = laplace(img)

# Laplacian of Gaussian (blob detection)
log = gaussian_laplace(img, sigma=2)

# Gradient magnitude with built-in smoothing
gm = gaussian_gradient_magnitude(img, sigma=2)

Convolution & Correlation

from scipy.ndimage import convolve, correlate

kernel = np.array([[0, 1, 0],
                   [1, -4, 1],
                   [0, 1, 0]])

out = convolve(img, kernel, mode='reflect')
out = correlate(img, kernel)   # correlation = convolution w/o kernel flip

Binary Morphology

from scipy.ndimage import (
    binary_erosion, binary_dilation, binary_opening, binary_closing,
    binary_fill_holes, generate_binary_structure
)

mask = img > 0.5

er = binary_erosion(mask)                       # shrink objects
di = binary_dilation(mask, iterations=2)        # grow objects
op = binary_opening(mask)                       # remove small specks
cl = binary_closing(mask)                       # close small holes/gaps
filled = binary_fill_holes(mask)                # fill enclosed holes

# Structuring element (connectivity)
st = generate_binary_structure(rank=2, connectivity=2)  # 8-connectivity
er = binary_erosion(mask, structure=st)

Labeling & Measurements

from scipy.ndimage import label, find_objects, center_of_mass, sum_labels, mean

mask = img > 0.8

# Connected-component labeling
labels, n = label(mask)          # labels: int array, n components

# Bounding-box slices per component
slices = find_objects(labels)
component_0 = img[slices[0]]

# Per-component measurements
idx = np.arange(1, n + 1)
sizes = sum_labels(mask, labels, index=idx)             # pixel counts
means = mean(img, labels=labels, index=idx)             # mean intensity
coms = center_of_mass(img, labels=labels, index=idx)    # centroids

# Remove small components
keep = sizes >= 20
mask_clean = keep[labels - 1] & (labels > 0)

Distance Transform

from scipy.ndimage import distance_transform_edt

# Euclidean distance from each True pixel to the nearest False pixel
dist = distance_transform_edt(mask)

# Also return the index of the nearest background pixel
dist, idx = distance_transform_edt(mask, return_indices=True)

Geometric Transforms

from scipy.ndimage import zoom, rotate, shift, affine_transform, map_coordinates

# Resize by a factor (spline interpolation, order 0-5; default 3)
big = zoom(img, 2.0)                    # 2x upsample
small = zoom(img, 0.5, order=1)         # bilinear downsample

# Rotate (degrees, counterclockwise)
rot = rotate(img, angle=30)             # output grows to fit
rot = rotate(img, angle=30, reshape=False)

# Subpixel shift
sh = shift(img, shift=(5.5, -2.25))

# Affine: output[o] = input[matrix @ o + offset]
mat = np.array([[0.5, 0], [0, 0.5]])    # 2x magnification
out = affine_transform(img, mat, offset=0, output_shape=img.shape)

# Sample at arbitrary coordinates (rows, cols)
coords = np.array([[10.5, 20.1], [30.2, 40.7]])   # shape (ndim, n_points)
vals = map_coordinates(img, coords, order=1)

Common Gotchas

zoom/rotate default to cubic splines (order=3), which can overshoot and produce values outside the input range (e.g. negative intensities). Use order=1 (linear) or clip the output for masks and physical data — and order=0 for label images, or labels will be blended.

Binary morphology defaults to 4-connectivity (cross-shaped structuring element) in 2-D. Pass structure=generate_binary_structure(2, 2) for 8-connectivity — label has the same default.

mode='reflect' is the default boundary for filters, but mode='constant', cval=0 is the default for geometric transforms (zoom, rotate, shift). Edge artifacts often come from this mismatch.

center_of_mass and friends return (row, col) order — numpy index order, not (x, y). Swap before plotting with matplotlib's scatter(x, y).