Thresholding & Segmentation
Separating foreground from background using global and adaptive thresholding, and Otsu's method.
Learning Objectives
- ✓Apply manual global thresholding
- ✓Use Otsu's automatic threshold selection
- ✓Apply adaptive local thresholding for uneven lighting
- ✓Label connected regions in binary images
Global Thresholding
Global thresholding applies a single threshold T to the whole image. If pixel > T → white (foreground), else → black (background). Manual selection requires domain knowledge. cv2.THRESH_BINARY is the basic mode.
import cv2
img = cv2.imread('coins.jpg', cv2.IMREAD_GRAYSCALE)
# Manual threshold at 127
_, binary_manual = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)Otsu's Automatic Thresholding
Otsu's method automatically finds the threshold T that minimizes within-class variance (equivalently, maximizes between-class variance). Pass cv2.THRESH_OTSU flag and set threshold to 0 — OpenCV computes the optimal T.
# Otsu's method - threshold value is computed automatically
T_otsu, binary_otsu = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
print(f'Otsu threshold: {T_otsu}')Adaptive Local Thresholding
When lighting varies across the image, a single global threshold fails. Adaptive thresholding computes a different threshold for each pixel based on a local neighborhood. Two methods: mean of neighborhood or Gaussian-weighted mean.
# Adaptive mean threshold (block size 11, constant C=2)
adaptive_mean = cv2.adaptiveThreshold(
img, 255,
cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY, 11, 2
)
# Adaptive Gaussian threshold
adaptive_gauss = cv2.adaptiveThreshold(
img, 255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2
)Region Labeling
After binarization, connected-component labeling assigns a unique integer label to each connected region (blob). cv2.connectedComponentsWithStats() returns the label map and statistics (area, bounding box) for each region.
import cv2
import numpy as np
img = cv2.imread('objects.jpg', cv2.IMREAD_GRAYSCALE)
_, binary = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary)
print(f'Found {num_labels - 1} regions (excluding background)')