Adaptive Thresholding using OpenCV

Before we start with adaptive thresholding, let us look at the problem that we face when using Otsu’s global thresholding algorithm.

Problems with Otsu’s Global Thresholding Algorithm

Otsu is highly useful when the image has a bimodal histogram. In other words, if the objects are separable using one threshold. However, if this is not the case, then the Otsu method will fail. When we tried to threshold the following image using the Otsu's Global thresholding algorithm (Click Here for Otsu's Global Thresholding Algorithm), we obtained the following output.

No image
Figure 1: Original image (left), thresholded image using Otsu method (right).

The results are quite terrible in my opinion as we lost lot of information (text at bottom). We need to understand that the Otsu will fail in such scenarios where the histogram of the image is not bimodal. In simple words, we can say that the Otsu is not suitable when the image or object has varying intensity values in different regions due to different lighting conditions such as the one shown above. You can see that the brightless towards left top corner is high and it is getting low and lower towards the bottom right corner. In such as case, an alternative solution is used called adaptive thresholding.

Adaptive Thresholding

Adaptive thresholding algorithm is suitable for a situation where the lighting conditions are changing for different regions in the image. In contrast to the global thresholding algorithms, which use only one threshold value to segment the whole image, the adaptive thresholding algorithm calculates multiple threshold values for each small region and then applies thresholding to segment the image. For varying illumination conditions, it gives us better results.

OpenCV provides adaptiveThreshold() function to perform adaptive thresholding. The signature of the adaptiveThreshold() function is as shown below:

cv.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C[, dst])

Parameter Description

src

Source 8-bit single-channel image.

maxValue

Non-zero value assigned to the pixels for which the condition is satisfied.

adaptiveMethod

Adaptive thresholding algorithm to use as described below.

thresholdType

Two possible values are THRESH_BINARY or THRESH_BINARY_INV.

blockSize

Size of a pixel neighborhood that is used to calculate a threshold value for the pixel. It should be an odd number.

C

Constant subtracted from the mean or weighted mean of the neighbourhood pixels. Normally, it is positive but may be zero or negative as well.

The adaptiveMethod decides how the threshold value is calculated:

  • cv2.ADAPTIVE_THRESH_MEAN_C: The threshold value is the mean of the neighbourhood area minus the constant C.
  • cv2.ADAPTIVE_THRESH_GAUSSIAN_C: The threshold value is a gaussian-weighted sum of the neighbourhood values minus the constant C.

Code -1 shows an example of how to use adaptive thresholding in OpenCV.

Code -1: Example of adaptive thresholding.
 1
 2
 3
 4
 5
 6
 7


 8


 9
10
11
12
13
14
import cv2
import numpy as np
try:
    path = r'F:\img\gradient.jpg'
    img = cv2.imread(path, cv2.IMREAD_GRAYSCALE) 
    img =  cv2.GaussianBlur(img,(3,3),0)
    imgThreshold1 = cv2.adaptiveThreshold(img,255, .                     
                    cv2.ADAPTIVE_THRESH_MEAN_C,
                    cv2.THRESH_BINARY_INV,11,3)
    imgThreshold2 = cv2.adaptiveThreshold(img,255,
                    cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                    cv2.THRESH_BINARY_INV,11,3)
    cv2.imshow('Original Image',(img))
    cv2.imshow('ADAPTIVE_THRESH_MEAN_C',imgThreshold1)
    cv2.imshow('ADAPTIVE_THRESH_GAUSSIAN_C',imgThreshold2)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
except Exception as e:
    print(str(e))

Line 1 and 2: We start by importing OpenCV and numpy libraries.
Line 3: This line defines a try block. The exception block (Line 11 and 12) is associated with this block. If any exception occurs, it throws it, and the code in the exception block is executed.
Line 4: Define the path of the image to read.
Line 5: Here we read a grayscale image (see the second parameter).
Line 6: This line blurs the image using Gaussian blur.
Line 7: This line performs the thresholding operation using cv2.adaptiveThreshold() function in OpenCV. Here we used cv2.ADAPTIVE_THRESH_MEAN_C.
Line 8: This line performs the thresholding operation using cv2.adaptiveThreshold() function in OpenCV. Here we used cv2.ADAPTIVE_THRESH_GAUSSIAN_C.
Line 9-13: These lines help display the input and output image.

The output obtained when code-1 is executed is shown below in Figure 2. We can see from the figure that the problem of varying illumination is solved using the adaptive thresholding method. It is worth mentioning here that the choice of parameter is task specific. For example, for another image, a different value for block size might produce better results. Users must work a bit to identify the best combination of these parameter values.

No image
Figure 2: Original image (left), results obtained for ADAPTIVE_THRESH_MEAN_C (middle) and results for ADAPTIVE_THRESH_GAUSSIAN_C (right).

OpenCV Tutorials