close

Image Thresholding in OpenCV

Carefully observe the animation below in Figure 1. How many numbers do you see? Most of you will see several numbers. But there is more to the image than meets the eye. As the image cycles through the animation, you will see the thresholded version of the original image, where:

BERJAYA

Carefully observe the animation below in Figure 1. How many numbers do you see? Most of you will see several numbers. But there is more to the image than meets the eye.

Input image to be used for image thresholding in OpenCV.

As the image cycles through the animation, you will see the thresholded version of the original image, where:

  • All the numbers look completely white (i.e. they have a grayscale value of 255).
  • You can also see the number ‘5’, which was present but invisible in the original image, simply because its grayscale value was 5.

In fact, all the numbers in the original image have a grayscale value equal to the value of the number. So, ‘255’ is the brightest and ‘5’ the darkest. Recall that grayscale intensities range from pure black (0) to pure white (255). 

So, reading numbers in the thresholded image is much easier than reading numbers in the original image. Not surprisingly, even text-recognition algorithms find it easier to process a thresholded image over the original. Thresholding therefore has numerous applications in computer vision, and is often performed in the initial stages in  many processing pipelines. There are several types of thresholding algorithms. Let’s focus on  ‘global’ thresholding here.

This post is a part of the series Getting Started with OpenCV which consists of the following posts:

  1. Read, Display, and Write an Image using OpenCV
  2. Reading and Writing Videos using OpenCV
  3. Image Resizing using OpenCV
  4. Cropping an Image using OpenCV
  5. Image Rotation and Translation using OpenCV
  6. Annotating Images Using OpenCV
  7. Color spaces in OpenCV
  8. Image Filtering Using Convolution in OpenCV
  9. Image Thresholding in OpenCV
  10. Edge Detection using OpenCV
  11. Mouse and Trackbar using OpenCV GUI
  12. Contour Detection using OpenCV
  13. Deep Learning with OpenCV DNN Module: A Definitive Guide

Contents

  1. Global Thresholding
  2. Binary Thresholding
  3. Inverse-Binary Thresholding
  4. Truncate Thresholding
  5. Threshold to Zero
  6. Inverted Threshold to Zero

Global Thresholding

So, what is ‘global’ thresholding? When the thresholding rule is applied equally to every pixel in the image, and the threshold value is fixed, the operations are called global. 

Global thresholding algorithms take a source image (src) and a threshold value (thresh) as input, and produce an output image (dst), by comparing the pixel intensity at source pixel location (x,y) to the threshold. If src(x,y) > thresh, then dst(x,y) is assigned some value. Otherwise, dst(x,y) is assigned some other value.

The simplest form of global thresholding is called Binary Thresholding

  • In addition to the source image (src) and the threshold value (thresh ), it takes another input parameter called the maximum value (maxValue).
  •  At each pixel location (x,y), the pixel intensity at that location is compared to  a threshold value,  thresh .

If src(x,y) is greater than thresh, the thresholding operation sets the value of the destination image pixel dst(x,y) to the maxValue. Otherwise, it sets it to 0, as shown in the pseudo code below.

# Simple threshold function pseudo code
if src(x,y) > thresh
  dst(x,y) = maxValue
else
  dst(x,y) = 0

Thresholding algorithms vary, based on different threshold rules applied to src(x,y) to get dst(x,y). Here, we will examine five different threshold types available in OpenCV.

Threshold Examples: Python and C++ 

Let’s first look at the code that will demonstrate several thresholding rules. We will discuss each line in detail so that you understand it fully.

Python:

# import opencv 
import cv2 

# Read image 
src = cv2.imread("threshold.png", cv2.IMREAD_GRAYSCALE); 

# Basic threhold example 
th, dst = cv2.threshold(src, 0, 255, cv2.THRESH_BINARY); 
cv2.imwrite("opencv-threshold-example.jpg", dst); 

# Thresholding with maxValue set to 128
th, dst = cv2.threshold(src, 0, 128, cv2.THRESH_BINARY); 
cv2.imwrite("opencv-thresh-binary-maxval.jpg", dst); 

# Thresholding with threshold value set 127 
th, dst = cv2.threshold(src,127,255, cv2.THRESH_BINARY); 
cv2.imwrite("opencv-thresh-binary.jpg", dst); 

