I\'m looking for some kind of formula or algorithm to determine the brightness of a color given the RGB values. I know it can\'t be as simple as adding the RGB values toget
The 'V' of HSV is probably what you're looking for. MATLAB has an rgb2hsv function and the previously cited wikipedia article is full of pseudocode. If an RGB2HSV conversion is not feasible, a less accurate model would be the grayscale version of the image.
Please define brightness. If you're looking for how close to white the color is you can use Euclidean Distance from (255, 255, 255)
For clarity, the formulas that use a square root need to be
sqrt(coefficient * (colour_value^2))
not
sqrt((coefficient * colour_value))^2
The proof of this lies in the conversion of a R=G=B triad to greyscale R. That will only be true if you square the colour value, not the colour value times coefficient. See Nine Shades of Greyscale
To add what all the others said:
All these equations work kinda well in practice, but if you need to be very precise you have to first convert the color to linear color space (apply inverse image-gamma), do the weight average of the primary colors and - if you want to display the color - take the luminance back into the monitor gamma.
The luminance difference between ingnoring gamma and doing proper gamma is up to 20% in the dark grays.
Rather than getting lost amongst the random selection of formulae mentioned here, I suggest you go for the formula recommended by W3C standards.
Here's a straightforward but exact PHP implementation of the WCAG 2.0 SC 1.4.3 relative luminance and contrast ratio formulae. It produces values that are appropriate for evaluating the ratios required for WCAG compliance, as on this page, and as such is suitable and appropriate for any web app. This is trivial to port to other languages.
/**
* Calculate relative luminance in sRGB colour space for use in WCAG 2.0 compliance
* @link http://www.w3.org/TR/WCAG20/#relativeluminancedef
* @param string $col A 3 or 6-digit hex colour string
* @return float
* @author Marcus Bointon <marcus@synchromedia.co.uk>
*/
function relativeluminance($col) {
//Remove any leading #
$col = trim($col, '#');
//Convert 3-digit to 6-digit
if (strlen($col) == 3) {
$col = $col[0] . $col[0] . $col[1] . $col[1] . $col[2] . $col[2];
}
//Convert hex to 0-1 scale
$components = array(
'r' => hexdec(substr($col, 0, 2)) / 255,
'g' => hexdec(substr($col, 2, 2)) / 255,
'b' => hexdec(substr($col, 4, 2)) / 255
);
//Correct for sRGB
foreach($components as $c => $v) {
if ($v <= 0.04045) {
$components[$c] = $v / 12.92;
} else {
$components[$c] = pow((($v + 0.055) / 1.055), 2.4);
}
}
//Calculate relative luminance using ITU-R BT. 709 coefficients
return ($components['r'] * 0.2126) + ($components['g'] * 0.7152) + ($components['b'] * 0.0722);
}
/**
* Calculate contrast ratio acording to WCAG 2.0 formula
* Will return a value between 1 (no contrast) and 21 (max contrast)
* @link http://www.w3.org/TR/WCAG20/#contrast-ratiodef
* @param string $c1 A 3 or 6-digit hex colour string
* @param string $c2 A 3 or 6-digit hex colour string
* @return float
* @author Marcus Bointon <marcus@synchromedia.co.uk>
*/
function contrastratio($c1, $c2) {
$y1 = relativeluminance($c1);
$y2 = relativeluminance($c2);
//Arrange so $y1 is lightest
if ($y1 < $y2) {
$y3 = $y1;
$y1 = $y2;
$y2 = $y3;
}
return ($y1 + 0.05) / ($y2 + 0.05);
}
The only answers that are accurate are the @jive-dadson and @EddingtonsMonkey answers, and in support @nils-pipenbrinck. The other answers (including the accepted) are linking to or citing sources that are either wrong, irrelevant, obsolete, or broken.
Because this thread appears highly in search engines, I am adding this answer to clarify the various misconceptions on the subject.
Brightness is a perceptual attribute, it does not have a direct measure.
Perceived lightness is measured by some vision models such as CIELAB, here L* (Lstar) is a measure of perceptual lightness, and is non-linear to approximate the human vision non-linear response curve.
Luminance is a linear measure of light, spectrally weighted for normal vision but not adjusted for non-linear perception of lightness.
Luma (Y´ prime) is a gamma encoded, weighted signal used in some video encodings. It is not to be confused with linear luminance.
Gamma or transfer curve (TRC) is a curve that is often similar to the perceptual curve, and is commonly applied to image data for storage or broadcast to reduce perceived noise and/or improve data utilization (and related reasons).
To determine perceived lightness, first convert gamma encoded R´G´B´ image values to linear luminance (L
or Y
) and then to non-linear perceived lightness (L*
)
...Because apparently it was lost somewhere...
Convert all sRGB 8 bit integer values to decimal 0.0-1.0
vR = sR / 255;
vG = sG / 255;
vB = sB / 255;
Convert a gamma encoded RGB to a linear value. sRGB (computer standard) for instance requires a power curve of approximately V^2.2, though the "accurate" transform is:
Where V´ is the gamma-encoded R, G, or B channel of sRGB.
Pseudocode:
function sRGBtoLin(colorChannel) {
// Send this function a decimal sRGB gamma encoded color value
// between 0.0 and 1.0, and it returns a linearized value.
if ( colorChannel <= 0.04045 ) {
return colorChannel / 12.92;
} else {
return pow((( colorChannel + 0.055)/1.055),2.4));
}
}
To find Luminance (Y) apply the standard coefficients for sRGB:
Pseudocode using above functions:
Y = (0.2126 * sRGBtoLin(vR) + 0.7152 * sRGBtoLin(vG) + 0.0722 * sRGBtoLin(vB))
Take luminance Y from above, and transform to L*
Pseudocode:
function YtoLstar(Y) {
// Send this function a luminance value between 0.0 and 1.0,
// and it returns L* which is "perceptual lightness"
if ( Y <= (216/24389) { // The CIE standard states 0.008856 but 216/24389 is the intent for 0.008856451679036
return Y * (24389/27); // The CIE standard states 903.3, but 24389/27 is the intent, making 903.296296296296296
} else {
return pow(Y,(1/3)) * 116 - 16;
}
}
L* is a value from 0 (black) to 100 (white) where 50 is the perceptual "middle grey". L* = 50 is the equivalent of Y = 18.4, or in other words an 18% grey card, representing the middle of a photographic exposure (Ansel Adams zone V).
IEC 61966-2-1:1999 Standard
Wikipedia sRGB
Wikipedia CIELAB
Wikipedia CIEXYZ
Charles Poynton's Gamma FAQ