I'm currently trying to determine the color difference between our output image and a painting of Monet with Python using OpenCV.
With my research I've seen that Delta E is the best for determining color difference. I've tried using extracting the BGR Channels of the two images and then taking the mean "Blue" "Green" and "Red" color used to use for computing the difference of each color channel.
output_chans = cv2.split(image)
monet_chans = cv2.split(best_painting)
colors = ("Blue", "Green", "Red")
for (output_chan, monet_chan, color) in zip(output_chans, monet_chans, colors):
output_mean = np.mean(output_chan)
monet_mean = np.mean(monet_chan)
color1_rgb = None
color2_rgb = None
if color == "Blue":
color1_rgb = sRGBColor(0.0, 0.0, output_mean)
color2_rgb = sRGBColor(0.0, 0.0, monet_mean)
elif color == "Green":
color1_rgb = sRGBColor(0.0, output_mean, 0.0);
color2_rgb = sRGBColor(0.0, monet_mean, 0.0);
elif color == "Red":
color1_rgb = sRGBColor(output_mean, 0.0, 0.0);
color2_rgb = sRGBColor(monet_mean, 0.0, 0.0);
# Convert from RGB to Lab Color Space
color1_lab = convert_color(color1_rgb, LabColor);
# Convert from RGB to Lab Color Space
color2_lab = convert_color(color2_rgb, LabColor);
# Find the color difference
delta_e = delta_e_cie2000(color1_lab, color2_lab);
print("Delta E of the Mean of %s Channel: %f" % (color, delta_e))
I receive an output of for the color difference for each color channel, however my professor suggests that I may be doing Delta E wrong as I'm supposed to only get one value for the color difference of the entire image instead of one value for each three color channels. In this case is there an alternative method or a correct method of of calculating the Delta E of our two images?
This is a link to a sample of our test image: https://imgur.com/a/KToggFS
And a link to a sample of the paintings: https://imgur.com/a/vi1SFax
To calculate the Delta E variance from the produced color to the target, you square each reading's distance (to ensure a positive number). Then you add all of the squares of those readings and take the square root of that number and this gives you the Delta E variance.
Use the norm() Function of OpenCV to Compare Images If the two images that we want to compare have the same size and orientation, we can use the norm() function of OpenCV. This function finds errors present in identical pixels of the two images.
As a whole, the term Delta E means a difference in sensation. Delta E is measured on a scale from 0 to 100, where 0 is less color difference, and 100 indicates complete distortion. As explained in this guide by Zachary Schuessler, standard perception ranges are as follows: <= 1.0: Not perceptible by the human eye.
Brief Explanation of delta E or delta E* Follow a* represents redness-greenness of the color. Positive values of a* are red; negative values of a* are green; 0 is neutral. b* represents yellowness-blueness of the color. Positive values of b* are yellow; negative values of b* are blue; 0 is neutral.
you seem to be using the colormath
library which does the math nicely, but is very slow. the colour-science
package uses numpy to vectorise operations and get an answer in much less time
the cv2
library you're using has simple versions of some of the transformations you need, e.g. you can get most of the way doing:
import cv2
image1_rgb = cv2.imread('image1.jpeg')
image2_rgb = cv2.imread('image2.jpeg')
image1_lab = cv2.cvtColor(image1_rgb, cv2.COLOR_RGB2Lab)
image2_lab = cv2.cvtColor(image2_rgb, cv2.COLOR_RGB2Lab)
but note that you'll probably get better results if you convert to floats first:
image_lab = cv2.cvtColor(image_rgb.astype(np.float32) / 255, cv2.COLOR_RGB2Lab)
and then just use color-science
for the final call to delta_E()
for each pixel (but note these are all vectorised, so you just give it the array of everything and it does it all efficiently at once):
import colour
delta_E = colour.delta_E(image1_lab, image2_lab)
and then you'll probably want the mean of this over the whole image:
np.mean(delta_E)
but median, quantiles, or a plotting the distribution would give you more information
note that if you care about color spaces and need more control over the transform from RGB to Lab you get a lot more control with colour-science
, with the rough template looking like:
image_lab = colour.XYZ_to_Lab(colour.sRGB_to_XYZ(image_srgb))
and there are lots of options about how to do this transform along the way, see docs for colour.XYZ_to_Lab
and colour.XYZ_to_Lab
.
The above answer is correct. However, if you are looking for more simplified way for calculating Delta E, i.e. by avoiding extra dependencies. You can simply calculate calculate the Euclidean distance between the two images and take mean.
def deltaE(img1, img2, colorspace = cv2.COLOR_BGR2LAB):
# check the two images are of the same size, else resize the two images
(h1, w1) = img1.shape[:2]
(h2, w2) = img1.shape[:2]
h, w = None, None
# check the height
if h1 > h2:
h = h1
else:
h = h2
#check the width
if w1 > w2:
w = w1
else:
w = w2
img1 = cv2.resize(img1, (h,w))
img2 = cv2.resize(img2, (h,w))
# Convert BGR images to specified colorspace
img1 = cv2.cvtColor(img1, colorspace)
img2 = cv2.cvtColor(img2, colorspace)
# compute the Euclidean distance with pixels of two images
return np.sqrt(np.sum((img1 - img2) ** 2, axis=-1))/255.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With