Project

An Accurate Programatic Perceptual Contrast Assessment for Website Color Schemes.

  • Private Profile

Goal: The current W3CWCAG standard for determining contrast between web colors is considered flawed by many designers. It uses a simple contrast ratio of luminance, and while it has a mild offset to clamp contrast ratio to a reasonable level, does not adequately model human perception (with or without visual impairments) and further does not adequately take into account ambient light and light adaptation (both general and local).

As such it lacks utility when used to determine colors for a website design. Presently investigating various programatic contrast assessment methods that take perception and numerous other factors into account.

Date: 20 March 2019

Updates
0 new
6
Recommendations
0 new
0
Followers
0 new
1
Reads
1 new
193

Project log

Private Profile
added an update
LUMINANCE CONTRAST and PERCEPTION
There are many factors that determine legibility of graphics displayed on a computer monitor. Among them is luminance contrast. L:uminance contrast is substantially more important than color contrast as a substantial portion of hte population has difficulty distinguishing colors. It is estimated that 6% of males have "color blindness" and rely on luminance contrast and not color contrast.
DETERMINING LUMINANCE
Luminance is a spectrally weighted but otherwise linear measure of light. The spectral weighting is based on how human trichromatic vision perceives different wavelengths of light. This was part of the measurements in the CIE 1931 experiments and resultant colorspaces such as CIEXYZ (Luminance is the Y in XYZ).
While XYZ is a linear model of light, human perceptions is very much non-linear. As such, XYZ is not perceptually uniform. Nevertheless, for your purposes you just want to know what the equivalent luminance is for a color vs a grey patch.
Assuming you are starting with sRGB video (i.e. the web and computer standard colorspace) you first need to remove the gamma encoding, and then apply the spectral weighting.
I've made a lot of posts here on Stack regarding gamma, but if you want a definitive explaination I recommend Poynton's Gamma FAQ https://poynton.ca/GammaFAQ.html
DEFINITIONS:
sRGB: sRGB is a tristimulus color model which is the standard for the Web, and used on most computer monitors. It uses the same primaries and white point as Rec709, the standard for HDTV. sRGB differs from Rec709 only in the transfer curve, often referred to as gamma.
Gamma: This is a curve used with various methods of image coding for storage and transmission. It is often similar to the perception curve of human vision. In digital, gamma's effect is to give more weight to the darker areas of an image such that they are defined by more bits in order to avoid artifacts such as "banding".
Luminance: (notated L or Y): a linear measure or representation of light (i.e. NO gamma curve). As a measure it is usually cd/m2. As a representation, it's Y as in CIEXYZ, and commonly 0 (black) to 100 (white). Luminance features spectral weighting, based on human perception of different wavelengths of light. However, luminance is linear in terms of lightness/darkness - that is if 100 photons of light measures 10, then 20 would be 200 photons of light.
L* (aka Lstar): Perceptual Lightness, as defined by CIELAB (L*a*b*) Where luminance is linear in terms of the quantity of light, L* is based on perception, and so is nonlinear in terms of light quantities, with a curve intended to match the human eye's photopic vision (approx. gamma is ^0.43).
Luminance vs L*: 0 and 100 are the same in both luminance (written Y or L) and Lightness (written L*), but in the middle they are very different. What we identify as middle grey is in the very middle of L* at 50, but that relates to 18.4 in Luminance (Y). In sRGB that's #777777 or 46.7%.
Contrast: The term for defining a difference between two L or two Y values. There are multiple methods and standards for contrast. One common method is Weber contrast, which is ΔL/L. Contrast is usually stated as a ratio (3:1) or a percentage (70%).
DERIVING LUMINANCE (Y) FROM sRGB
STEP ZERO (un - HEX)
If needed, convert a HEX color value to a triplet of integer values where #00 = 0 and #FF = 255.
STEP ONE (8 bit to decimal)
Convert 8 bit sRGB values to decimal by dividing by 255:
decimal = R´8bit / 255       G´decimal = G´8bit / 255       B´decimal = B´8bit / 255
If your sRGB values are 16 bit then convert to decimal by dividing by 65535.
STEP TWO (Linearize, Simple Version)
Raise each color channel to the power of 2.2, the same as an sRGB display. This is fine for most applications. But if you need to make multiple ound trips into and out of sRGB gamma encoded space, then use the more accurate versions below.
2.2 = Rlin    G´2.2 = Glin    B´2.2 = Blin
ALTERNATE STEP TWO (Linearize, Accurate Version)
Use this version instead of the simple ^2.2 version above if you are doing image manipulations and multiple round trips in and out of gamma encoded space. ( There does not seem to be a way to format code here on researchgate!!)
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 Math.pow((( colorChannel + 0.055)/1.055),2.4));
}
}
STEP THREE (Spectrally Weighted Luminance)
The normal human eye has three types of cones that are sensitive to red, green, and blue light. But our spectral sensitivity is not uniform, as we are most sensitive to green (555 nm), and blue is a distant last place. Luminance is spectrally weighted to reflect this using the following coefficients:
Rlin * 0.2126 + Glin * 0.7152 + Blin * 0.0722 = Y = L
Multiply each linearized color channel by their coefficient and sum them all together to find L, Luminance.
STEP FOUR (Contrast Determination)
There are many different means to determine contrast, and various standards as well. Some equations work better than others depending on the specific application.
WCAG The current web page standard listed in the WCAG 2.0 and 2.1 is simple contrast:
C = ((Llighter + 0.05) / (Ldarker + 0.05)) : 1
This gives a ratio, and the standards of the WCAG specify 3:1 for non-text, and 4.5:1 for text.
However, it is a weak example for a variety of reasons. I'm on record as pointing out the flaws in a current GitHub issue (695) and have been researching alternatives.
Modified WeberW The Hwang Peli modified eber ( ) provides a better assessment of contrast as it applies to computer monitors / sRGB.
C = (Llighter – Ldarker) / (Llighter + 0.1)
Note that I chose the flare factor of 0.1 instead of 0.05 based on some recent experiments. That value is TBD though, and a different value might be better.
LAB Difference Another alternative that I happen to like more than others is converting the linearized luminance (L) to L* which is Perceptual Lightness, then just subtracting one from the other to find the difference.
Convert Y to L*: ( does not seem to be a way to format code here on researchgate!!)
function YtoLstar(Y) {
// Send this function a luminance value between 0.0 and 1.0,
// and it returns L* - 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 Math.pow(Y,(1/3)) * 116 - 16;
}
}
Once you've converted L to L*, then a useful contrast figure is simply:
C = L*lighter – L*darker
The results here may need to be scaled to be similar to other methods. A scaling of about 1.6 or 1.7 seems to work well.
There are a number of other methods for determining contrast, but these are the most common. Some applications though will do better with other contrast methods. Some others are Michaelson Contrast, Perceptual Contrast Length (PCL), and Bowman/Sapolinski.
ALSO, if you are looking for color differences beyond the luminance or lightness differences, then CIELAB has some useful methods in this regard.
SIDE NOTES:
Averaging RGB No Bueno!
Often mentioned is a commonly cited equation for making a greyscale of a color from RGB as:
GRAY = round((R + G + B) / 3);
It is simple, it is elegant and... it is completely wrong.
The spectral weighting of R, G, and B is substantial and cannot be overlooked. GREEN is a higher luminance than BLUE by an ORDER OF MAGNITUDE. You cannot just sum all three channels together and divide by three and get anything close to the actual luminance of a particular color.
I believe the confusion over this may have come from a color control known as HSI (Hue, Saturation, Intensity). But this control is not (and never intended to be) perceptually uniform!!! HSI, like HSV, are just "conveniences" for manipulating color values in a computer. Neither are perceptually uniform, and the math they use is strictly for supporting an "easy" way to adjust color values in software.
 
