Goal:
Learning the concept of histogram equailze and how to use it to improve the contrast of pictures
Theory:
If most of the pixel values in an images are concentrated in one pixel range.For example, if a picture is bright as a whole, all pixels should be very high, but the pixel value distribution of a high quality image should be very wide.So we should horizontally stretch the histogram.
In general,this operation will improve the contrast of the image.
First we use Numpy for histogram equlaization, and then learn how to use OpenCV for it.
Numpy
# -*- coding: utf-8 -*-
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('wiki.jpg',0)
# flatten() Change to one-dimensional array
hist,bins = np.histogram(img.flatten(),256,[0,256])
# Calculate cumulative distribution
cdf = hist.cumsum() # accumulation
cdf_normalized = cdf * hist.max()/ cdf.max() # normalized
plt.plot(cdf_normalized, color = 'b')
plt.hist(img.flatten(),256,[0,256], color = 'r')
plt.xlim([0,256])
plt.legend(('cdf','histogram'), loc = 'upper left')
plt.show()
We can see that most of the higher gray value is very concentrated.
However, we hope that the histogram distribution is relatively scattered and can cover the whole x-axis.So, we need a transform function to help us map the current histogram to a widely distributed histogram.
Now we need to find the minimum value in the histogram (except 0), and use it in the histogram equalization formula in this picture.We used numpy’s mask array, all operations on mask arrays are only valid for non-masked elements.
# -*- coding: utf-8 -*-
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('wiki.jpg',0)
# flatten() Change to one-dimensional array
hist,bins = np.histogram(img.flatten(),256,[0,256])
# Calculate cumulative distribution
cdf = hist.cumsum() # accumulation
# create Numpy Mask array. CDF is the original array,If the array element is 0.Calculation ignored
cdf_m = np.ma.masked_equal(cdf,0)
cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
# Masked elements is 0
cdf = np.ma.filled(cdf_m,0).astype('uint8')
# Apply this transformation to the image
img2 = cdf[img]
hist1,bins = np.histogram(img2.flatten(),256,[0,256])
cdf2 = hist1.cumsum() # accumulation
cdf_normalized = cdf2 * hist.max()/ cdf2.max() # normalized
plt.plot(cdf_normalized, color = 'b')
plt.hist(img2.flatten(),256,[0,256], color = 'r')
plt.xlim([0,256])
plt.legend(('cdf','histogram'), loc = 'upper left')
plt.show()
The important feature is that even if our input image is a darker image, we can get the same result after histogram equalization.Therefore, histogram equalization is often used as a reference tool to judge that the image has the same brightness.
OpenCV
The histogram equalization function in OpenCV is cv2. cv2.equalizeHist(),Input image of this function is only a gray image, and the result is the balanced image.
import cv2
import numpy as np
img = cv2.imread('wiki.jpg',0)
equ = cv2.equalizeHist(img)
res = np.hstack((img,equ))
#stacking images side-by-side
cv2.imshow('res.png',res)
cv2.waitKey(-1)
Histogram equalization is very useful when the data in histogram is concentrated in a certain range.
However, if the pixel changes greatly and occupies a very wide range, it will not change much.
CLAHE
Adaptive histogram equalization: The image will be divided into many pieces, which are called “tiles”(The default size of tiles in OpenCV is 8x8), and equalize each block. The histogram will be concentrated in a small area.
import cv2
img = cv2.imread('tsukuba_l.png',0)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)
cv2.imshow('img',cl1)
cv2.waitKey(0)