Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compute the Delta E between two images using OpenCV

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

like image 512
CaptWulfz Avatar asked Jul 26 '19 16:07

CaptWulfz


People also ask

How do you calculate Delta E?

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.

How do I compare two images in OpenCV?

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.

What is Delta E value?

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.

How do you interpret Delta E color?

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.


2 Answers

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.

like image 66
Sam Mason Avatar answered Nov 02 '22 18:11

Sam Mason


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.
like image 40
Kumar S Avatar answered Nov 02 '22 16:11

Kumar S