# Thresholding using THRESH_BINARY_INV 
th, dst = cv2.threshold(src,127,255, cv2.THRESH_BINARY_INV); 
cv2.imwrite("opencv-thresh-binary-inv.jpg", dst); 

# Thresholding using THRESH_TRUNC 
th, dst = cv2.threshold(src,127,255, cv2.THRESH_TRUNC); 
cv2.imwrite("opencv-thresh-trunc.jpg", dst); 

# Thresholding using THRESH_TOZERO 
th, dst = cv2.threshold(src,127,255, cv2.THRESH_TOZERO); 
cv2.imwrite("opencv-thresh-tozero.jpg", dst); 

# Thresholding using THRESH_TOZERO_INV 
th, dst = cv2.threshold(src,127,255, cv2.THRESH_TOZERO_INV); 
cv2.imwrite("opencv-thresh-to-zero-inv.jpg", dst); 

C++:

#include "opencv2/opencv.hpp"

using namespace cv;
using namespace std;

int main( int argc, char** argv )
{

	// Read image 
	Mat src = imread("threshold.png", IMREAD_GRAYSCALE); 
	Mat dst; 
	
	// Basic threhold example 
	threshold(src,dst,0, 255, THRESH_BINARY); 
	imwrite("opencv-threshold-example.jpg", dst); 

	// Thresholding with maxval set to 128
	threshold(src, dst, 0, 128, THRESH_BINARY); 
	imwrite("opencv-thresh-binary-maxval.jpg", dst); 
	
	// Thresholding with threshold value set 127 
	threshold(src,dst,127,255, THRESH_BINARY); 
	imwrite("opencv-thresh-binary.jpg", dst); 
	
	// Thresholding using THRESH_BINARY_INV 
	threshold(src,dst,127,255, THRESH_BINARY_INV); 
	imwrite("opencv-thresh-binary-inv.jpg", dst); 
	
	// Thresholding using THRESH_TRUNC 
	threshold(src,dst,127,255, THRESH_TRUNC); 
	imwrite("opencv-thresh-trunc.jpg", dst); 

	// Thresholding using THRESH_TOZERO 
	threshold(src,dst,127,255, THRESH_TOZERO); 
	imwrite("opencv-thresh-tozero.jpg", dst); 

	// Thresholding using THRESH_TOZERO_INV 
	threshold(src,dst,127,255, THRESH_TOZERO_INV); 
	imwrite("opencv-thresh-to-zero-inv.jpg", dst); 
} 

We assume you already have OpenCV in your system. If you need to install OpenCV, please visit the relevant link below.
  1. Install OpenCV on Windows
  2. Install OpenCV on MacOS
  3. Install OpenCV on Ubuntu

Input Image

In the following examples, we will use this image as input.  The input image contains numbers written with intensity (grayscale value) equal to the number itself. For example, the pixel intensity of the number ‘200’ is 200, and the intensity of the number ‘32’ is 32. No wonder ‘32’ appears much darker than ‘200’.

BERJAYA
Figure 2 Input Image Click to open a high resolution PNG in a different window

In each example below, we will explain the thresholding rule via pseudo-code, and then provide the actual Python and C++ code, for the example as well as the thresholded output image.

1. Binary Thresholding ( THRESH_BINARY )

This is the most common and simplest type of thresholding.

Thresholding rule

# Binary Threshold
if src(x,y) > thresh
  dst(x,y) = maxValue
else
  dst(x,y) = 0

Python:

# import opencv
import cv2

# Read image
src = cv2.imread("threshold.png", cv2.IMREAD_GRAYSCALE)

# Set threshold and maxValue
thresh = 0
maxValue = 255 

# Basic threshold example
th, dst = cv2.threshold(src, thresh, maxValue, cv2.THRESH_BINARY);

Download Code To easily follow along this tutorial, please download code by clicking on the button below. It's FREE!
BERJAYA

C++:

using namespace cv; 

// Read image
Mat src = imread("threshold.png", IMREAD_GRAYSCALE);
Mat dst;

// Set threshold and maxValue
double thresh = 0;
double maxValue = 255; 

// Binary Threshold
threshold(src,dst, thresh, maxValue, THRESH_BINARY);

Result of Binary Threshold

Figure 3 shows the result of applying binary thresholding to the input image, with thresh = 0 and maxValue = 255.