Private Profile
added an update
The present status: after a series of experiments in perceptual contrast, focusing on luminance contrast, it became clear that "contrast" cannot be isolated from font size, font weight and the effect of "padding" in a web design element (such as a DIV) that contains the text (this is related to the Bartleson and Breneman effect).
As a result this study is going to fork out to:
  1. The original luminance contrast and perceptual uniformity in contrast assessment study.
  2. A new study, now underway, to develop a programatic means to assess font size, font weight, and font contrast characteristics as they pertain to legibility and color choiuce requirements to fit luminance contrast specifications.
  3. A further new study to determine a rational basis and standards for CSS DIV (web element) "padding" to support perceptual contrast for graphically rich content displayed on computer monitors.
At the present time, the Luminance contrast study has spawned a number of potential algorithms which are undergoing testing.
 
Private Profile
added a research item
Updated link: https://www.myndex.com/WEB/Perception The above link connects to our directory of web vision experiments.
Private Profile
added an update
A listing of work in progress live experimental pages on this link:
Page purpose: demonstrate the flaws in the W3C WCAG math for determining contrast of web colors. Discussion thread at GitHub:
 
Private Profile
added a project goal
The current W3CWCAG standard for determining contrast between web colors is considered flawed by many designers. It uses a simple contrast ratio of luminance, and while it has a mild offset to clamp contrast ratio to a reasonable level, does not adequately model human perception (with or without visual impairments) and further does not adequately take into account ambient light and light adaptation (both general and local).
As such it lacks utility when used to determine colors for a website design. Presently investigating various programatic contrast assessment methods that take perception and numerous other factors into account.