Image processing with scipy.ndimage

Filter, label, measure and transform N-dimensional arrays, with an eye on the coordinate convention that trips everyone up once.

Filtering and morphology

import numpy as np
from scipy import ndimage as ndi

img = np.random.default_rng(0).random((200, 200))
blurred = ndi.gaussian_filter(img, sigma=2.0)
edges = ndi.sobel(blurred, axis=0)

mask = blurred > 0.6
opened = ndi.binary_opening(mask, structure=np.ones((3, 3)), iterations=1)
filled = ndi.binary_fill_holes(opened)
dilated = ndi.binary_dilation(filled, iterations=2)
  • The default mode="reflect" pads virtually at the boundary; other options are constant, nearest, wrap and mirror.
  • sigma is in array index units, not physical units. Convert from physical distance yourself.
  • Morphology operators need a boolean or integer array; passing a float array silently applies a different rule.

Labelling and measuring regions

labels, n = ndi.label(filled, structure=np.ones((3, 3)))
print("components:", n)

sizes = ndi.sum_labels(np.ones_like(labels), labels, index=np.arange(1, n + 1))
coms = ndi.center_of_mass(filled, labels, index=np.arange(1, n + 1))

objects = ndi.find_objects(labels)
for i, sl in enumerate(objects, start=1):
    if sizes[i - 1] < 50:                 # drop specks
        labels[sl][labels[sl] == i] = 0

kept = ndi.label(labels > 0)[1]
print("after filtering:", kept)
FunctionReturns
labelInteger labels plus the count of components
sum / meanPer-label or per-axis aggregates
center_of_massCentroid coordinates of each labelled region
find_objectsBounding-box slices you can index with
maximum_positionCoordinate of the brightest pixel per label

Transforms and interpolation

rotated = ndi.rotate(img, angle=30, reshape=True, order=1)
zoomed = ndi.zoom(img, zoom=2.0, order=3)
shifted = ndi.shift(img, shift=(5, -3), mode="nearest")

matrix = np.array([[1, 0.2, 0], [0, 1, 0], [0, 0, 1]])
sheared = ndi.affine_transform(img, matrix, offset=0.0, order=1)

import matplotlib.pyplot as plt
plt.imshow(sheared, cmap="gray", origin="upper")
plt.axis("off")
⚠️
ndimage works on plain arrays in (row, column) order — index 0 is y, index 1 is x. Coordinates from center_of_mass and maximum_position follow the same convention, so plotting them on an imshow chart means swapping the two values.

FAQ

Should I use ndimage or scikit-image?
For filtering, labelling, morphology and geometry on arrays, ndimage is compact and fast. For higher-level work — feature detection, segmentation, region properties, colour-space conversion, reading image files — scikit-image has the richer API and often a clearer result.
Why did binary_opening remove my small objects?
Opening erodes then dilates, so any structure thinner than the structuring element disappears. Reduce the element size, or apply closing instead if the real problem is small holes rather than specks.

FFT and spectral analysis with scipy.fft Statistics and signal processing

Last refreshed 2026-09-18.