Region Growing Segmentation

A radiologist stares at an MRI slice. She tries to outline a tumor's exact boundary among tissue of similar gray levels. Simple thresholding fails here. The tumor and healthy tissue overlap in intensity. A single global cutoff either eats into healthy tissue or leaves gaps in the tumor. What the eye does naturally, algorithms must do explicitly. Start from a point clearly inside the tumor. Expand outward, absorbing neighboring pixels only while they still "belong." This is the core idea behind region growing. It is one of the oldest and most intuitive families of image segmentation algorithms. Region growing matters because it captures spatial coherence. Pixel-wise thresholding cannot do this. Image Thresholding classifies every pixel independently based on intensity alone. It ignores where the pixel sits relative to its neighbors. Region growing instead builds connected components incrementally. It uses both intensity similarity and spatial adjacency. The resulting regions are guaranteed to be contiguous blobs, not scattered speckle. This single property — connectivity by construction — explains its staying power. Region growing remains a standard tool in medical imaging, remote sensing, and industrial inspection. This holds true decades after its introduction. The big picture is a graph-search problem in disguise. Treat every pixel as a node in a grid graph. Connect it to its 4 or 8 neighbors. Grow regions the way breadth-first search grows a connected component. But the "visit" decision is no longer just "unvisited." It is "unvisited AND similar enough to the region." This reframing lets us borrow the correctness and complexity machinery of graph traversal wholesale. The interesting design work happens entirely in the homogeneity criterion. This is the rule that decides whether a candidate pixel still belongs. This article gives a precise algorithmic treatment of seeded region growing. It covers how seeds are chosen. It explains how homogeneity criteria are defined and updated online. It includes the full pseudocode with correct queue/visited-set bookkeeping. It offers a complexity and correctness analysis rooted in graph traversal. It provides a worked numeric trace on a small image. Finally, it covers the classic failure modes — leakage, seed sensitivity, order dependence — that every practitioner must guard against.

Key takeaways
  • Region growing starts from seed pixels and expands connected regions by repeatedly testing neighbor pixels against a homogeneity criterion.
  • It is structurally a breadth-first or best-first graph traversal over the pixel adjacency graph, with a similarity test replacing the plain "visited" check.
  • Homogeneity criteria range from a fixed intensity threshold around the seed to running region statistics (mean, variance) updated as the region grows.
  • Complexity is O(N)O(N) time and space for NN pixels under 4- or 8-connectivity, matching standard graph BFS/DFS bounds.
  • Correctness rests on an invariant: every pixel ever added is connected to a seed through a chain of accepted, similar pixels — this guarantees connected output regions.
  • Its main failure modes are boundary leakage through weak edges, sensitivity to seed placement, and pixel-visit-order dependence; it is often followed by Morphological Operations to clean up the result.
The core insight

Region growing turns segmentation into a graph traversal where a pixel is "visited" only if it is both spatially adjacent to the region and statistically similar to it.

The idea

Region growing is a bottom-up segmentation technique that builds image regions incrementally, starting from one or more seed pixels and repeatedly annexing neighboring pixels that satisfy a homogeneity criterion relative to the growing region. Unlike thresholding, which partitions pixels purely by intensity value, region growing enforces spatial connectivity: a pixel can only join a region if it is adjacent (in the 4-neighbor or 8-neighbor sense) to a pixel already in that region. The output is, by construction, a set of connected components that tile (part of) the image. Three ingredients define any region-growing algorithm. First, the seed set S0S_0: one or more starting pixels, chosen manually, by a grid, or by local extrema of some feature (e.g., pixels with locally minimal gradient magnitude, indicating flat, likely-homogeneous interior points). Second, the connectivity structure: which neighbor pixels are candidates for inclusion — typically the 4 orthogonal neighbors or the 8 including diagonals. Third, the homogeneity predicate H(p,R)H(p, R): a Boolean or thresholded test of whether candidate pixel pp is similar enough to current region RR to be absorbed. Common choices include

∣I(p)−I(seed)∣≤T,∣I(p)−μR∣≤T,∣I(p)−μR∣≤k σR,|I(p) - I(\text{seed})| \le T, \qquad |I(p) - \mu_R| \le T, \qquad |I(p) - \mu_R| \le k\,\sigma_R,

