How to calculate the Perceived Brightness of a colour
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:
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:
![]()
Geometric Mean:
Formula:

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:
![]()
Quadratic Mean:
Formula:

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: 
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 0×99
Darkest Component:
Formula: 

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: 

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:

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:
Weighted W3C Formula:
Formula: 
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:

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 (280)4 Responses to How to calculate the Perceived Brightness of a colour
LaunchpadCleaner
Tags
3D Printing air apparat apple as3 colours cpd datagram FDT flash flash builder flex FlexCPD FlexMetrics FlexPMD flex skinning FlexUnit git grails groovy hudson jenkins joomla Launchpad linux mac maven Maya netfabb os x lion parsley performance pmd replicatorg reprap scala scien scientific linux sky sonar sts subclipse svn udp ultimaker






Land Beyond Productions

How to calculate the Perceived Brightness of a colour http://t.co/hvJl4Mw
This is a pretty nice comparison of methods of calculating Perceived Brightness of a color. http://t.co/nRVFlPCk
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!
Hi Michael,
You can download ColorUtils.as from here:
ColorUtils.as
Try the Weighted W3C algorithm in that file, let me know if it return the wrong value(255) for RGB=255,255,255.
Cheers,
Zoltan