Reputation: 99
I am new to Histogram comparisons.
This code uses these images to make a histogram comparison. The result was impressive with a 0.99 %, however I think that the result resulted in 99% because of the background color. Can someone tell me how can I ignore the white color and compare the actual fruit.
The following code was found here.
# Load the images
img1 = cv2.imread('D:/downloads/app1.jpg')
img2 = cv2.imread('D:/downloads/app2.jpg')
# Convert it to HSV
img1_hsv = cv2.cvtColor(img1, cv2.COLOR_BGR2HSV)
img2_hsv = cv2.cvtColor(img2, cv2.COLOR_BGR2HSV)
# Calculate the histogram and normalize it
hist_img1 = cv2.calcHist([img1_hsv], [0,1], None, [180,256], [0,180,0,256])
cv2.normalize(hist_img1, hist_img1, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX);
hist_img2 = cv2.calcHist([img2_hsv], [0,1], None, [180,256], [0,180,0,256])
cv2.normalize(hist_img2, hist_img2, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX);
# find the metric value
metric_val = cv2.compareHist(hist_img1, hist_img2, cv2.HISTCMP_BHATTACHARYYA)
Upvotes: 5
Views: 7200
Reputation: 27557
You'll only need to raise the minimum saturation value for an HSV mask to effectively mask away all the white background:
import cv2
import numpy as np
def get_masked(img):
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower = np.array([0, 50, 0])
upper = np.array([179, 255, 255])
mask = cv2.inRange(img_hsv, lower, upper)
return cv2.bitwise_and(img, img, mask=mask)
img1 = cv2.imread("apple1.png")
img2 = cv2.imread("apple2.png")
cv2.imshow("Apple 1", get_masked(img1))
cv2.imshow("Apple 2", get_masked(img2))
cv2.waitKey(0)
Upvotes: 2
Reputation: 18895
Using some mask as Fred suggested seems to be the cleanest solution, but Fred's comment regarding the HSV color space is even more important here! But, first of all, the reported metric value of 0.99...
(also in the linked article) was obtained using cv2.HISTCMP_CORREL
, not using cv2.HISTCMP_BHATTACHARYYA
!
Now, let's stick to OpenCV's common BGR color space, and adapt the code:
import cv2
# Load the images
img1 = cv2.imread('app1.png')
img2 = cv2.imread('app2.png')
# Calculate the histograms, and normalize them
hist_img1 = cv2.calcHist([img1], [0, 1, 2], None, [256, 256, 256], [0, 256, 0, 256, 0, 256])
cv2.normalize(hist_img1, hist_img1, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX)
hist_img2 = cv2.calcHist([img2], [0, 1, 2], None, [256, 256, 256], [0, 256, 0, 256, 0, 256])
cv2.normalize(hist_img2, hist_img2, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX)
# Find the metric value
metric_val = cv2.compareHist(hist_img1, hist_img2, cv2.HISTCMP_CORREL)
print(metric_val)
# 0.9995753648895891
The metric value is still something at 99.9 %.
So, now, let's ignore all white pixels by manually setting hist_imgx[255, 255, 255] = 0
:
import cv2
# Load the images
img1 = cv2.imread('app1.png')
img2 = cv2.imread('app2.png')
# Calculate the histograms, set bin for (255, 255, 255) to 0, and normalize them
hist_img1 = cv2.calcHist([img1], [0, 1, 2], None, [256, 256, 256], [0, 256, 0, 256, 0, 256])
hist_img1[255, 255, 255] = 0
cv2.normalize(hist_img1, hist_img1, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX)
hist_img2 = cv2.calcHist([img2], [0, 1, 2], None, [256, 256, 256], [0, 256, 0, 256, 0, 256])
hist_img2[255, 255, 255] = 0
cv2.normalize(hist_img2, hist_img2, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX)
# Find the metric value
metric_val = cv2.compareHist(hist_img1, hist_img2, cv2.HISTCMP_CORREL)
print(metric_val)
# 0.6199666001215806
And, the metric value drops to 62 %!
So, your assumption seems to be correct, the white background distorts the whole histogram comparison.
----------------------------------------
System information
----------------------------------------
Platform: Windows-10-10.0.16299-SP0
Python: 3.9.1
PyCharm: 2021.1.1
OpenCV: 4.5.1
----------------------------------------
Upvotes: 8