Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

An algorithm for selecting a dark color similar to a light color

I'm making a chat where users can select their own preferred text color. The same chat will be displayed in several places in the website. In some places the background will be dark, and in others - light. As a result, most selected colors will probably be illegible in some of the chatboxes.

So I'm looking for an algorithm that, given a color which works well on one type of background (light or dark), produces another color which looks good on the opposite type of background and is as similar to the first color as possible (so the user gets the impression that he is using the same color everywhere).

I know this is probably impossible to do perfectly, but any attempts are welcome.

like image 769
Vilx- Avatar asked Feb 24 '13 07:02

Vilx-


2 Answers

Look into http://en.wikipedia.org/wiki/HSL_and_HSV

As long as you keep the hue and saturation constant it would seem the same color, and you can play with the brightness for contrast with the background

like image 29
Ofir Avatar answered Oct 02 '22 12:10

Ofir


Okay, after reading about a couple of things here and there. Here is what I was able to find out so far.

First of all I would like to highlight a few points and make sure that anyone that is reading my answer is able to understand what I'm talking about here.

What is a Color Space?

A range of colors can be created by the primary colors of pigment and these colors then define a specific color space. Color space, also known as the color model (or color system), is an abstract mathematical model which simply describes the range of colors as tuples of numbers, typically as 3 or 4 values or color components (ex: RGB). Basically speaking, color space is an elaboration of the coordinate system and sub-space. Each color in the system is represented by a single dot.


Most of us developers uses one of the following color spaces (HEX, RGB, RGBA) some even go to use (CMYK, HSV & HSL, etc) Which can provide you with any color that you want through the combination of the main colors (Red, Green, Blue, Alpha).

If we want to know if a color is close to another color we look at it with our eyes, but since we would like to have the computer programmatically do it for us then we have look at it in a mathematical manner.

Given that color A is Red in HEX color space #FF0000 and color B is Green in HEX color space as well #00FF00 and from our understanding of RGB we the have the first two values are the representation of the Red color, the second two values are the representation of the Green color and the last two values are the representation of the Blue color and since we know that each one these values are a number representation of its value (0-9) then (A, B, C, D, F) = (10, 11, 12, 13, 14). Then we can draw the color in a 3D dimension and calculate the distance between them using a law like Euclidean.

EX: A = (R1 = FF, G1 = 00, B1 = 00)
B = (R2 = 00, G2 = FF, B2 = 00)
We have our two point here, now we can use Euclidean law
Distance = sqrt((R2 - R1)^2 + (G2 - G1)^2 + (B2 - B1)^2)

So far so good, right?
Nope.

Wither we used HEX, RGBA, CMYK or any other color space we won't be able to know anything except the distance between the two colors in their color space which sometime might be completely different color yet the distance is between them is low because they don't take in consideration how our eyes see colors.

But there exist other color spaces (scientific ones) that take in consideration the way our eyes see colors and how our mind interpret them. One of these are Lab.


Color Transformation

A color in one absolute color space can be converted into another absolute color space, and back again, in general; however, some color spaces may have gamut limitations, and converting colors that lie outside that gamut will not produce correct results. There are also likely to be rounding errors, especially if the popular range of only 256 distinct values per component (8-bit color) is used.


What is gamut?

In color reproduction, including computer graphics and photography, the gamut, or color gamut, is a certain complete subset of colors. The most common usage refers to the subset of colors which can be accurately represented in a given circumstance, such as within a given color space or by a certain output device.


Now that we understood the basic functionalities that we are going to implement let's start coding knowing the following equation.

HEX To RGB

We have HEX as the color representation in hexadecimal value we just have to get their decimal values and that it, now we have our color in RGB color space.
A = RGB(255, 0, 0) Red
B = RGB(0, 255, 0) Green

RGB To XYZ

We have to follow the following mathematical law
color = current color / 255
if color > 0.04045
color = ( ( color + 0.055 ) / 1.055 ) ^ 2.4
else
color = color / 12.92
color = color * 100
X = colorRed * 0.4124 + colorGreen * 0.3576 + colorBlue * 0.1805
Y = colorRed * 0.2126 + colorGreen * 0.7152 + colorBlue * 0.0722
Z = colorRed * 0.0193 + colorGreen * 0.1192 + colorBlue * 0.9505
That' it

EX:- A = RGB(255, 0, 0) Red
colorRed = 255/255
colorGreen = 0/255
colorBlue = 0/255

if (colorRed > 0.04045){
    colorRed = ( ( colorRed + 0.055 ) / 1.055 ) ^ 2.4
}else{
    colorRed = colorRed / 12.92
}
if (colorGreen > 0.04045){
    colorGreen = ( ( colorGreen + 0.055 ) / 1.055 ) ^ 2.4
}else{<br/>
    colorGreen = colorGreen / 12.92
}
if (colorBlue > 0.04045){
    colorBlue = ( ( colorBlue + 0.055 ) / 1.055 ) ^ 2.4
}else{
    colorBlue = colorBlue / 12.92
}

colorRed = colorRed * 100
colorGreen = colorGreen * 100
colorBlue = colorBlue * 100

X = (colorRed * 0.4124) + (colorGreen * 0.3576) + (colorBlue * 0.1805)
Y = (colorRed * 0.2126) + (colorGreen * 0.7152) + (colorBlue * 0.0722)
Z = (colorRed * 0.0193) + (colorGreen * 0.1192) + (colorBlue * 0.9505)

