What is image thresholding?

Image thresholding is a fundamental technique in image processing, used to separate objects or regions of interest from the background in a digital image. The main objective of thresholding is to convert a grayscale or color image into a binary image, where pixels are categorized into two classes based on their intensity values: foreground (object) and background.

In binary images, pixel values are typically represented using only two intensity levels: 0 (black) and 255 (white). Image thresholding is applied by comparing each pixel’s intensity value to a predetermined threshold value. If the pixel value is greater than or equal to the threshold, it is assigned to the foreground class; otherwise, it is assigned to the background class.

Types of image thresholding

Several image thresholding techniques are used to handle different types of images and scenarios. Some basic techniques are:

  • Binary thresholding

  • Inverse binary thresholding

  • Truncated thresholding

  • To-zero thresholding

  • Inverse to-zero thresholding

  • Mean adaptive thresholding

  • Adaptive Gaussian thresholding

  • Otsu’s thresholding

Binary thresholding

Binary thresholding segments an image into two classes based on a fixed threshold value. Pixels with intensities greater than or equal to the threshold are set to the maximum value (white), while pixels with intensities lower than the threshold are set to the minimum value (black). This method is ideal for images with well-defined foreground and background, where a single threshold value can effectively separate objects of interest from the background. Here is the Python implementation for binary thresholding:

# Import the necessary libraries, OpenCV(cv2) and NumPy
import cv2
import numpy as np
# Read the input image in grayscale mode (cv2.IMREAD_GRAYSCALE)
img = cv2.imread('input_image.png', cv2.IMREAD_GRAYSCALE)
# Set the binary threshold value to 127
threshold = 127
# Perform binary thresholding on the grayscale image
binary_thresh = np.where(img >= threshold, 255, 0)

Inverse binary thresholding

Inverse binary thresholding is similar to binary thresholding, but the roles of black and white regions are inverted. Pixels with intensities greater than the threshold are set to the minimum value (black), while pixels with intensities lower than the threshold are set to the maximum value (white). This technique is useful when the objects of interest have lower intensities than the background, and the threshold separates the background from the darker objects.

# Import the necessary libraries, OpenCV(cv2) and NumPy
import cv2
import numpy as np
# Read the input image in grayscale mode (cv2.IMREAD_GRAYSCALE)
img = cv2.imread('input_image.png', cv2.IMREAD_GRAYSCALE)
# Set the binary threshold value to 127
threshold = 127
# Perform inverse binary thresholding on the grayscale image
inverse_thresh = np.where(img >= threshold, 0, 255)

Truncated thresholding

Truncated thresholding sets all pixel values greater than the threshold to the threshold value itself. In other words, it "truncates" the intensities above the threshold. It works well for images with a narrow intensity range, where you want to truncate the high-intensity values while preserving the lower ones.

# Import the necessary libraries, OpenCV(cv2) and NumPy
import cv2
import numpy as np
# Read the input image in grayscale mode (cv2.IMREAD_GRAYSCALE)
img = cv2.imread('input_image.png', cv2.IMREAD_GRAYSCALE)
# Set the binary threshold value to 127
threshold = 127
# Perform truncated thresholding on the grayscale image
trunc_thresh = np.where(img >= threshold, threshold, img)

To-zero thresholding

To-zero thresholding sets all pixel values less than the threshold to zero. It segments the darker regions to black. It is often used to enhance certain regions in the image or to remove noise and low-intensity background.

# Import the necessary libraries, OpenCV(cv2) and NumPy
import cv2
import numpy as np
# Read the input image in grayscale mode (cv2.IMREAD_GRAYSCALE)
img = cv2.imread('input_image.png', cv2.IMREAD_GRAYSCALE)
# Set the binary threshold value to 127
threshold = 127
# Perform to-zero thresholding on the grayscale image
to_zero_thresh = np.where(img >= threshold, img, 0)

Inverse to-zero thresholding

Inverse to-zero thresholding is the opposite of to-zero thresholding. It sets all pixel values greater than the threshold to zero and segments the brighter regions to black. This technique is helpful in highlighting lower intensity objects while suppressing the brighter areas.

# Import the necessary libraries, OpenCV(cv2) and NumPy
import cv2
import numpy as np
# Read the input image in grayscale mode (cv2.IMREAD_GRAYSCALE)
img = cv2.imread('input_image.png', cv2.IMREAD_GRAYSCALE)
# Set the binary threshold value to 127
threshold = 127
# Perform truncated thresholding on the grayscale image
inverse_to_zero_thresh = np.where(img >= threshold, 0, img)

Mean adaptive thresholding

Mean adaptive thresholding calculates different threshold values for different regions of the image based on the local pixel neighborhood. It works well in cases where the lighting conditions vary across the image.

# Import the necessary libraries, OpenCV(cv2) and NumPy
import cv2
import numpy as np
# Read the input image in grayscale mode
img = cv2.imread('input_image.png', cv2.IMREAD_GRAYSCALE)
# Set the size of the block for adaptive thresholding
block_size = 11
# Set the constant value used to compute the threshold
constant = 2
# Create a new image to store the result of adaptive mean thresholding
adaptive_mean_thresh = np.zeros_like(img, dtype=np.uint8)
# Get the height and width of the input image
height, width = img.shape
# Loop through the image in block_size steps
for y in range(0, height, block_size):
for x in range(0, width, block_size):
# Extract a block of the image based on the current coordinates
block = img[y:y + block_size, x:x + block_size]
# Compute the threshold using the mean of the block intensity values minus the constant
threshold = np.mean(block) - constant
# Apply the thresholding operation to the block:
# Set pixel values in the adaptive_mean_thresh image to 255 if the corresponding pixel in the block is greater than or equal to the threshold, otherwise set it to 0
adaptive_mean_thresh[y:y + block_size, x:x + block_size] = np.where(block >= threshold, 255, 0)

