Search code examples
pythonimageopencvhistogram

Implementing Histogram Spread for Image Contrast Metrics


Currently I'm trying to compute histogram spread for image contrast metrics based on this paper Performance metrics for image contrast. The algorithm for easier and faster to read showed by this screenshot of the paper:

snippet from paper

Or by quoting the paper:

Histogram spread is the ratio of the quartile distance to the range of the histogram. Quartile distance is denoted as the difference between the 3 rd quartile and the 1 st quartile. Here 3 rd quartile and 1 st quartile means the histogram bins at which cumulative histogram have 75% and 25% of the maximum value respectively (see Fig.1)

I use these two images for these experiments which both are medical images (mammograms):

  1. Sample 1:

    sample1

  2. Sample 2:

    sample2

Here is the code that I used:

import cv2
import numpy as np


def calculate_histogram_spread(gray_img):

    #compute image histogram and its cdf
    histo,_ = np.histogram(gray_img.flatten(),256,[0,256])
    cdf = np.cumsum(histo)

    #calculate the Q3 (75%percentile) and Q1 (25%percentile) 
    Q3 = np.percentile(cdf,75)
    Q1 = np.percentile(cdf,25)

    #find the which bin value  
    Q3_bin = np.searchsorted(cdf,Q3) 
    Q1_bin = np.searchsorted(cdf,Q1)
    
    IQR = Q3_bin - Q1_bin
    divider = np.max(gray_img) - np.min(gray_img)

    HS = IQR/divider
    return Q3_bin,Q1_bin,HS

if __name__ == '__main__':

    sample1 = '/home/mario/Desktop/hs1.jpg'
    sample2 = '/home/mario/Desktop/hs2.jpg'
 
    img1 = cv2.imread(sample1,0)
    img2 = cv2.imread(sample2,0)

    print('Sample1')
    Q3_bin,Q1_bin,HS = calculate_histogram_spread(img1)
    print('Q3_bin={},Q1_bin={},HS={}'.format(Q3_bin,Q1_bin,HS))

    print('Sample2')
    Q3_bin,Q1_bin,HS = calculate_histogram_spread(img2)
    print('Q3_bin={},Q1_bin={},HS={}'.format(Q3_bin,Q1_bin,HS))

Here is my terminal result:

Sample1
Q3_bin=192,Q1_bin=64,HS=0.5019607843137255
Sample2
Q3_bin=192,Q1_bin=64,HS=0.5019607843137255

My question is why the two images have the same exact output while visually the images have different contrast (I think)? Did I do any mistakes? I'm testing those images in same size/resolution.


Solution

  • This seems to give different contrast values for me in Python/OpenCV.


    Input 1:

    enter image description here

    Input 2:

    enter image description here


    import cv2
    import numpy as np
    
    # load images as grayscale
    img = cv2.imread("breast1.jpg", 0)
    #img = cv2.imread("breast2.jpg", 0)
    hh, ww = img.shape[:2]
    
    # compute total pixels
    tot = hh * ww
    
    # compute histogram
    hist = np.histogram(img,bins=256,range=[0,255])[0]
    
    # compute cumulative histogram
    cum = np.cumsum(hist)
    
    # normalize histogram to range 0 to 100
    cum = 100 * cum / tot
    
    # get bins of percentile at 25 and 75 percent in cum histogram
    i = 0
    while cum[i] < 25:
        i = i+1
    B1 = i
    i = 0
    while cum[i] < 75:
        i = i+1
    B3 = i
    print('25 and 75 percentile bins:',B1,B3)
    
    # compute min and max graylevel (which are also the min and max bins)
    min = np.amin(img)
    max = np.amax(img)
    print('min:',min,  'max:',max)
    
    # compute contrast
    contrast = (B3-B1)/(max-min)
    print('contrast:',contrast)
    

    Result for Image 1:

    25 and 75 percentile bins: 0 147
    min: 0 max: 255
    contrast: 0.5764705882352941
    

    Result for Image 2:

    25 and 75 percentile bins: 58 162
    min: 0 max: 255
    contrast: 0.40784313725490196