How would you determine programmatically  whether Black text or White text is more readable on a colour background?

Here are a few algorithms to calculate the brightness of a color: (see the interactive demo at the bottom of this page)

1. Arithmetic Mean:

Formula:%5CLARGE%5C%21f%5E%5Cprime%28x%29%5C%20%3D%20%5Cfrac%7Br%20%2B%20g%20%2B%20b%7D3 How to calculate the Perceived Brightness of a colour

Screen Shot 2011 07 24 at 20.15.09 How to calculate the Perceived Brightness of a colour

AS3 Code:

public static function arithmeticMean(hex:uint):Number
{
var rgb:Array = ColorUtils.hex2rgb(hex);
return (rgb[0] + rgb[1] + rgb[2])/3;
}
public static function arithmeticMean(hex:uint):Number
{
var rgb:Array = ColorUtils.hex2rgb(hex);
return (rgb[0] + rgb[1] + rgb[2])/3;
}

It was a very simple and effective algorithm. Unfortunately it failed between the green and turquoise region:
Screen Shot 2011 07 24 at 20.17.39 How to calculate the Perceived Brightness of a colour

 

Geometric Mean:

Formula:%5CLARGE%5C%21f%5E%5Cprime%28x%29%5C%20%3D%20%5Csqrt%5Bn%5D%7Br%20%20g%20%20b%7D How to calculate the Perceived Brightness of a colour

Screen Shot 2011 07 24 at 20.30.50 How to calculate the Perceived Brightness of a colour

AS3 Code:

public static function geometricMean(hex:uint):Number
{
var rgb:Array = ColorUtils.hex2rgb(hex);
return Math.pow(rgb[0] * rgb[1] * rgb[2],1/3);
}
public static function geometricMean(hex:uint):Number
{
var rgb:Array = ColorUtils.hex2rgb(hex);
return Math.pow(rgb[0] * rgb[1] * rgb[2],1/3);
}

Ok, the green is a lot better, but now the brightness of the yellow is wrong:

Screen Shot 2011 07 24 at 20.31.59 How to calculate the Perceived Brightness of a colour

Quadratic Mean:

Formula:%5CLARGE%5C%21f%5E%5Cprime%28x%29%5C%20%3D%20%5Csqrt%7B%5Cfrac%7Br%5E2%20g%5E2%20b%5E2%7D%7B3%7D%7D How to calculate the Perceived Brightness of a colour

Screen Shot 2011 07 24 at 20.35.00 How to calculate the Perceived Brightness of a colour

AS3 Code:

public static function quadraticMean(hex:uint):Number
{
var rgb:Array = ColorUtils.hex2rgb(hex);
return Math.pow( (rgb[0]*rgb[0] + rgb[1]*rgb[1] + rgb[2]*rgb[2])/3 ,1/2);
}
public static function quadraticMean(hex:uint):Number
{
var rgb:Array = ColorUtils.hex2rgb(hex);
return Math.pow( (rgb[0]*rgb[0] + rgb[1]*rgb[1] + rgb[2]*rgb[2])/3 ,1/2);
}

Works really well for all dark colours. Fails on purple.

HSV Value (Brightest Component):

Formula: %5CLARGE%5C%21f%5E%5Cprime%28x%29%5C%20%3D%20%5Cmax %7Br%2C%20g%2C%20b%7D How to calculate the Perceived Brightness of a colour

Screen Shot 2011 07 24 at 20.43.26 How to calculate the Perceived Brightness of a colour

AS3 Code:

public static function valueFromHSV(hex:uint):Number
{
var hsv:Array = ColorUtils.hex2hsv(hex);
return hsv[2]*255;
}
public static function valueFromHSV(hex:uint):Number
{
var hsv:Array = ColorUtils.hex2hsv(hex);
return hsv[2]*255;
}

Dark colours are ok, Fails when the r, g or b value is close to 0x99

Darkest Component:

Formula: %5CLARGE%5C%21f%5E%5Cprime%28x%29%5C%20%3D%20%5Cmin %7Br%2C%20g%2C%20b%7D How to calculate the Perceived Brightness of a colour

Screen Shot 2011 07 24 at 20.52.08 How to calculate the Perceived Brightness of a colour

AS3 Code:

public static function darkestComponent(hex:uint):Number
{
var rgb:Array = ColorUtils.hex2rgb(hex);
return Math.min(rgb[0], rgb[1], rgb[2]);
}
public static function darkestComponent(hex:uint):Number
{
var rgb:Array = ColorUtils.hex2rgb(hex);
return Math.min(rgb[0], rgb[1], rgb[2]);
}

Only the very bright colours work fine with this algorithm.

3D distance in RGB space:

Formula: %5CLARGE%5C%21f%5E%5Cprime%28x%29%5C%20%3D%20%5Csqrt%7Br%5E2%20%2B%20g%5E2%20%2B%20b%5E2%7D How to calculate the Perceived Brightness of a colour