In the code above, the image is then divided into blocks, and we traverse through the image with steps equal to the block_size. For each block in the image, the threshold value is computed as the mean intensity of the pixels within the block minus the constant value. With NumPy's where function, thresholding is done on each block. Pixels greater than or equal to threshold are set to 255 (white), while pixels less than threshold are set to 0 (black).

Adaptive Gaussian thresholding

Gaussian adaptive thresholding calculates different threshold values for different regions based on the local pixel neighborhood's Gaussian weights. It is also effective in handling varying lighting conditions. This method is particularly useful for images with uneven lighting conditions and varying contrasts.

# Import the necessary libraries, OpenCV(cv2) and NumPy
import cv2
import numpy as np
# Read the input image in grayscale mode
img = cv2.imread('input_image.png', cv2.IMREAD_GRAYSCALE)
# Set the size of the block for adaptive thresholding
block_size = 11
# Set the constant value used to compute the threshold
constant = 0.9
# Create a new image to store the result of adaptive Gaussian thresholding
adaptive_gaussian_thresh = np.zeros_like(img, dtype=np.uint8)
# Get the height and width of the input image
height, width = img.shape
# Loop through the image in block_size steps
for y in range(0, height, block_size):
for x in range(0, width, block_size):
# Extract a block of the image based on the current coordinates
block = img[y:y + block_size, x:x + block_size]
# Compute the threshold using the mean of the block intensity values minus a fraction of the standard deviation
threshold = np.mean(block) - constant * np.std(block)
# Apply the thresholding operation to the block:
# Set pixel values in the adaptive_gaussian_thresh image to 255 if the corresponding pixel in the block is greater than or equal to the threshold, otherwise set it to 0
adaptive_gaussian_thresh[y:y + block_size, x:x + block_size] = np.where(block >= threshold, 255, 0)

In the code above, the image is then divided into blocks, and we traverse through the image with steps equal to block_size. The adaptive thresholding calculates the threshold for each block based on the mean and standard deviation of pixel intensities within the block. If a pixel's intensity value in the block is greater than or equal to the computed threshold, it is set to 255 (white); otherwise, it is set to 0 (black).

Otsu’s thresholding

Otsu's thresholding is an automatic thresholding technique that calculates the optimal threshold value by maximizing the inter-class variance. It works well with bimodal images, where the pixel intensities can be separated into two distinct classes.

# Import the necessary libraries, OpenCV(cv2) and NumPy
import cv2
import numpy as np
# Read the input image in grayscale mode
img = cv2.imread('input_image.png', cv2.IMREAD_GRAYSCALE)
# Compute the histogram of the image
hist, _ = np.histogram(img, bins=256, range=(0, 256))
# Calculate the total number of pixels in the image
total_pixels = img.shape[0] * img.shape[1]
# Calculate the sum of (pixel value * frequency) for all pixel values
sum_total = np.sum(np.arange(256) * hist)
# Variables to keep track of the sum and frequencies for background and foreground pixels during threshold calculation
sum_back = 0
w_back = 0
w_fore = 0
# Variables to keep track of the maximum inter-class variance and the corresponding threshold
max_variance = 0
threshold = 0
# Iterate through all possible threshold values (0 to 255)
for i in range(256):
# Incrementally add the current pixel value to the sum and update the frequency for the background
w_back += hist[i]
if w_back == 0:
continue
# Calculate the frequency for the foreground
w_fore = total_pixels - w_back
if w_fore == 0:
break
# Update the sum for the background
sum_back += i * hist[i]
# Calculate the mean values for background and foreground
mean_back = sum_back / w_back
mean_fore = (sum_total - sum_back) / w_fore
# Calculate the inter-class variance using the current threshold
variance = w_back * w_fore * ((mean_back - mean_fore) ** 2)
# Update the maximum variance and the corresponding threshold if needed
if variance > max_variance:
max_variance = variance
threshold = i
# Create the binary image using the Otsu threshold
otsu_thresh = np.where(img >= threshold, 255, 0).astype(np.uint8)

The code above reads an input image in grayscale and computes its histogram. Then, it iterates through all possible threshold values (0 to 255) and calculates the inter-class variance for each threshold. The inter-class variance measures the separability of foreground and background pixel intensities. The optimal threshold is the one that maximizes the inter-class variance. The threshold value that results in the maximum variance is chosen. Finally, the binary image otsu_thresh is created by setting pixel values to 255 (white) for the pixels in the input image that have intensities greater than or equal to the computed threshold and 0 (black) for the rest.

Summary

Image thresholding is an image processing technique for converting grayscale or color images into binary representations based on pixel intensity values. The choice of the appropriate thresholding method directly impacts the accuracy of image analysis tasks. Distinct methods offer distinct features for specific image characteristics and applications.

Here is a comparison table highlighting their key features and typical use cases:

Thresholding technique

Key features

Typical use case

Binary

Simple, fixed threshold value

Well defined foreground-background

Inverse binary

Inverts the roles of background and foreground

Objects darker than background

Truncated

Intensity values above threshold are set to threshold

To achieve narrow intensity range

To-zero

Low-intensity pixels set to zero

Enhancing regions, removing noise

Inverse to-zero

High-intensity pixels set to zero

Suppressing high-intensity regions

Mean adaptive

Locally determined threshold based on mean

Non-uniform illumination

Adaptive Gaussian

Threshold set by weighted sum with Gaussian

Uneven lighting, varying contrasts

Otsu

Automatically calculates optimal threshold

Bimodal images

Free Resources

Copyright ©2024 Educative, Inc. All rights reserved