Image Thresholding From Scratch

Rohit Krishna
Geek Culture
Published in
5 min readApr 7, 2023
Taj Mahal | Image by Author

Thresholding is a process in which an input image is converted into a binary image, where pixels with intensity values above a certain threshold are set to a maximum value (usually 255) and pixels below the threshold are set to a minimum value (usually 0). The threshold value can be determined based on some criteria.

So the Thresholding process just boils down to finding a specific threshold for whatever task you wanna do with it.

There are many ways to find the threshold

  1. Global Thresholding: A fixed threshold value is applied to the entire image.
  2. Adaptive Thresholding: The threshold value is calculated locally around each pixel based on the intensity values in its neighborhood.
  3. Color Thresholding: Instead of using grayscale intensity values, color thresholding uses color information to separate objects of interest from the background.
  4. etc…

Though there are many methods, I’m gonna be explaining some techniques that I recently learned and it seems to be very useful in many cases, those are, Global Thresholding, Adaptive Thresholding, and Otsu’s Thresholding.

1. Global Thresholding

It is simple and streight forward approch, given a threshold if any pixel are more than that put 255 else 0.

img = cv2.imread("<path-to-img>", cv2.IMREAD_GRAYSCALE)
thresh = 130
_, result = cv2.threshold(img, thresh, 255, cv2.THRESH_BINARY)
# or do manually by following
img[img > thresh] = 255
img[img <= thresh] = 0

2. Otsu’s Thresholding

Example for Otsu’s Thresholding | Image by Author

Unlike Global Thresholding, this technique automatically calculates an optimal threshold value that minimizes the intra-class(within-class) variance of the two classes of pixels (foreground and background), or maximizes the inter-class(between-class) variance of it.

OOh, you feeling a huge headache by reading that definition, don’t be, it is fairly simple :)

The algorithm is that, in all available thresholds that we can go through all and find a criteria for each threshold and finally find the threshold which corresponds to the minimum criteria, and that’s it, we can use that threshold value to binarize the image.

Now we gotta understand the process of calculating the criteria, which is, given a threshold we first split the image into two arrays. One of the array contains pixel values that are greater than the given threshold, and another one with pixel values that are less than or equal to the given threshold.

And we consider those two arrays as two distributions and find the variance of both, and return the summation of both variances multiplied by their weight (the number of pixels they have divided by the total number of pixels the image has).

So generally speaking we are finding a threshold that splits the image pixels into two distributions whose inter-class variance(between-class variance) is maximizes or intra-class variance(within-class variance) is minimizes.

Below is shown two examples of the processed thresholds using Otsu method and the histogram of each of the images.

Now before getting into other adaptive thresholding techniques, I want to discuss the limitation of Otsu’s Thresholding, and why we need Adaptive Thresholding.

  1. Assumption of bi-modal histogram: Otsu’s method assumes that the histogram of image intensities is bi-modal, meaning that there are two distinct classes of pixels (foreground and background) with distinct intensity values. If the histogram is not bi-modal, Otsu’s method may not work well.
  2. Sensitivity to image noise: Otsu’s method is sensitive to noise in the image, which can affect the accuracy of the calculated threshold value. To mitigate this issue, image smoothing techniques can be applied before applying the thresholding.
  3. Computational cost: Otsu’s method involves calculating the histogram of image intensities and computing the between-class variance for all possible threshold values. This can be computationally expensive for large images, especially if the method is used in real-time applications.
  4. Limited applicability to complex scenes: Otsu’s method works best when the foreground and background have distinct intensity values. However, in complex scenes where the foreground and background have similar intensity values, Otsu’s method may not be effective.
  5. Not suitable for adaptive thresholding: Otsu’s method calculates a single global threshold value for the entire image. It is not suitable for adaptive thresholding, where the threshold value is calculated locally for each pixel based on its neighboring pixels.
Example of the Limitation of Otsu Thresholding | Image by Author

3. Adaptive Thresholding

The process is that, instead of calculating a global threshold value for the whole image, calculate it for each chunk of the image.

In Mean Adaptive Thresholding, we take the mean of the chunk of the gray scaled image as the threshold.

In Gaussian Adaptive Thresholding, we perform Gaussian Blur on the image and wherever there are pixel intensities which are more than the pixel intensities of the blurred image set those regions to 255 else 0.

If you don’t know what is a Gaussian Blur then checkout my article, where i got into more details of it, along with the custom implementation.

The Complete Code is available in my Github Repo…

Conclusion

Now i hope you have a clear and detailed picture of image thersholding. Below is the code for the algorithms we taught in this article implemented using OpenCV.

import cv2
img = cv2.imread('<path-to-img>', cv2.IMREAD_GRAYSCALE)
otsu_thresh = cv2.threshold(img, -1, 255, cv2.THRESH_OTSU)
ada_thresh_mean = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 7, 4)
ada_thresh_gaussian = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 7, 4)

If this article helps you in any way, i really appreciate if you could support me through BuyMeACoffee, it really motivates me to produce amazing articles for you guys 🥰.

References

--

--