Screen Shot 2011 07 24 at 20.53.51 How to calculate the Perceived Brightness of a colour

AS3 Code:

public static function distanceIn3D(hex:uint):Number
{
var rgb:Array = ColorUtils.hex2rgb(hex);
return Math.sqrt( (rgb[0]*rgb[0] + rgb[1]*rgb[1] + rgb[2]*rgb[2]));
}
public static function distanceIn3D(hex:uint):Number
{
var rgb:Array = ColorUtils.hex2rgb(hex);
return Math.sqrt( (rgb[0]*rgb[0] + rgb[1]*rgb[1] + rgb[2]*rgb[2]));
}

Worse than using the V component of the HSV representation.

Lightness From HSL:

Screen Shot 2011 07 24 at 20.57.08 How to calculate the Perceived Brightness of a colour

AS3 Code:

public static function lightnessFromHSL(hex:uint):Number
{
var hsl:Array = ColorUtils.hex2hsl(hex);
return hsl[2]*255;
}
public static function lightnessFromHSL(hex:uint):Number
{
var hsl:Array = ColorUtils.hex2hsl(hex);
return hsl[2]*255;
}

The best unweighted formula. Fails on yellow around 0xeeee00.

Weighted Algorithms

Natural formulas don’t take into consideration that the human eye perceives some of the primary colours darker than others.

Eg pure green(0xff0000) is perceived brighter than pure blue(0x00ff00).
According to the W3C consortium, this biased perception can be modelled with the following weights:

r *= .299
g *= .587
b *= .111
r *= .299
g *= .587
b *= .111

Weighted W3C Formula:

Formula: %5CLARGE%5C%21f%5E%5Cprime%28x%29%5C%20%3D%20%5Cfrac%7Br%2A299%20%2B%20g%2A587%20%2Bg%2A117%7D%7B1000%7D How to calculate the Perceived Brightness of a colour

Screen Shot 2011 07 24 at 21.11.02 How to calculate the Perceived Brightness of a colour

AS3 Code:

public static function weightedW3C(hex:uint):Number
{
var rgb:Array = ColorUtils.hex2rgb(hex);
return ((rgb[0] * 299) + (rgb[1] * 587) + (rgb[2] * 114)) / 1000;
}
public static function weightedW3C(hex:uint):Number
{
var rgb:Array = ColorUtils.hex2rgb(hex);
return ((rgb[0] * 299) + (rgb[1] * 587) + (rgb[2] * 114)) / 1000;
}

Very good algorithm, works really well. Source: http://www.w3.org/TR/AERT#color-contrast

Weighted Distance in 3D RGB Space:

Formula:

%5CLARGE%5C%21f%5E%5Cprime%28x%29%5C%20%3D%20%5Csqrt%7B%20r%5E2%20%2A%200.241%20%2B%20g%5E2%20%2A%200.691%20%2B%20b%5E2%20%2A%200.068%7D How to calculate the Perceived Brightness of a colour

Screen Shot 2011 07 24 at 21.17.13 How to calculate the Perceived Brightness of a colour

AS3 Code:

public static function weightedDistanceIn3D(hex:uint):Number
{
var rgb:Array = ColorUtils.hex2rgb(hex);
return Math.sqrt(rgb[0] * rgb[0] * .241 + rgb[1] * rgb[1] * .691 + rgb[2] * rgb[2] * .068);
}
public static function weightedDistanceIn3D(hex:uint):Number
{
var rgb:Array = ColorUtils.hex2rgb(hex);
return Math.sqrt(rgb[0] * rgb[0] * .241 + rgb[1] * rgb[1] * .691 + rgb[2] * rgb[2] * .068);
}

An improved version of the W3C fomula.
Source: http://www.nbdtech.com/Blog/archive/2008/04/27/Calculating-the-Perceived-Brightness-of-a-Color.aspx

Flex demo for testing Perceived Brightness:

click on the colour picker to test the brightness of a colour:

Downloads

ColorUtils (721)
Tagged with:
 

5 Responses to How to calculate the Perceived Brightness of a colour

  1. How to calculate the Perceived Brightness of a colour http://t.co/hvJl4Mw

  2. This is a pretty nice comparison of methods of calculating Perceived Brightness of a color. http://t.co/nRVFlPCk

  3. michael says:

    Hello, Very nice examples. Where are you getting the ColorUtils library?
    Also the Weighted W3C algorithm seems to return 255 for RGB=255,255,255 any idea why this would be happening?

    Thanks in advance!

  4. […] Wie lässt sich am besten berechnen, ob schwarzer oder weißer Text besser bei einem farbigen Hintergrund lesbar ist? Auf zoltanb.co.uk wurden einige Algorithmen zur Berechnung der Farbhelligkeit auf diese Frage hin getestet: http://zoltanb.co.uk/how-to-calculate-the-perceived-brightness-of-a-colour/ […]

Leave a Reply