BERJAYA
Figure 3 Binary Threshold thresh = 0 and maxValue = 255

Changing thresh to 127 removes all numbers less than or equal to 127.

BERJAYA
Figure 4 Binary Threshold thresh = 127 and maxValue = 255

Changing maxValue to 128 sets the value of the thresholded regions to 128.

BERJAYA
Figure 5 Binary Threshold with maxValue set to 128

2. Inverse-Binary Thresholding ( THRESH_BINARY_INV )

Inverse-Binary Thresholding is just the opposite of Binary Thresholding. The destination pixel is set to:

  •  zero, if the corresponding source pixel is greater than the threshold
  •  maxValue, if the source pixel is less than the threshold

Thresholding rule

# Inverse Binary Threshold
if src(x,y) > thresh
  dst(x,y) = 0
else
  dst(x,y) = maxValue

Python:

th, dst = cv2.threshold(src, thresh, maxValue, cv2.THRESH_BINARY_INV)

C++:

threshold(src,dst, thresh, maxValue, THRESH_BINARY_INV);

Result of Inverse-Binary Threshold

Note how the result of Inverse-Binary Thresholding, shown in Figure 6, is exactly the inverse of Figure 4.

BERJAYA
Figure 6 Inverse Binary Thresholding thresh = 127 maxValue = 0

3. Truncate Thresholding ( THRESH_TRUNC )

In this type of thresholding:

  • The destination pixel is set to the threshold (thresh), if the source pixel value is greater than the threshold.
  • Otherwise, it is set to the source pixel value
  • The maxValue is ignored

Thresholding rule

# Truncate Threshold
if src(x,y) > thresh
  dst(x,y) = thresh
else
  dst(x,y) = src(x,y)

Python:

th, dst = cv2.threshold(src, thresh, maxValue, cv2.THRESH_TRUNC)

C++:

threshold(src,dst, thresh, maxValue, THRESH_TRUNC);

Result of Truncate Thresholding

Figure 7 shows the result of applying Truncate Thresholding to the input image. Note that:

  • All values above the threshold (127) are set to 127
  • All values less than or equal to 127 are unchanged
  • The  maxValue is ignored.
BERJAYA
Figure 7 Truncate Thresholding thresh = 127

4. Threshold to Zero ( THRESH_TOZERO )

In this type of thresholding,

  • The destination pixel value is set to the pixel value of the corresponding source , if the source pixel value is greater than the threshold.
  • Otherwise, it is set to zero
  • The maxValue is ignored

Thresholding rule

# Threshold to Zero
if src(x,y) > thresh
  dst(x,y) = src(x,y)
else
  dst(x,y) = 0

Python:

th, dst = cv2.threshold(src, thresh, maxValue, cv2.THRESH_TOZERO)

C++:

threshold(src,dst, thresh, maxValue, THRESH_TOZERO);

Result of Threshold to Zero

BERJAYA
Figure 8 Threshold to Zero thresh = 127

5. Inverted Threshold to Zero ( THRESH_TOZERO_INV )

In Inverted Threshold to Zero,

  • The destination pixel value is set to zero, if the source pixel value is greater than the threshold.
  • Otherwise, it is set to the source pixel value
  • The  maxValue is ignored

Thresholding rule

# Inverted Threshold to Zero
if src(x,y) > thresh
  dst(x,y) = 0
else
  dst(x,y) = src(x,y)

Python:

th, dst = cv2.threshold(src, thresh, maxValue, cv2.THRESH_TOZERO_INV)

C++:

threshold(src,dst, thresh, maxValue, THRESH_TOZERO_INV);

Result of Inverted Threshold to Zero

Figure 9 shows the result of applying Inverted Threshold to Zero to the input image.

  • The numbers below the threshold retain their grayscale value
  • The numbers above the threshold are 0, except for the boundary

Check out the artifacts on the boundary of some of the numbers! When the pixel values at the boundary transition from 0 to the value of the number, over very few pixels, some of the boundary pixels fall below the threshold. So, you get these artifacts.

BERJAYA
Figure 9 Inverted Threshold to Zero thresh = 127

Summary

We discussed how thresholding can be used to isolate certain objects in an image. Several global-thresholding algorithms were demonstrated, and we provided code examples for each. You learned how even a single function in OpenCV can perform different types of thresholding, by simply passing the appropriate thresholding flag. 



