Adaptive Threshold
Learn when and how to use the adaptive threshold operation.
We'll cover the following...
When discussing the thresholding operation, we assumed that the gray levels of the background and the objects to inspect were reasonably uniform across the image. In real-life scenarios, this is rarely the case. In particular, the lighting conditions can vary significantly from one side of the image to the other, especially when the camera’s field of view is more than a few tens of centimeters.
The intensity gradient problem
Let’s consider the following checkerboard image, affected by a strong intensity gradient due to non-uniform lighting:
Imagine we want to compute an active mask (i.e., white) in the areas of the black squares and inactive (i.e., black) in the areas of the white squares. The surface outside the checkerboard doesn’t matter.
Thresholding the checkerboard
How can we threshold the above image to highlight the black squares?
retval, mask = cv2.threshold(
src=image,
thresh=128,
maxval=255,
type=cv2.THRESH_BINARY_INV
)
retval, mask = cv2.threshold(
src=image,
thresh=None,
maxval=255,
type=cv2.THRESH_OTSU
)
mask = 255 - mask
With a uniform threshold, there is no way to highlight all the black squares without highlighting some white squares.
Let’s see what we can do with a uniform threshold:
import cv2threshold = 128image = cv2.imread('./images/checkerboards/lighting_checkerboard.png',flags=cv2.IMREAD_GRAYSCALE) # Read directly as a grayscale image# Apply a uniform thresholdretval, mask = cv2.threshold(src=image, # The source imagethresh=threshold, # The thresholdmaxval=255, # The 'active' valuetype=cv2.THRESH_BINARY_INV # Highlight gray levels below the threshold)# Write to './output'cv2.imwrite('./output/0_original.png', image)cv2.imwrite('./output/1_mask.png', mask)
In lines 9–14, we call the cv2.threshold()
function on the grayscale image.
We can change the threshold value in line 3 to convince ourselves that no single threshold value would be adequate to highlight only the black squares without highlighting at least some parts of the white squares. Making use of the Otsu algorithm won’t help since it computes a single threshold that is applied uniformly to the image.
Notice that in lines 5 and 6, the image is read with the flags=cv2.IMREAD_GRAYSCALE
argument. This shortcut allows us to read a grayscale image, whether the file is a color or a grayscale image. We can spare a call to cv2.cvtColor()
because we won’t need the color information for the task.
Adaptive thresholding
Binarizing an image in the presence of a ...