In the previous post, we discussed about histograms and how to equilize images, in this post we are going to talk about how to compare histograms. Histogram Comparison is one of the oldest way of comparing images in order to classify them according to a reference image. The main core idea behind this technique is to “reduce” the image to a histogram representation and compare it with other image histograms by using a metric in order to provide a rank of similarity between to images.

The histogram comparison methods can be classified into two categories:

The former category (Bin-to-bin) assumes that two histograms have to be aligned but such an assumpition is easy to violate because in most cases two images do not have the same lighting conditions, quantiztion, etc. Instead, the latter category (Cross-bin), is more robust and discriminative but it is computationally expensive. To reduce such a computation, the cross-bin methods can be reduced to bin-to-bin methods.

OpenCV provides the following function:

cv2.compareHist(Hist_1, Hist_2, method)

where method could be:

While for Correlation and Intersection, the higher the metric, the more accurate the match. For Bhattacharyya and Chi-square the lower metric value represents a more accurate match.

Let’s code it:

import cv2
import numpy as np

#read the images
reference_img = cv2.imread("reference_image.jpg")
test_img = cv2.imread("test_image.jpg")

# Convert it to HSV
reference_hsv = cv2.cvtColor(reference_img, cv2.COLOR_BGR2HSV)
test_hsv = cv2.cvtColor(test_img, cv2.COLOR_BGR2HSV)
 
# Calculate the histogram and normalize it
hist_reference = cv2.calcHist([reference_hsv], [0,1], None, [180,256], [0,180,0,256])
cv2.normalize(hist_reference, hist_reference, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX)

test_reference = cv2.calcHist([test_hsv], [0,1], None, [180,256], [0,180,0,256])
cv2.normalize(test_reference, test_reference, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX)

# find the metric value
metrics = {cv2.HISTCMP_CORREL: 'Correlation', cv2.HISTCMP_CHISQR: 'Chi-square', cv2.HISTCMP_CHISQR_ALT: 'Alternative Chi-square', cv2.HISTCMP_INTERSECT: 'Intersection', cv2.HISTCMP_BHATTACHARYYA: 'Bhattacharyya', cv2.HISTCMP_HELLINGER: 'Hellinger', cv2.HISTCMP_KL_DIV: 'Kullback-Leibler divergence'}

metric_vals = {}

for key, value in metrics.items():
    metric_vals[key] = cv2.compareHist(hist_reference, test_reference, key)

images = [reference_img]

font                   = cv2.FONT_HERSHEY_SIMPLEX
topLeftCornerOfText = (10, 30)
fontScale              = 1
fontColor              = (0, 0, 255)
lineType               = 2


for key, value in metrics.items():
    img = test_img.copy()
    cv2.putText(img, value+": "+str(metric_vals[key]), topLeftCornerOfText, 
    font, 
    fontScale,
    fontColor,
    lineType)
    images.append(img)

#concatenating the bgr image and the canny one
concat_image = np.concatenate(np.array(images), axis=1)

#show the image
cv2.imshow("result", concat_image)
cv2.waitKey(0)

So, if we execute the above code by using the same image as reference and test we get:

Dark Histogram

So, Image Histogram Comparison could be a very useful tool for calculating the similarity between images and can be seen as an archaic image classification method.