Image thresholding is one of the most essential and widely used techniques in image processing and computer vision. It transforms a grayscale image into a binary image by setting pixel values to either a maximum or minimum based on a defined threshold. This simple yet powerful method is commonly used in applications such as object detection, document scanning, image segmentation, and more. In this tutorial, we will explore various thresholding techniques provided by OpenCV and demonstrate how to implement them in both Python and C++.
Table of Contents
- Import cv2
- Example image
- Functions and Syntaxes
- Implementation
- Other Thresholding Methods
- Summary
Import cv2
Before using any OpenCV functions, we must first import the library. This is the essential first step to access all OpenCV functionalities.
Python
# import the cv2 library
import cv2
C++
//Include Libraries
//OpenCV's cv::Mat acts like NumPy arrays for image processing.
#include<opencv2/opencv.hpp>
#include<iostream>
We are assuming that you have already installed OpenCV on your device.
If not please refer the relevant links below:
Example Image
We have used the image below, which contains various numbers rendered with pixel intensities equal to their actual values. In this grayscale image, the higher the pixel value, the brighter the corresponding number appears.
Functions and Syntaxes
Image thresholding is the process of converting a grayscale image into a binary image using cv2.threshold(). This is achieved by selecting a threshold value and assigning pixel values accordingly. This technique is particularly useful for separating objects from the background.
Python
retval, dst = cv2.threshold(src, thresh, maxval, type)
C++
double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type);
The function accepts the below arguments:
- src: Input grayscale image (must be single-channel).
- dst: Output image after thresholding (same size and type as input).
- thresh: Threshold value to compare each pixel against.
- maxval: Value assigned to pixels that meet the threshold condition (varies by type).
- type: Thresholding type.
OpenCV provides five basic types of image thresholding that can be applied to grayscale images using the cv2.threshold() function. These techniques differ in how they modify pixel values based on a given threshold.
Binary Thresholding (cv2.THRESH_BINARY)
Sets pixels to the maximum value if they are above the threshold; otherwise, sets them to zero.
Python
_, thresh_img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
C++
threshold(img, thresh_img, 127, 255, THRESH_BINARY);
This thresholding operation can be expressed as:
So, if the intensity of the pixel src(x,y) is higher than thresh, then the new pixel intensity is set to a MaxVal. Otherwise, the pixels are set to 0.
Inverse Binary Thresholding (cv2.THRESH_BINARY_INV)
Opposite of binary thresholding: sets pixels to zero if they are above the threshold; otherwise, sets them to the maximum value.
Python
_, thresh_img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
C++
threshold(img, thresh_img, 127, 255, THRESH_BINARY_INV);
This thresholding operation can be expressed as:
If the intensity of the pixel src(x,y) is higher than thresh, then the new pixel intensity is set to a 0. Otherwise, it is set to MaxVal.
Truncate Thresholding (cv2.THRESH_TRUNC)
Sets pixels to the threshold value if they are above it; otherwise, leaves them unchanged.
Python
_, thresh_img = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
C++
threshold(img, thresh_img, 127, 255, THRESH_TRUNC);
This thresholding operation can be expressed as:
The maximum intensity value for the pixels is thresh, if src(x,y) is greater, then its value is truncated.
To Zero Thresholding (cv2.THRESH_TOZERO)
Leaves pixels unchanged if they are above the threshold; otherwise, sets them to zero.
Python
_, thresh_img = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
C++
threshold(img, thresh_img, 127, 255, THRESH_TOZERO);
This operation can be expressed as:
If src(x,y) is lower than thresh, the new pixel value will be set to 0.
Inverse To Zero Thresholding (cv2.THRESH_TOZERO_INV)
Opposite of To Zero thresholding: sets pixels to zero if they are above the threshold; otherwise, leaves them unchanged.
Python
_, thresh_img = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)
C++
threshold(img, thresh_img, 127, 255, THRESH_TOZERO_INV);
This operation can be expressed as:
If src(x,y) is greater than thresh, the new pixel value will be set to 0.
Implementation
Let’s apply these thresholding techniques to an example image:
Python
import cv2
import matplotlib.pyplot as plt
# Read the image
img = cv2.imread('intensity_digits.png', cv2.IMREAD_GRAYSCALE)
# Apply different thresholding techniques
_, binary = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
_, binary_inv = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
_, trunc = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
_, tozero = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
_, tozero_inv = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)
# Display the results
cv2.imshow("binary",binary)
cv2.imshow("binary_inv",binary_inv)
cv2.imshow("trunc",trunc)
cv2.imshow("tozero",tozero)
cv2.imshow("tozero_inv",tozero_inv)
cv2.waitKey(0)
cv2.destroyAllWindows()
C++
#include <opencv2/opencv.hpp>
using namespace cv;
int main() {
// Read the image in grayscale
Mat img = imread("intensity_digits.png", IMREAD_GRAYSCALE);
Mat binary, binary_inv, trunc, tozero, tozero_inv;
// Apply different thresholding techniques
threshold(img, binary, 127, 255, THRESH_BINARY);
threshold(img, binary_inv, 127, 255, THRESH_BINARY_INV);
threshold(img, trunc, 127, 255, THRESH_TRUNC);
threshold(img, tozero, 127, 255, THRESH_TOZERO);
threshold(img, tozero_inv, 127, 255, THRESH_TOZERO_INV);
// Display the results
imshow("binary", binary);
imshow("binary_inv", binary_inv);
imshow("trunc", trunc);
imshow("tozero", tozero);
imshow("tozero_inv", tozero_inv);
waitKey(0);
destroyAllWindows();
return 0;
}
This code reads a grayscale image and applies five different image thresholding techniques (BINARY, BINARY_INV, TRUNC, TOZERO, TOZERO_INV) using OpenCV’s cv2.threshold() function. Each resulting image is displayed in a separate window to visually compare the effects of the different methods.
Output
Fig2. Binary Thresholding Fig3. Inverse Binary Thresholding
Fig4. Truncate Thresholding Fig5. To Zero Thresholding
Other Thresholding Methods
While basic image thresholding works well for images with uniform lighting, it often fails when lighting varies across the image. To handle such cases, OpenCV offers more advanced techniques like Adaptive Thresholding and Otsu’s Thresholding. These methods automatically determine the threshold value either locally (adaptive) or globally (Otsu’s), resulting in more robust segmentation in challenging lighting conditions.
Adaptive Thresholding
In situations where lighting conditions vary across the image, adaptive thresholding is more effective. Instead of using a global threshold value, it calculates the threshold for smaller regions of the image.
Python
# Apply Adaptive Mean Thresholding
thresh_img = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
# Apply Adaptive Gaussian Thresholding
thresh_img = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
C++
# Apply Adaptive Mean Thresholding
adaptiveThreshold(img, thresh_img, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 11, 2);
# Apply Adaptive Gaussian Thresholding
adaptiveThreshold(img, thresh_img, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 11, 2);
- cv2.ADAPTIVE_THRESH_MEAN_C calculates the mean of the neighborhood area.
- cv2.ADAPTIVE_THRESH_GAUSSIAN_C calculates a weighted sum of the neighborhood values where weights are a Gaussian window.
- 11 is the size of the neighborhood area (block size).
- 2 is a constant subtracted from the mean or weighted mean.
Otsu’s Binarization
Otsu’s method automatically determines the optimal threshold value by minimizing intra-class intensity variance. It is useful when the image histogram has two distinct peaks.
Python
# Apply Otsu's thresholding
_, thresh_img = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
C++
# Apply Otsu's thresholding
threshold(img, thresh_img, 0, 255, THRESH_BINARY | THRESH_OTSU);
- img: Input grayscale image.
- 0: Initial threshold value (ignored when using Otsu’s method).
- 255: Maximum pixel value to use.
- cv2.THRESH_BINARY + cv2.THRESH_OTSU: Combines binary thresholding with Otsu’s algorithm, which automatically computes the optimal threshold based on image histogram.
The initial threshold value (0 here) is ignored and OpenCV calculates the best threshold internally and returns it as the first output (_ in this case).
Example Implementation
Python
import cv2
# Load image in grayscale
img = cv2.imread("intensity_digits.png", cv2.IMREAD_GRAYSCALE)
# Adaptive Mean Thresholding
thresh_mean = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
# Adaptive Gaussian Thresholding
thresh_gauss = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
# Otsu's Thresholding
_, thresh_otsu = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# Save the output images
cv2.imwrite("adaptive_mean.png", thresh_mean)
cv2.imwrite("adaptive_gaussian.png", thresh_gauss)
cv2.imwrite("otsu_threshold.png", thresh_otsu)
# Display results
cv2.imshow("Adaptive Mean", thresh_mean)
cv2.imshow("Adaptive Gaussian", thresh_gauss)
cv2.imshow("Otsu Threshold", thresh_otsu)
cv2.waitKey(0)
cv2.destroyAllWindows()
C++
#include <opencv2/opencv.hpp>
using namespace cv;
int main() {
// Load image in grayscale
Mat img = imread("intensity_digits.png", IMREAD_GRAYSCALE);
// Check if image loaded
if (img.empty()) {
std::cerr << "Failed to load image." << std::endl;
return -1;
}
Mat thresh_mean, thresh_gauss, thresh_otsu;
// Adaptive Mean Thresholding
adaptiveThreshold(img, thresh_mean, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 11, 2);
// Adaptive Gaussian Thresholding
adaptiveThreshold(img, thresh_gauss, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 11, 2);
// Otsu's Thresholding
threshold(img, thresh_otsu, 0, 255, THRESH_BINARY | THRESH_OTSU);
// Save the results
imwrite("adaptive_mean.png", thresh_mean);
imwrite("adaptive_gaussian.png", thresh_gauss);
imwrite("otsu_threshold.png", thresh_otsu);
// Show results
imshow("Adaptive Mean", thresh_mean);
imshow("Adaptive Gaussian", thresh_gauss);
imshow("Otsu Threshold", thresh_otsu);
waitKey(0);
destroyAllWindows();
return 0;
}
- adaptiveThreshold(…) splits the image into small regions (blocks) and applies a threshold for each.
- ADAPTIVE_THRESH_MEAN_C: Uses the mean of the neighborhood.
- ADAPTIVE_THRESH_GAUSSIAN_C: Uses a weighted sum (Gaussian window).
- blockSize = 11: Size of the local neighborhood (must be odd).
- C = 2: A constant subtracted from the mean or weighted mean to fine-tune the result.
- The threshold value is 0 and OpenCV computes the optimal value automatically for Otsu’s technique.
Output
Fig7. Adaptive mean Fig8. Adaptive Gaussian
Summary
In this blog, we explored different image thresholding techniques using OpenCV. We began with basic thresholding methods and moved on to more advanced techniques like Adaptive Thresholding, which is effective under varying lighting conditions, and Otsu’s Thresholding, which automatically determines the optimal threshold value based on image histograms. With just a few lines of code, OpenCV makes it easy to implement powerful image preprocessing techniques.
The post Image Thresholding using OpenCV appeared first on OpenCV.