Search code examples
pythonopencvhistogram

How to obtain smooth histogram after scaling image?


I am trying to linearly scale an image so the whole greyscale range is used. This is to improve the lighting of the shot. When plotting the histogram however I don't know how to get the scaled histogram so that its smoother so it's a curve as aspired to discrete bins. Any tips or points would be much appreciated.

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

img = cv.imread(r'/Users/harold/Documents/Academia/Nottingham Uni/Year 4/ImageProcessing/Imaging_Task_Sheet/PointImage.jpeg', cv.IMREAD_GRAYSCALE)

img_s = img/255
img_s = img_s / np.max(img_s)
img_s = img_s*255

histogram = cv.calcHist([img], [0], None, [256], [0, 256])
histogram1 = cv.calcHist([img_s.astype('uint8')], [0], None, [256], [0, 256])

plt.figure()
plt.title("Grayscale Histogram")
plt.xlabel("grayscale value")
plt.ylabel("pixels")

plt.plot(histogram, label='Original Image')  # <- or here
plt.plot(histogram1, label='Equalised Image')  # <- or here

The histogram produced is:

enter image description here

Which is from this picture:

enter image description here


Solution

  • I think what you have in mind is a spline curve that passes through your points. Here is how to do it:

    import cv2 as cv
    import numpy as np
    import matplotlib.pyplot as plt
    
    from scipy import interpolate
    
    img = cv.imread(r'3NKTJ.jpg', cv.IMREAD_GRAYSCALE)
    
    img_s = img/255
    img_s = img_s / np.max(img_s)
    img_s = img_s*255
    
    histogram = cv.calcHist([img], [0], None, [256], [0, 256])
    histogram1 = cv.calcHist([img_s.astype('uint8')], [0], None, [256], [0, 256])
    
    x=np.linspace(0,len(histogram1),len(histogram1)) # x: 0 --> 255 with step=1
    
    X=np.where(histogram1>0)[0] # extract bins with non-zero histogram1 values
    Y=histogram1[X] # the corresponding Y values
    
    F=interpolate.splrep(X, Y)   # spline representation of (X,Y)
    Ynew = interpolate.splev(x, F) # calculate interpolated Ynew
    
    plt.figure()
    plt.title("Grayscale Histogram")
    plt.xlabel("grayscale value")
    plt.ylabel("pixels")
    
    plt.plot(histogram, label='Original Image')  # <- or here
    plt.plot(histogram1, label='Equalised Image')  # <- or here
    plt.plot(x,Ynew, label='spline interpolation of Equalised Image')
    

    Below, the result: enter image description here

    Best regards, Stéphane