Thursday, October 24, 2019

Image Thresholding

1. Simple Thresholding

This is a technique for images processing, Using OpenCV we can get the desired results,

Let us understand the theory and practice about thresholding techniques.

in OpenCV we have to use cv2.threshold( ) function.

the usage is : cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)

where, first argument : img is a source image, which should be a grayscale image.
2nd argument : 127 is the threshold value which is used to classify the pixel values. this is a global value also.
3rd argument : 255 is the maxVal which represents the value to be given if pixel value is more than (sometimes less than) the threshold value.
4th argument : different styles of thresholding.

as in 2nd argument, threshold value, i.e, 127, ( it is a global value) If pixel value is greater than a threshold value, it assigned one value ( may be white), else it is assigned another value (may be black).

4th argument : thresholding techniques - Different types :
1). cv2.THRESH_BINARY
2). cv2.THRESH_BINARY_INV
3). cv2.THRESH_TRUNC
4). cv2.THRESH_TOZERO
5). cv2.THRESH_TOZERO_INV

we will see an example on these thresholding techniques. see the code below,



in this code , we have used an input image , 'gradient.png', it is given below(pls download) and save in your working directory.



see the code , in line number 9:
 1st argument, 'img', - it is a input image which we have read from my current directory using cv2.imread() function as grayscale image. 2nd argument: 127 is the global threshold value, it means the pixel values above this value will get the value of 3rd argument, i.e, 255 (here) that means the pixel values will get white pixels.
4th argument : cv2.THRESH_BINARY, it converts the pixel values in black and white as per the 2nd and 3rd arguments specifies. it's output is shown in "BINARY" name.
it returns two values , ret & thresh1, here we need thresh value which is the required image. in the next section we will see what is ret value?

in line number 10: cv2.THRESH_BINARY_INV , it is the opposite to the code in line number 9.

in the line number 11: cv2.THRESH_TRUNC, it truncates and separates black and white pixels.

in the line number 12: cv2.THRESH_TOZERO, it sets the pixel vales either black or white.

in the line number 13: cv2.THRESH_TOZERO_INV, it is opposite to the code in line number 12.
.
now run the code, then you will see the output (below shown) like this :


(2). Adaptive Thresholding:

in Simple thresholding, we have used a global value as threshold value, i.e, 127. But it may not be sufficient in all the conditions where image has different lighting conditions in different areas. In that case, we go for Adaptive Thresholding. 

Adaptive Method - it decides how thresholding value is calculated

In this method, the algorithm calculate the threshold for a small regions of the image. So we get the different thresholds for different regions of the same image and it gives us better results for images with varying illumination.

It has three 'special' input parameters and only one output argument..

Here is the two algorithms in adaptive method:

(a). cv2.ADAPTIVE_THRESH_MEAN_C : this algorithm finds a threshold value from the mean value of neighbourhood area.

(b). cv2.ADAPTIVE_THRESH_GAUSSIAN_C : this algorithm finds a threshold value from the weighted sum of neighbourhood values where weights are a gaussian window.

we will see the differences of these two algorithms using an example.

frequently used terms  are :

Block Size - It decides the size of neighbourhood area.
C - It is just a constant which is subtracted from the mean or weighted mean calculated.

let's see the code : 


the input image - dave.jpg, (pls download from here):




in this code, we have read an input image "dave.jpg" in grayscale mode.
in line number 6 : This image is blurred with cv2.medianBlur( ) function it takes median of all the pixels under kernel area and central element is replaced with this median value. This is highly effective against salt-and-pepper noise in the images. central element is always replaced by some pixel value in the image. It reduces the noise effectively. Its kernel size should be a positive odd integer only.

in line number 8 : cv2.threshold(....., cv2.THRESH_BINARY) , using this line, our median blurred image is (from line 6) thresholded binary (see in the output "Global Thresholding(v=127))

in line number 9: cv2.adaptiveThreshold( ) function uses cv2.ADAPTIVE_THRESH_MEAN_C algorithm,
see the code :
cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
where (i). img is the median blurred image,
(ii). 255 is the maxValue, it is a non-zero value assigned to the pixels for which the condition satisfied only.
(iii). threshold type : cv2.THRESH_BINARY or cv2.THRESH_BINARY_INV
(iv). blockSize – 11: it is a size of a pixel neighborhood that is used to calculate a threshold value for the pixel: 3, 5, 7, and so on.
(v). C –2 : Constant subtracted from the mean or weighted mean. Normally, it is positive but may be zero or negative as well.

in line number 10: cv2.adaptiveThreshold( ) function uses cv2.ADAPTIVE_GAUSSIAN_C algorithm,

see the code :
cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_GAUSSIAN_MEAN_C, cv2.THRESH_BINARY, 11, 2)


lets' run the code, here is the output :



(3). Otsu's Binarization :

In global thresholding, we used an arbitrary value for threshold value, it is purely a trail and error method.

But consider a bimodal image ( it is an image whose histogram has two peaks), for this image, we can approxmately take a value in the middle of those peaks as threshold value, that thing is what Otsu binarization does. it automatically calculates a threshold value from image histogram for a bimodal image. For the other modals ( except bimodal), binarization won't be accurate.

For this cv2.threshold( ) function is used, but we have to pass an extra flag, cv2.THRESH_OTSU. For threshold value simply pass zero. Then the algorithm finds the optimal threshold value and returns as the second output, i.e, retVal. If Otsu thresholding is not used, retVal is same as the threshold value you used.

in the following code, Input image is a noisy image. In first case,global thresholding value used 127, In second case Otsu's thresholding applied directly. In third case the image is filtered with a 5x5 gaussian kernal to remove the noise, then applied Otsu thresholding. See how noise filtering improves the result.

see the code :



the input image "noisy2.png" download from here.


now run the code : here is the output-






Python's - The Complete argparse module Tutorial Part - 2