SciPy Cheatsheet

Image Processing (ndimage)

Use this SciPy reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

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).