Very basic scoring to compare images.
How to quantify difference between two images?
- Are images of the same area and dimension?
- Is lightness/contrast the same? Is color information important?
Very basic scoring to compare images.
How to quantify difference between two images?
def __init__(self, img1, img2):
self.__img1 = img1
self.__img2 = img2
Return a score based on the Euclidian distance.
DOES NOT WORK: can't get the max distance !!!!
def compare_with_distance(self):
"""Return a score based on the Euclidian distance.
DOES NOT WORK: can't get the max distance !!!!
"""
w1, h1 = self.__img1.size()
w2, h2 = self.__img2.size()
img1 = self.__img1.iresize(width=min(w1, w2), height=min(h1, h2))
img2 = self.__img2.iresize(width=min(w1, w2), height=min(h1, h2))
dist = img1.euclidian_distance(img2)
black = img1.blank_image()
white = img1.blank_image(white=True)
dist_max = black.euclidian_distance(white)
return 1.0 - dist / dist_max
Mix all comparison scores to return a single one.
Linear interpolation with empirically fixed weights.
def score(self):
"""Mix all comparison scores to return a single one.
Linear interpolation with empirically fixed weights.
"""
s1 = self.compare_areas()
s2 = self.compare_sizes()
s3 = self.compare_with_mse()
s4 = self.compare_with_kld()
return 0.2 * s1 + 0.2 * s2 + 0.4 * s3 + 0.2 * s4
Return a score on how image areas are similar.
def compare_areas(self):
"""Return a score on how image areas are similar.
:return: (float) value between 0. and 1.
"""
w1, h1 = self.__img1.size()
w2, h2 = self.__img2.size()
area1 = w1 * h1
area2 = w2 * h2
min_area = min(area1, area2)
max_area = max(area1, area2)
if max_area < 2:
return 0.0
return float(min_area) / float(max_area)
Return a score on how image sizes are similar.
def compare_sizes(self):
"""Return a score on how image sizes are similar.
:return: (float) value between 0. and 1.
"""
w1, h1 = self.__img1.size()
w2, h2 = self.__img2.size()
w_min = min(w1, w2)
w_max = max(w1, w2)
h_min = min(h1, h2)
h_max = max(h1, h2)
w_ratio = 0.0
if w_max > 2:
w_ratio = float(w_min) / float(w_max)
h_ratio = 0.0
if h_max > 2:
h_ratio = float(h_min) / float(h_max)
return (w_ratio + h_ratio) / 2.0
Return a score to compare images with the Mean Squared Error.
def compare_with_mse(self):
"""Return a score to compare images with the Mean Squared Error.
:return: (float) value between 0. and 1.
"""
r1 = sppasImageCompare(self.__img1, self.__img2.ired()).mse()
r2 = sppasImageCompare(self.__img1.ired(), self.__img2).mse()
b1 = sppasImageCompare(self.__img1, self.__img2.iblue()).mse()
b2 = sppasImageCompare(self.__img1.iblue(), self.__img2).mse()
g1 = sppasImageCompare(self.__img1, self.__img2.igreen()).mse()
g2 = sppasImageCompare(self.__img1.igreen(), self.__img2).mse()
total = r1 + r2 + b1 + b2 + g1 + g2
mini = min((r1, r2, b1, b2, g1, g2))
if round(total, 2) == 0.0:
return 1.0
return min(1.0, max(0.0, 1.0 - self.mse() / mini))
Return the Mean Squared Error between the two images.
def mse(self):
"""Return the Mean Squared Error between the two images.
:return: (float) The lower the error, the more similar the images are
"""
img1_gray = self.__img1.igray()
img2_gray = self.__img2.igray()
w1, h1 = self.__img1.size()
w2, h2 = self.__img2.size()
img1 = img1_gray.iresize(width=min(w1, w2), height=min(h1, h2))
img2 = img2_gray.iresize(width=min(w1, w2), height=min(h1, h2))
err = numpy.sum((img1.astype('float') - img2.astype('float')) ** 2)
err /= float(img1.shape[0] * img2.shape[1])
return float(err)
Return a score to compare images with the Kullback-Leibler Dist.
def compare_with_kld(self):
"""Return a score to compare images with the Kullback-Leibler Dist.
:return: (float) value between 0. and 1.
"""
w1, h1 = self.__img1.size()
w2, h2 = self.__img2.size()
w = max(w1, w2)
h = max(h1, h2)
img1 = self.__img1 // 8
img2 = self.__img2 // 8
rgb1 = self.img_to_rgb_values(img1)
rgb2 = self.img_to_rgb_values(img2)
obs1 = rgb1.tolist()
obs2 = rgb2.tolist()
neg_img1 = img1.inegative()
neg_img2 = img2.inegative()
neg_rgb1 = self.img_to_rgb_values(neg_img1)
neg_rgb2 = self.img_to_rgb_values(neg_img2)
neg_obs1 = neg_rgb1.tolist()
neg_obs2 = neg_rgb2.tolist()
model = self.img_to_rgb_dict(rgb1)
kl = sppasKullbackLeibler(model=model)
kl.set_epsilon(1.0 / float(w * h * 2))
kl.set_observations(neg_obs1)
dist_max1 = kl.eval_kld()
kl.set_observations(obs2)
dist1 = kl.eval_kld()
model = self.img_to_rgb_dict(rgb2)
kl = sppasKullbackLeibler(model=model)
kl.set_epsilon(1.0 / float(w * h * 2))
kl.set_observations(neg_obs2)
dist_max2 = kl.eval_kld()
kl.set_observations(obs1)
dist2 = kl.eval_kld()
norm = (dist1 + dist2) / (dist_max1 + dist_max2)
return min(1.0, max(0.0, 1.0 - norm))
Return the Kullback-Leibler Distance between the two images.
def kld(self):
"""Return the Kullback-Leibler Distance between the two images.
:return: (float) The lower the distance, the more similar the images are
"""
img1 = self.__img1 // 16
img2 = self.__img2 // 16
w1, h1 = img1.size()
w2, h2 = img1.size()
model = self.img_to_rgb_dict(img1)
rgb2 = self.img_to_rgb_values(img2)
obs = rgb2.tolist()
kl = sppasKullbackLeibler(model=model, observations=obs)
kl.set_epsilon(1.0 / (2.0 * (w1 * h1 + w2 * h2)))
return kl.eval_kld()
@staticmethod
def img_to_rgb_dict(img):
if isinstance(img, sppasImage):
rgb = sppasImageCompare.img_to_rgb_values(img)
else:
rgb = img
unique, counts = numpy.unique(rgb, return_counts=True)
occ1 = dict(zip(unique, counts))
model = dict()
n1 = len(rgb)
for obs in occ1:
model[obs] = float(occ1[obs]) / float(n1)
return model
Return a numpy.array representing a unique value of the colors.
@staticmethod
def img_to_rgb_values(img):
"""Return a numpy.array representing a unique value of the colors.
:param img: (sppasImage)
"""
b = numpy.array(img[:, :, 0], dtype=int).reshape(-1)
g = numpy.array(img[:, :, 1], dtype=int).reshape(-1)
g = g * 255
r = numpy.array(img[:, :, 2], dtype=int).reshape(-1)
r = r * 65535
return r + g + b