Region Growing and Watershed - iffatAGheyas/computer-vision-handbook GitHub Wiki
✂️ Region Growing & Watershed Segmentation
Segmentation divides an image into meaningful regions. Two classic methods are Region Growing, which expands from seed points, and the Watershed algorithm, which treats an image as a topographic map and “floods” basins to find boundaries.
1. Region Growing
What Is It?
A seed‐based method that starts from one or more pixels and adds neighbouring pixels whose intensity or colour is similar enough.
Like dripping ink on tissue paper: it spreads until it hits a boundary.
How It Works
- Choose seed point(s)
- Compare neighbours: if a neighbour’s value is within a threshold, include it
- Repeat for each newly added pixel
Limitations
- Requires manual or automatic seed selection
- Not a single built-in OpenCV function (usually custom code or connected components)
2. Watershed Algorithm — Simulated Water Flow
What Is It?
Interprets the grayscale image as a topographic surface:
- Bright regions → “hills”
- Dark regions → “valleys”
Rain “floods” each valley; where floods meet, dams form—these dams become segment boundaries.
Steps in Watershed Segmentation
- Convert to grayscale
- Threshold (e.g. Otsu or edge detection)
- Remove noise with morphological opening
- Find sure background by dilation
- Find sure foreground via distance transform + threshold
- Mark unknown region (subtract foreground from background)
- Label markers with
cv2.connectedComponents()
- Apply
cv2.watershed()
→ boundaries marked as –1
Python Code: Watershed Example
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 1. Load and pre-process
img = cv2.imread("bird.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 0, 255,
cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 2. Noise removal
kernel = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN,
kernel, iterations=2)
# 3. Sure background
sure_bg = cv2.dilate(opening, kernel, iterations=3)
# 4. Sure foreground
dist = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
_, sure_fg = cv2.threshold(dist,
0.7 * dist.max(),
255, 0)
sure_fg = np.uint8(sure_fg)
# 5. Unknown region
unknown = cv2.subtract(sure_bg, sure_fg)
# 6. Marker labelling
_, markers = cv2.connectedComponents(sure_fg)
markers = markers + 1
markers[unknown == 255] = 0
# 7. Apply watershed
img_ws = img.copy()
markers = cv2.watershed(img_ws, markers)
img_ws[markers == -1] = [255, 0, 0] # red boundary
# 8. Display
img_rgb = cv2.cvtColor(img_ws, cv2.COLOR_BGR2RGB)
plt.figure(figsize=(6, 6))
plt.imshow(img_rgb)
plt.title("Watershed Segmentation")
plt.axis("off")
plt.show()
✅ Summary: Region Growing vs Watershed
Feature | Region Growing | Watershed |
---|---|---|
Type | Seed-based expansion | Topographic flooding |
Requires Seed | ✅ Yes (manual or auto) | ✅ Yes (foreground/background) |
Boundary Sharpness | ❌ Not always sharp | ✅ Sharp contour boundaries |
OpenCV Support | ❌ Custom implementation | ✅ cv2.watershed() |