where μR\mu_R and σR\sigma_R are the running mean and standard deviation of intensities inside RR, updated as pixels are added, and TT, kk are user-chosen tolerances. The middle and right variants are strictly more powerful than the seed-only test because they let the region's notion of "typical value" adapt as it grows across a smoothly varying but non-constant surface (e.g., shading gradients), at the cost of being sensitive to growth order and to noisy early absorptions dragging μR\mu_R off target. Region growing sits in the same conceptual family as Image Thresholding but adds the missing ingredient — spatial coherence — and foreshadows Morphological Operations, which are typically applied afterward to smooth jagged region boundaries, fill small holes, and remove spurious pixel-scale artifacts that a purely local homogeneity test cannot prevent.

How it works

The clean way to implement seeded region growing is as a breadth-first search (or, for order-robust variants, a best-first search using a priority queue) over the pixel grid graph, where the "already visited" test of ordinary BFS is augmented with the homogeneity test.

Step 1 — Seed selection. Choose one seed per intended region: manually clicked points, a regular grid of candidate seeds later merged, or automatic seeds at local intensity extrema / low-gradient plateaus. Each seed gets a unique region label.

Step 2 — Initialize. For each seed, create a region record holding its label, its running mean μ\mu, running sum of squares (for variance), and pixel count n=1n=1. Push the seed into a FIFO queue (or priority queue, keyed by similarity) and mark it visited.

Step 3 — Grow. Pop a pixel pp from the queue. For each unvisited neighbor qq of pp (4- or 8-connected):

  • Evaluate the homogeneity predicate H(q,R)H(q, R) using the current running statistics of region RR.
  • If it passes, label qq with RR's label, mark it visited, update RR's running mean/variance to include I(q)I(q), and push qq onto the queue.
  • If it fails, leave qq unvisited (it may later be claimed by a different, adjacent region, or remain unlabeled background).

