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.
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 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 NumPyimport cv2import 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 127threshold = 127# Perform binary thresholding on the grayscale imagebinary_thresh = np.where(img >= threshold, 255, 0)
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 NumPyimport cv2import 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 127threshold = 127# Perform inverse binary thresholding on the grayscale imageinverse_thresh = np.where(img >= threshold, 0, 255)
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 NumPyimport cv2import 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 127threshold = 127# Perform truncated thresholding on the grayscale imagetrunc_thresh = np.where(img >= threshold, threshold, img)
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 NumPyimport cv2import 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 127threshold = 127# Perform to-zero thresholding on the grayscale imageto_zero_thresh = np.where(img >= threshold, img, 0)
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 NumPyimport cv2import 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 127threshold = 127# Perform truncated thresholding on the grayscale imageinverse_to_zero_thresh = np.where(img >= threshold, 0, img)
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 NumPyimport cv2import numpy as np# Read the input image in grayscale modeimg = cv2.imread('input_image.png', cv2.IMREAD_GRAYSCALE)# Set the size of the block for adaptive thresholdingblock_size = 11# Set the constant value used to compute the thresholdconstant = 2# Create a new image to store the result of adaptive mean thresholdingadaptive_mean_thresh = np.zeros_like(img, dtype=np.uint8)# Get the height and width of the input imageheight, width = img.shape# Loop through the image in block_size stepsfor 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 coordinatesblock = img[y:y + block_size, x:x + block_size]# Compute the threshold using the mean of the block intensity values minus the constantthreshold = 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 0adaptive_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).
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 NumPyimport cv2import numpy as np# Read the input image in grayscale modeimg = cv2.imread('input_image.png', cv2.IMREAD_GRAYSCALE)# Set the size of the block for adaptive thresholdingblock_size = 11# Set the constant value used to compute the thresholdconstant = 0.9# Create a new image to store the result of adaptive Gaussian thresholdingadaptive_gaussian_thresh = np.zeros_like(img, dtype=np.uint8)# Get the height and width of the input imageheight, width = img.shape# Loop through the image in block_size stepsfor 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 coordinatesblock = 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 deviationthreshold = 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 0adaptive_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 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 NumPyimport cv2import numpy as np# Read the input image in grayscale modeimg = cv2.imread('input_image.png', cv2.IMREAD_GRAYSCALE)# Compute the histogram of the imagehist, _ = np.histogram(img, bins=256, range=(0, 256))# Calculate the total number of pixels in the imagetotal_pixels = img.shape[0] * img.shape[1]# Calculate the sum of (pixel value * frequency) for all pixel valuessum_total = np.sum(np.arange(256) * hist)# Variables to keep track of the sum and frequencies for background and foreground pixels during threshold calculationsum_back = 0w_back = 0w_fore = 0# Variables to keep track of the maximum inter-class variance and the corresponding thresholdmax_variance = 0threshold = 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 backgroundw_back += hist[i]if w_back == 0:continue# Calculate the frequency for the foregroundw_fore = total_pixels - w_backif w_fore == 0:break# Update the sum for the backgroundsum_back += i * hist[i]# Calculate the mean values for background and foregroundmean_back = sum_back / w_backmean_fore = (sum_total - sum_back) / w_fore# Calculate the inter-class variance using the current thresholdvariance = w_back * w_fore * ((mean_back - mean_fore) ** 2)# Update the maximum variance and the corresponding threshold if neededif variance > max_variance:max_variance = variancethreshold = i# Create the binary image using the Otsu thresholdotsu_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.
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