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?
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.
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.
The intensity is the sum of the RGB values normalized to 1: 1 1= 3(R + G+ B). (10.11) - R+G+B.
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.
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.
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...)
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