Step 4 — Terminate. Stop when the queue is empty for every region. Every pixel is now either labeled with exactly one region or left unlabeled (if it never satisfied any region's predicate).

Step 5 (optional) — Post-process. Merge tiny regions into neighbors, relabel unlabeled pixels via nearest-region assignment, and clean boundaries — commonly using Morphological Operations such as opening/closing. ``` function REGION_GROW(image, seeds, T): n_rows, n_cols = image.shape label = array of size (n_rows, n_cols), initialized to UNLABELED visited = array of booleans, initialized to False regions = empty map from label_id -> RegionStats(mean, sum_sq, count) queue = empty FIFO queue # holds (row, col, label_id) for i, (r, c) in enumerate(seeds): label_id = i + 1 label[r][c] = label_id visited[r][c] = True regions[label_id] = RegionStats(mean=image[r][c], sum_sq=image[r][c]^2, count=1) queue.push((r, c, label_id)) while queue is not empty: (r, c, label_id) = queue.pop_front() R = regions[label_id] for (nr, nc) in NEIGHBORS(r, c, connectivity=8): # bounds-checked if not in_bounds(nr, nc): continue if visited[nr][nc]: continue value = image[nr][nc] if HOMOGENEOUS(value, R, T): visited[nr][nc] = True label[nr][nc] = label_id R.count += 1 R.sum += value R.sum_sq += value * value R.mean = R.sum / R.count queue.push((nr, nc, label_id))

# else: leave unvisited; may be claimed later by another region

# or remain UNLABELED forever return label

function HOMOGENEOUS(value, R, T): return abs(value - R.mean) <= T ``` The critical correctness-preserving detail is that `visited` is set at the moment of acceptance, not at the moment of testing — this is exactly the standard BFS discipline that prevents a pixel from being pushed onto the queue by two different regions and processed twice. Ties (a pixel adjacent to two regions, both willing to accept it) are broken by processing order: whichever region reaches it first in the queue claims it. This first-come-first-served rule is simple but is the direct source of order-dependence discussed in the pitfalls below; a priority-queue variant that always expands the globally most similar pending pixel next (a "best-first" region grower) reduces, but does not eliminate, this dependence.

Figure
Region growing as graph BFS: seed expands outward while a homogeneity test gates each edge
Pixel grid (values shown), seed at ★ ★ ★ blue = region A (light source) red = region B (dark object) gray = unlabeled / rejected Underlying process: gated BFS seed H(p,R) fails not enqueued Accept: mark visited, update μ,σ, push to queue Reject: leave unvisited, may join a rival region later

Complexity & correctness

Time complexity. Each pixel is pushed onto the queue at most once, because it is marked `visited` at the moment of acceptance and the algorithm never re-examines a `visited` pixel as a candidate. Popping and processing a pixel does O(1)O(1) work per neighbor under 4- or 8-connectivity (a constant number of neighbors), plus O(1)O(1) amortized work to update running mean/variance incrementally. With NN total pixels, the total work is

O(N⋅c)=O(N),O(N \cdot c) = O(N),

where c∈{4,8}c \in \{4, 8\} is the connectivity constant. This is identical in form to the O(V+E)O(V + E) bound for BFS on a graph, specialized to a grid graph where E=O(N)E = O(N).

Space complexity. The `label` and `visited` arrays are O(N)O(N). The queue holds at most NN pixels at any time, so it is O(N)O(N) as well. Region statistics are O(1)O(1) per region and O(R)O(R) total for RR regions, dominated by the O(N)O(N) terms whenever R≪NR \ll N (the typical case). Total space is O(N)O(N).

Correctness (connectivity invariant). Define the invariant: at every point during execution, every labeled pixel qq with label ℓ\ell is connected to the seed of region ℓ\ell through a path of pixels, each consecutive pair adjacent, each pixel on the path already labeled ℓ\ell. This holds initially (seeds are trivially connected to themselves) and is preserved by the growth step: a pixel qq is only ever labeled ℓ\ell when it is popped as a neighbor of some already-ℓ\ell-labeled pixel pp, so the path to pp's seed extends by one edge to include qq. By induction over the sequence of accept operations, the invariant holds at termination, which proves: > Claim. Every output region is a connected subgraph of the pixel adjacency graph. This is precisely the property thresholding lacks and region growing guarantees by construction — the proof is a direct transcription of the standard BFS reachability argument, with the homogeneity predicate simply pruning which edges are traversable.

What correctness does not guarantee. The invariant says nothing about whether the region is semantically correct (i.e., matches the true object boundary). That depends entirely on how well HH approximates "is part of the same real-world surface," which is a modeling choice, not something the traversal argument can certify. In particular:

  • If two true objects are connected in the image by even a single thin bridge of similar intensity (e.g., a shadow or blur), the algorithm cannot distinguish them — this is leakage, discussed below.
  • The final segmentation can depend on the order in which the queue is processed when a boundary pixel is equally eligible for two regions; FIFO BFS and best-first search can produce different final boundaries, both individually "correct" with respect to the invariant but different from each other.

Tradeoffs. Region growing is cheap and simple, and its output is guaranteed connected and free of the salt-and-pepper noise that pure thresholding produces — but it is a greedy, local algorithm: it never backtracks or reconsiders an earlier acceptance in light of later evidence, so early noisy pixels can permanently bias μR\mu_R and cause a slow "drift" of the region into territory a global view would have excluded. More globally aware alternatives (graph cuts, watershed with markers, level sets) trade this cheapness for the ability to jointly optimize over the whole partition, at higher computational cost.

Worked example

Consider a tiny 5×55 \times 5 grayscale image (intensity values 0–255), with a bright blob in the upper-left and darker background elsewhere. We grow one region from a single seed at (0,0)(0,0) (value 200), using the mean-based homogeneity test with threshold T=15T = 15: accept a neighbor if ∣I(neighbor)−μR∣≤15|I(\text{neighbor}) - \mu_R| \le 15. Image (row, col), 0-indexed: ``` row\col 0 1 2 3 4 0 200 195 120 110 105 1 190 205 115 108 100 2 130 125 118 112 102 3 120 118 116 110 100 4 115 112 110 108 100 ``` Trace of the queue (4-connectivity), showing region mean μR\mu_R before each test:

StepPoppedCandidate neighborValueμR\mu_R (current)∣v−μR∣\lvert v-\mu_R\rvertAccept?New μR\mu_R
1(0,0)(0,1)195200.05.0✓197.5
2(0,0)(1,0)190197.57.5✓195.0
3(0,1)(0,2)120195.075.0✗195.0
4(0,1)(1,1)205195.010.0✓197.5
5(1,0)(1,1)———already visited—
6(1,0)(2,0)130197.567.5✗197.5
7(1,1)(1,2)115197.582.5✗197.5
8(1,1)(2,1)125197.572.5✗197.5

The queue empties after step 8: no further pixel in the frontier passes the test. The final region is exactly {(0,0),(0,1),(1,0),(1,1)}\{(0,0), (0,1), (1,0), (1,1)\} — the four bright corner pixels — while the darker background remains unlabeled, correctly separating the blob from the surrounding tissue-like texture despite the background itself having non-uniform values (110–130) that a naive global threshold at, say, 150 would have handled identically anyway. The instructive part is step 3 versus step 6: pixel (0,2)=120 is rejected early while μR=195\mu_R = 195, but if the algorithm had instead grown down through (2,0)=130 first and drifted μR\mu_R downward before ever reaching (0,2), the same pixel might have been accepted — a direct, concrete illustration of order-dependence: the final region boundary is a function not just of the image and TT, but of traversal order.

Common pitfalls & traps

PitfallWhy it happensConsequenceMitigation
Leakage through weak edgesA thin bridge of similar-enough pixels connects two semantically distinct regionsOne region "floods" into a neighboring objectTighten TT, add gradient-magnitude term to HH, or stop growth at detected edges
Seed sensitivityDifferent seed placement inside the same object yields different μR\mu_R trajectoriesTwo runs on the same image, same object, give different boundariesUse multiple seeds per region + merge, or seed at robust local extrema
Order dependenceFIFO/queue order determines which region claims a contested boundary pixel firstNon-deterministic-looking boundaries between adjacent regionsUse best-first (priority queue by similarity) growth, or resolve ties by comparing candidate regions directly
Statistic driftRunning mean/variance updates let early noisy accepts bias later decisionsRegion "walks" away from the true seed value over many pixelsCap TT relative to seed value, not just running mean; periodically re-anchor to a robust statistic (median)
Off-by-one in visited markingMarking `visited` at pop-time instead of push/accept-timeSame pixel enqueued multiple times, wasted work or double-processingAlways mark visited at the moment of acceptance, before pushing
Ignoring 4- vs 8-connectivity mismatchUsing 8-connectivity for growth but 4-connectivity assumptions downstream (e.g., contour tracing)Regions can be "connected" in a way inconsistent with later processingFix and document one connectivity convention through the whole pipeline

Pioneers & history

Region growing emerged from the earliest wave of digital image processing research, when researchers sought computationally cheap alternatives to global thresholding for photointerpretation and medical scans. The technique's core idea — grow a connected region from a seed using a local similarity test — was formalized and popularized in the image processing literature of the 1970s, alongside split-and-merge quadtree methods that attacked the same problem from the opposite direction (top-down splitting rather than bottom-up growing).

Origins · 1 minAzriel Rosenfeld and how this was discovered
AR
Azriel Rosenfeld
1931–2004 · Pioneer of digital image processing and computer vision, formalized region-based and connectivity concepts foundational to segmentation

Rosenfeld's work on digital topology and picture processing in the 1960s–1980s established the rigorous notion of pixel connectivity (4- vs 8-adjacency) that every region-growing algorithm depends on, and his textbooks helped define image segmentation as a distinct algorithmic subfield.

History
1965
— Early digital image processing systems establish pixel connectivity and neighbor-adjacency formalisms.
1970
— Region-based segmentation techniques, including seeded growing, appear in remote-sensing and photointerpretation pipelines.
1976
— Split-and-merge algorithms (Horowitz and Pavlidis) formalize the complementary top-down view of region-based segmentation.
1994
— Adams and Bischof publish a widely cited formalization of "seeded region growing" with explicit tie-breaking rules for contested pixels.
2000
s — Region growing becomes a standard interactive tool in medical image segmentation software (e.g., tumor and organ delineation), often combined with level-set refinement.

Where this matters

Region growing remains a working tool wherever a human or automated system can supply reliable seed points and needs a fast, interpretable, connectivity-guaranteed segmentation. Medical imaging software uses seeded region growing for interactive tumor, organ, and vessel delineation in MRI and CT, where a clinician clicks a point inside the structure of interest and the algorithm proposes a boundary that a radiologist then edits. Remote sensing pipelines use it to segment land-cover types (water bodies, forest canopy, urban blocks) in satellite imagery, seeding from known ground-truth points. Industrial inspection systems use region growing to isolate a defect region on a manufactured part once a rough location is flagged by a coarser detector. It also serves as a fast preprocessing stage before more expensive graph-based or learned segmentation methods, providing an initial region proposal that is then refined — and it is frequently followed immediately by Morphological Operations to smooth boundaries and by connected-component analysis to filter spurious small regions, reflecting its place as one classical stage in a longer classical vision pipeline that also draws on Image Thresholding and Edge Detection.

Ask the tutor: How would you redesign the homogeneity criterion to make region growing robust against leakage through thin low-contrast bridges?

How does region growing differ from image thresholding?

Thresholding classifies every pixel independently by comparing its intensity (or another feature) to a fixed cutoff, with no notion of position or neighbors — the output can be scattered, disconnected speckle. Region growing instead starts from seed pixels and expands only to spatially adjacent pixels that pass a similarity test, so every output region is connected by construction. Thresholding is essentially a per-pixel classifier; region growing is a constrained graph traversal. In practice they are complementary: thresholding is often used to generate candidate seeds or a rough mask, and region growing then refines it into clean, connected components. Region growing also naturally adapts its notion of "typical value" as it expands, which fixed-threshold methods cannot do.

How should seed points be chosen if no user is available to click them?

Automatic seeding typically looks for pixels that are locally "safe": points with low local gradient magnitude (indicating a flat, homogeneous neighborhood, away from edges), local intensity extrema, or points sampled from a coarse grid and then merged if they end up in the same eventual region. Some pipelines run a cheap clustering or thresholding pass first and pick centroid pixels of the resulting blobs as seeds. The key requirement is that a seed be interior to its intended region and not near ambiguous boundaries, since seed placement directly determines the initial running mean and can bias the whole trajectory of growth, especially for mean-based homogeneity criteria.

What homogeneity criteria are used besides a simple intensity threshold?

Beyond ∣I(p)−μR∣≤T|I(p) - \mu_R| \le T, common variants include a statistical test using the region's standard deviation, ∣I(p)−μR∣≤kσR|I(p) - \mu_R| \le k\sigma_R, which adapts the tolerance to how noisy or textured the region already is; multi-channel criteria comparing color vectors (e.g., Euclidean or Mahalanobis distance in RGB or Lab space); texture-based criteria comparing local statistics like local variance or gradient orientation histograms; and gradient-aware criteria that additionally require the local gradient magnitude to stay below a threshold, explicitly discouraging growth across strong edges to reduce leakage. More sophisticated criteria fuse several of these into a single weighted score.

Does region growing handle images with multiple objects and no clear seeds for each?

Yes, but it requires either multiple seeds (one per intended region, grown simultaneously in the same queue with separate labels, exactly as in the pseudocode) or an iterative scheme that repeatedly finds an unlabeled pixel, treats it as a new seed, and grows a new region, continuing until all pixels are labeled or classified as background. The multi-seed simultaneous variant is more common in practice because it lets regions compete for contested boundary pixels in a single consistent pass, rather than having an arbitrary processing order across separate single-region runs bias the final partition.

How does region growing compare to more modern segmentation methods like graph cuts or deep learning?

Region growing is a greedy, local, single-pass method: cheap (O(N)O(N) time), simple to implement, and interpretable, but it never revisits or globally optimizes a decision once made. Graph cuts formulate segmentation as a global energy minimization over the whole image, jointly balancing region homogeneity against boundary smoothness, which handles leakage and ambiguous boundaries far better but costs more computation (typically polynomial in NN via max-flow, still efficient but with larger constants). Deep learning segmentation networks learn the homogeneity criterion itself from data rather than hand-specifying it, generalizing far better to complex real-world imagery but requiring large labeled datasets and significant training compute. Region growing remains useful as a fast baseline, an interactive tool, or a component inside larger pipelines.

What typically happens after region growing in a classical vision pipeline?

Region-grown segmentations often have jagged, pixel-scale boundary noise and can contain tiny spurious regions from isolated accepts or rejects near the true boundary. A common next step applies Morphological Operations such as opening (erosion then dilation) to remove small protrusions and closing (dilation then erosion) to fill small holes, smoothing the region boundary without changing its overall shape. Connected-component filtering is then used to discard regions below a minimum pixel-count threshold, and the cleaned masks are passed on to downstream tasks like measurement, tracking, or feature extraction.

Can region growing use 8-connectivity, and does that change correctness?

Yes — 8-connectivity (including diagonal neighbors) is a common choice and does not affect the connectivity correctness argument, since the invariant only requires that the adjacency relation used for growth matches the adjacency relation used to define "connected region," whichever one is chosen. It does change the result: 8-connectivity allows regions to bridge across diagonal gaps that 4-connectivity would leave as separate components, generally producing larger, more merged regions and being more prone to leakage through diagonal-only bridges. The choice should be made once and used consistently with any downstream connected-component or contour-tracing code, since mismatched conventions are a classic source of subtle bugs.

Before this

Where this leads