Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Given an RGB value what would be the best way to find the closest match in the database?

I have a rgb value and if it doesn't exist in the color table in my database I need to find the closest color. I was thinking of comparing all values and finding the difference(in red,green,and blue) then take the average. The lowest average deviation should be the closest color. There seems to me like there should be a better way. Any ideas?

like image 711
Mike Avatar asked Dec 04 '09 13:12

Mike


People also ask

How do you find the closest color?

The Euclidean distance difference = sqrt(sqr(red1 - red2) + sqr(green1 - green2) + sqr(blue1 - blue2)) is the standard way to determine the similarity of two colours.

How do you calculate RGB value?

The function R*0.2126+ G*0.7152+ B*0.0722 is said to calculate the perceived brightness (or equivalent grayscale color) for a given an RGB color. Assuming we use the interval [0,1] for all RGB values, we can calculate the following: yellow = RGB(1,1,0) => brightness=0.9278.

How do you calculate RGB values from intensity?

The intensity is the sum of the RGB values normalized to 1: 1 1= 3(R + G+ B). (10.11) - R+G+B.

What do RGB values range from?

Each level is represented by the range of decimal numbers from 0 to 255 (256 levels for each color), equivalent to the range of binary numbers from 00000000 to 11111111, or hexadecimal 00 to FF. The total number of available colors is 256 x 256 x 256, or 16,777,216 possible colors.


2 Answers

Consider a color as a vector in 3-dimensional space, you can then easily compute the difference by using 3d pythagoras:

d = sqrt((r2-r1)^2 + (g2-g1)^2 + (b2-b1)^2) 

However, note that due to colors being subject to interpretation by not-so-perfect eyes, you might want to adjust the colors to avoid them having the same importance.

For instance, using a typical weighted approach:

d = sqrt(((r2-r1)*0.3)^2 + ((g2-g1)*0.59)^2 + ((b2-b1)*0.11)^2) 

Since eyes are most sensitive to green, and least sensitive to blue, two colors that differ only in the blue component must thus have a larger numeric difference to be considered "more different" than one that is the same numeric difference in the green component.

There's also various ways to optimize this calculation. For instance, since you're not really interested in the actual d value, you can dispense with the square root:

d =   ((r2-r1)*0.30)^2     + ((g2-g1)*0.59)^2     + ((b2-b1)*0.11)^2 

Note here that in many C-syntax-based programming languages (like C#), ^ does not mean "raise to the power of", but rather "binary exclusive or".

So if this was C#, you would use Math.Pow to calculate that part, or just expand and do the multiplication.

Added: Judging by the page on Color difference on Wikipedia, there's various standards that try to handle perceptual differences. For instance, the one called CIE94 uses a different formula, in the L*C*h color model that looks like it's worth looking into, but it depends on how accurate you want it to be.

like image 153
Lasse V. Karlsen Avatar answered Oct 13 '22 20:10

Lasse V. Karlsen


The following does exactly what you describe:

select (abs(my_R - t.r) + abs(my_G - t.g) + abs(my_B - t.b)) / 3 as difference, t.* from RGBtable t order by difference desc; 

However, you might get better results with something that was non-linear. In the "take the averages" approach, if you goal color is (25, 25, 25) the color (45, 25, 25) would be closer than (35, 35, 35). However, I bet the second would actually look closer, since it would also be gray.

A few ideas come to mind: you could try squaring the differences before you average them. Or you could do something complicated with finding the color with the closest ratio between the different values. Finding the closest ratios would get you closest to the right hue, but won't account for saturation (if I'm remembering the terms right...)

like image 30
David Oneill Avatar answered Oct 13 '22 19:10

David Oneill