A XYZ(X, Y, Z)

XYZ To Lab

// Reference-X, Reference-Y and Reference-Z refer to specific illuminants and observers.

X = X / Reference-X
Y = Y / Reference-Y
Z = Z / Reference-Z

if ( X > 0.008856 ) {
    X = X ^ ( 1/3 )
}else{
    X = ( 7.787 * X ) + ( 16 / 116 )
}
if ( Y > 0.008856 ) {
    Y = Y ^ ( 1/3 )
}else{
    Y = ( 7.787 * Y ) + ( 16 / 116 )
}
if ( Z > 0.008856 ) {
    Z = Z ^ ( 1/3 )
}else{
    Z = ( 7.787 * Z ) + ( 16 / 116 )
}

CIE-L* = ( 116 * Y ) - 16
CIE-a* = 500 * ( X - Y )
CIE-b* = 200 * ( Y - Z )


References

//2o Observer (CIE 1931)
// X2, Y2, Z2
CIE2_A = {109.850f, 100f, 35.585f} //Incandescent
CIE2_C = {98.074f, 100f, 118.232f}
CIE2_D50 = {96.422f, 100f, 82.521f}
CIE2_D55 = {95.682f, 100f, 92.149f}
CIE2_D65 = {95.047f, 100f, 108.883f} //Daylight
CIE2_D75 = {94.972f, 100f, 122.638f}
CIE2_F2 = {99.187f, 100f, 67.395f} //Fluorescent
CIE2_F7 = {95.044f, 100f, 108.755f}
CIE2_F11 = {100.966f, 100f, 64.370f}

//10o Observer (CIE 1964)
// X2, Y2, Z2
CIE10_A = {111.144f, 100f, 35.200f} //Incandescent
CIE10_C = {97.285f, 100f, 116.145f}
CIE10_D50 = {96.720f, 100f, 81.427f}
CIE10_D55 = {95.799f, 100f, 90.926f}
CIE10_D65 = {94.811f, 100f, 107.304f} //Daylight
CIE10_D75 = {94.416f, 100f, 120.641f}
CIE10_F2 = {103.280f, 100f, 69.026f} //Fluorescent
CIE10_F7 = {95.792f, 100f, 107.687f}
CIE10_F11 = {103.866f, 100f, 65.627f}


Distance between two colors in Lap color Space

Treat the color as 3d dimension like we did earlier and now we have the exact distance between the two colors with respect to the human eye.


To Include

Research more for a technique that we should use in order to change the color yet have the same color but feels like another one for the human eyes and through it we can see the background and the things that are drawn on top of it using the same color.

--

Update #1 (10/09/2018)

There are some mathematical equations that calculate the Color Difference with respect to the human perception called CIE. There has been a few iteration of them along the years. (CIE 1976, CIE 1994, CIE 2000).

CIE 1976

It is the distance between he two colours in 3D space and it is pretty much the Euclidean Distance formula.

CIE 1994

In 1994, the original Delta E formula was improved. The new formula would take into account certain weighting factors for each lightness, chroma, and hue value.

CIE 2000

The CIE organization decided to fix the lightness inaccuracies by introducing dE00. It’s currently the most complicated, yet most accurate, CIE color difference algorithm available.

And since CIE 2000 is the most accurate one we will go straight to it.

P.S

You don't need to implement it yourself. I have created a version in Javascript on the github Is This Colour Similar Repository.

After running the code we will have a value which just say the difference between two colours with respect to the human perception and its value is from 0 to 100. Check the following table for more clarification.

╔═══════════════╦════════════════════════════════════════╗
║ Delta E Value ║               Perception               ║
╠═══════════════╬════════════════════════════════════════╣
║ <= 1.0        ║ Not perceptible by human eyes.         ║
║ 1 - 2         ║ Perceptible through close observation. ║
║ 2 - 10        ║ Perceptible at a glance.               ║
║ 11 - 49       ║ Colors are more similar than opposite. ║
║ 100           ║ Colors are exact opposite.             ║
╚═══════════════╩════════════════════════════════════════╝

Now we know if colour A is closer to colour B or not or a little bit far.

This is the first point. Now that we know that. What should we do to handle something like that. We can play with 3 things in the colour value.

Lab colour space is unique in the following sense.

The lightness value, L*, represents the darkest black at L* = 0, and the brightest white at L* = 100.

a* and b* for the green–red and blue–yellow color components.

The color channels, a* and b*, represent true neutral gray values at a* = 0 and b* = 0.

The a* axis represents the green–red component, with green in the negative direction and red in the positive direction.

The b* axis represents the blue–yellow component, with blue in the negative direction and yellow in the positive direction.

Since we want the same colour but a little bit darker or brighter what ever you require at this moment.

We would take the Lab value of that colour and change the L value. Because it is the one responsible for lightness or darkness of the colour. By adding (more brightness) to a small percentage (0.05) of the already existing L value or subtracting (more darkness) (0.05) of the already existing L value.

In the code provided a complete working example that you can check on the following URL Is This Colour Similar Online example.

Hope this would be helpful for you.

like image 98
hamada147 Avatar answered Oct 02 '22 14:10

hamada147