32 Responses

  1. Your article helped me a lot, is there any more related content? Thanks!

  2. Thanks for sharing. I read many of your blog posts, cool, your blog is very good.

  3. BERJAYA binance says:

    Thank you for your sharing. I am worried that I lack creative ideas. It is your article that makes me full of hope. Thank you. But, I have a question, can you help me?

  4. BERJAYA binance says:

    Your point of view caught my eye and was very interesting. Thanks. I have a question for you.

  5. BERJAYA binance says:

    Thanks for sharing. I read many of your blog posts, cool, your blog is very good.

  6. I don’t think the title of your article matches the content lol. Just kidding, mainly because I had some doubts after reading the article.

  7. BERJAYA binance says:

    I don’t think the title of your article matches the content lol. Just kidding, mainly because I had some doubts after reading the article. https://accounts.binance.com/ar-BH/register?ref=GJY4VW8W

  8. BERJAYA бнанс says:

    Your point of view caught my eye and was very interesting. Thanks. I have a question for you. https://accounts.binance.com/uk-UA/register-person?ref=V3MG69RO

  9. BERJAYA Truck Driver says:

    Great job my friend!

  10. BERJAYA Bradley Racey says:

    What a great guide. Awesome job, I learned a lot.

  11. Thanks for greate tutorial, I learnt a lot from it

    1. Thanks for the kind words!

  12. BERJAYA vaishnavi says:

    I need something that will calculate the threshold based on image or we can say on runtime

    1. You may want to look at histogram of the image for deciding a threshold.

  13. BERJAYA piyush says:

    thanks sir

  14. BERJAYA Imran Qureshi says:

    very nice tutorial. Great sir thanks

  15. BERJAYA Subhendu Sinha Chaudhuri says:

    how to download the codes?

    1. You will receive an email with all the goodies once you subscribe.

  16. BERJAYA Facundo Galán says:

    I think adaptive thresholding is a really important one, that you might want to add here.
    Thanks for the tutorial 🙂

    1. Thanks, Facundo. Will do. Sorry I had missed your comment.

  17. BERJAYA Faiq FK says:

    Satya Mallick my program always give output : ucrtbased.dll and opencv_world310.dll cannot find or open pdb files, how to fix it?

    1. Hi Faiq,

      Unfortunately, I am do not work on Windows and do not know how to fix this problem. I hope you were able to solve the problem.

  18. BERJAYA tuvi says:

    Thank you so much…it helped so much to understand threshold value of OpenCV.

  19. BERJAYA Sudipta Basak says:

    Just read this Satya. Thanks for sharing 🙂

  20. BERJAYA Saurabh Khanduja says:

    Just started reading your articles, they are really good. I am just wondering why miss out on OTSU? Adaptive thresholding would be much better for making something
    like text reader.

    1. Thanks Saurabh. Good point. I should include OTSU in the post as well.

Leave a Reply

Your email address will not be published. Required fields are marked *

Prove your humanity: 8   +   5   =  

Read Next

How to Master YOLOE: Real-Time Open-Vocabulary Detection Made Easy

How to Master YOLOE: Real-Time Open-Vocabulary Detection Made Easy

Learn YOLOE for real-time open-vocabulary object detection and instance segmentation in Python with Ultralytics — text, visual, and prompt-free modes.

YOLO26 Keypoint Estimation: Real-Time Pose Estimation with Ultralytics

YOLO26 Keypoint Estimation: Real-Time Pose Estimation with Ultralytics

Learn how to use YOLO26-pose with Python for real-time keypoint estimation on images and videos, understand its RLE-based architecture, and…

YOLO26 Instance Segmentation: Pixel-Perfect AI at Real-Time Speed

YOLO26 Instance Segmentation: Pixel-Perfect AI at Real-Time Speed

Build a complete pipeline for YOLO26 instance segmentation, from image and video inference to custom dataset training and edge deployment.

Subscribe to our Newsletter

Subscribe to our email newsletter to get the latest posts delivered right to your email.

BERJAYA Click here to download the source code to this post

Subscribe to receive the download link, receive updates, and be notified of bug fixes

Which email should I send you the download link?

 

Get Started with OpenCV

Subscribe To Receive
BERJAYA

We hate SPAM and promise to keep your email address safe.​