In the previous blogs, we discussed different methods for automatically finding the global threshold for an image. For instance, the iterative method, Otsu’s method, etc. In this blog, we will discuss another very simple approach for automatic thresholding – Balanced histogram thresholding. As clear from the name, this method tries to automatically find the threshold by balancing the image histogram. Let’s understand this method in detail.
Note: This method assumes that the image histogram is bimodal and a reasonable contrast ratio exists between the background and the region of interest.
Concept
Suppose you have a perfectly balanced histogram i.e. a histogram where the distribution of the background and the roi is the same. If you place such a histogram over the lever, it will be balanced. And the optimum threshold will be at the center of the lever as shown in the figure below
This is the main idea behind the Balanced Histogram Thresholding. This method tries to balance the image histogram and then infer the threshold value from that.
But in real-life situations, we don’t encounter images with such perfectly balanced histograms. So, let’s see how this method balances the unbalanced histograms.
- First, it places the histogram over the lever and calculates the center point.
- Then this calculates the left side and right side weights from the center point.
- Removes weight from the heavier side and adjust the center.
- Repeat the above two steps until the starting and the endpoints are equal to the center.
The whole procedure can be summed up in the below gif (taken from Wikipedia)
Below is the python code for this. Here, i_s, i_e are the starting and the endpoints of the histogram and i_m is the center
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
def balanced_hist_thresholding(b): # Starting point of histogram i_s = np.min(np.where(b[0]>0)) # End point of histogram i_e = np.max(np.where(b[0]>0)) # Center of histogram i_m = (i_s + i_e)//2 # Left side weight w_l = np.sum(b[0][0:i_m+1]) # Right side weight w_r = np.sum(b[0][i_m+1:i_e+1]) # Until starting point not equal to endpoint while (i_s != i_e): # If right side is heavier if (w_r > w_l): # Remove the end weight w_r -= b[0][i_e] i_e -= 1 # Adjust the center position and recompute the weights if ((i_s+i_e)//2) < i_m: w_l -= b[0][i_m] w_r += b[0][i_m] i_m -= 1 else: # If left side is heavier, remove the starting weight w_l -= b[0][i_s] i_s += 1 # Adjust the center position and recompute the weights if ((i_s+i_e)//2) >= i_m: w_l += b[0][i_m+1] w_r -= b[0][i_m+1] i_m += 1 return i_m |
The above function takes the image histogram as the input and returns the optimum threshold. Let’s take an example to check how this works.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import cv2 import numpy as np import matplotlib.pyplot as plt %matplotlib inline np.random.seed(7) # Create a sample image img = np.random.normal(40,10,size=(500,500)).astype('uint8') img[img>100]=40 img[100:400,100:400] = np.random.normal(150,20,size=(300,300)).astype('uint8') # Plot the histogram b1 = plt.hist(img.ravel(),256,[0,256]) plt.show() |
Below is the histogram of the image constructed.
Now, let’s apply the Balanced Histogram thresholding method to check what threshold value this outputs.
1 2 |
thresh_value = balanced_hist_thresholding(b1) >>> 87 |
87 looks like a reasonable threshold, check the image histogram above. So, that’s all for this time. Hope you enjoy reading.
If you have any doubt/suggestion please feel free to ask and I will do my best to help or improve myself. Good-bye until next time.