Colour SpacesIn what follows are various notes dealing with colour spaces and conversion between them.
RGB colour spaceLists of RGB values for named colours
Written by Paul Bourke This table is the "standard" set as used by the SGI X windows server. The values are in the range of 0 to 255 inclusive. Contribution by Robert Rapplean, C++ program that creates an image that can be folded together to form the RGB colour cube. A colour space is a means of uniquely specifying a colour. There are a number of colour spaces in common usage depending on the particular industry and/or application involved. For example as humans we normally determine colour by parameters such as brightness, hue, and colourfulness. On computers it is more common to describe colour by three components, normally red, green, and blue. These are related to the excitation of red, green, and blue phosphors on a computer monitor. Another similar system geared more towards the printing industry uses cyan, magenta, and yellow to specify colour, they are related to the reflectance and absorbency of inks on paper. Some other major colour spaces are:
There are generally ways of converting (transforming) between different colour spaces although in most cases the transformation is non-linear. Some colour spaces for example can represent colours which cannot be represented in others. RGB colour cubeThe colour space for computer based applications is often visualised by a unit cube. Each colour (red, green, blue) is assigned to one of the three orthogonal coordinate axes in 3D space. An example of such a cube is shown below along with some key colours and their coordinates.
The first set below was originally compiled by Steve Hollasch and is organised as follows: the first column is the descriptive name of the colour; the next three columns are the RGB coordinates in the 0 to 255 range as if the components were being stored in one unsigned byte; the last three columns are the RGB colour coordinates in the range of 0 to 1 inclusive.
References An inexpensive scheme for calibration of a colour monitor in terms of CIE standard coordinates. W.B. Cowan, Computer Graphics, Vol. 17 No. 3, 1983 Calibration of a computer controlled colour monitor. Brainard, D.H,Color Research & Application, 14, 1, pp 23-34 (1989). Color Monitor Colorimetry. SMPTE Recommended Practice RP 145-1987 Color Temperature for Color Television Studio Monitors. SMPTE Recommended Practice RP 37 Color Science in Television and Display Systems. Sproson, W, N, Adam Hilger Ltd, 1983. ISBN 0-85274-413-7 CIE Colorimetry. Official recommendations of the International Commission on Illumination, Publication 15.2 1986 CRT Colorimetry: Part 1 Theory and Practice, Part 2 Metrology. Berns, R.S., Motta, R.J. and Gorzynski, M.E., Color Research and Application, 18, (1993) Effective Color Displays. Theory and Practice. Travis, D, Academic Press, 1991. ISBN 0-12-697690-2 Color and Its Reproduction. Field, G.G., Graphics Arts Technical, Foundation, 1988, pp. 320-9 Gamma and its disguises: The non-linear mappings of intensity in perception, CRT's, Film and Video. C. A. Poynton, SMPTE Journal, December 1993 Measuring Color (second edition). R. W. G. Hunt, Ellis Horwood 1991, ISBN 0-13-567686-x On the Gun Independence and Phosphor Consistency of Color Video Monitors. W.B. Cowan N. Rowell, Color Research and Application, V.11 Supplement 1986 Precision requirements for digital Color reproduction. M Stokes MD Fairchild RS Berns, ACM Transactions on graphics, v11 n4 1992 The colorimetry of self luminous displays - a bibliography. CIE Publication n.87, Central Bureau of the CIE, Vienna 1990 The Reproduction of Color in Photography, Printing and Television. R. W. G. Hunt, Fountain Press, Tolworth, England, 1987 Fully Utilizing Photo CD Images, Article No. 4, PhotoYCC Color Encoding and Compression Schemes. Eastman Kodak Company, Rochester NY (USA) (1993). Digital halftoning. Robert Ulichney, MIT Press, 1987, ISBN 0-262-21009-6
WWW Browser coloursWritten by Paul BourkeSeptember 1996 Achieving consistent colour representation within WWW documents between browsers (NetScape, MSIE) and hardware platforms (Macintosh, Windows, UNIX) requires some knowledge of how browsers allocate colours when running in 8 bit mode (256 colours). If 16, 24 or higher colour modes are being used then exact colour representation is achieved without dithering and the following doesn't apply. Colour in HTML is represented by 3 hexadecimal (hex) pairs, representing the red, green, blue components of the final colour. Each RGB component is stored as 1 byte (unsigned) ranging numerically from 0 to 255, in hex this is "00" to "ff". The colour model is the familiar colour cube used in computer graphics. ![]()
Any colour can be requested by a WWW page but the browser will not necessarily use that colour precisely due to hardware limitations. Even if the hardware is capable of 24 bit colour, the actual RGB components are often rounded to multiples of 4, fortunately this is not discernible by humans even if it could be resolved by the monitor. In index colour system such as the most common 256 colour system, the actual colours that can be displayed are quantised into much coarser steps. The operating system generally needs some colours for its own use such as drawing window boundaries, menus, etc. Browsers on Macintosh and MSWindows systems use 216 of the available 256 colours, the remaining 40 are left available for the operating system to allocate as necessary. If colours are used that are not in the palette of 256 colours the browser will either convert the colour to one that is closest in the palette or it will give the best representation of the requested colour by dithering a number of the available colours. If these colours are being used for backgrounds and/or text it can often mean the difference between a readable and unreadable page.
The set of colours which, if used, will look the same on all 256 palette systems is simply a 6x6x6 (216) partitioning of the colour cube. The discrete steps in each RGB component are
or in hex
or as percentages
This doesn't include any grey scale levels (where r = g = b) but fortunately the 40 system wide colours usually include a good range of grey values.
The above table was generated by slicing along the red axis of the colour cube, that is, each table above is a sampled plane parallel to the green-blue plane. Slices could be generated along the other two axes as well. Laid out as a PhotoShop table, the 256 colour palette for the Macintosh is shown on the left and the 216 palette for MS based machines is shown on the right.
All three slices can be viewed below
Note: The above refers to what colours should be used when creating simple colour diagrams, for example, backgrounds, logos, etc. For photographic or other images with more than 256 colours it is better to use an adaptive colour table when creating the gif rather than dithering to the browser palette. C code to create colour table.
Converting between RGB and CMY, YIQ, YUVCompiled by Paul BourkeFebruary 1994 RGB to/from CMY
Converting from RGB to CMY is simply the following
The reverse mapping is similarly obvious
The two system may also be known as additive for RGB and subtractive for CMY. RGB to/from YIQ
The YIQ system is the colour primary system adopted by NTSC for colour television broadcasting. The YIQ Color solid is formed by a linear transformation of the RGB cube. Its purpose is to exploit certain characteristics of the human visual system to maximize the use of a fixed bandwidth. The transform matrix is as follows
Note: First line Y = (0.299, 0.587, 0.144) (R,G,B) also gives pure B&W translation for RGB. The inverse transformation matrix that converts YIQ to RGB is
RGB to/from YUV
YUV is like YIQ, except that it is the PAL/European standard. Transformation matrix is
The reverse transform is
Frequency to RGBCompiled by Paul BourkeFebruary 1994
Reference:
Rogers, David F., "Procedural Elements for Computer Graphics," The best way of finding the RGB values of a given wavelength is to use the CIE chromaticity diagram. The spectral locus is on the edge of the wing-shaped curve. You just need to transform the xy coordinate from CIEXYZ space into RGB space. Below I have spectral locus coordinates from 380nm to 780m in steps of 5 nm. It's written as a C array. We'll refer to any particular wavelength's coordinates as xc and yc. To transform into RGB, we need the xy coordinates of the RGB primaries and the alignment white. I'll use a set of typical values.
x y
Red 0.628 0.346 call these xr and yr
Green 0.268 0.588 " " xg and yg
Blue 0.150 0.070 " " xb and yb
White 0.313 0.329 " " xw and yw
From these we can compute the linear transformation from CIEXYZ to RGB.It is:
[R] = [ 2.739 -1.145 -0.424 ] [X]
[G] = [ -1.119 2.029 0.033 ] [Y]
[B] = [ 0.138 -0.333 1.105 ] [Z]
However, if the xy coordinate of the spectral Color isn't inside the triangle formed by the RGB xy coordinates given above (and none of them are), then we must first find a closest match that is inside the triangle. Otherwise our RGB values will go outside the range [0,1], i.e. some values will be less than zero or greater than one. One common way of moving the colour inside the triangle is to make the colour whiter (i.e. desaturate it). Mathematically we do this by intersecting the line joining the colour and the alignment white with the edges of the triangle. First define the line that goes through white and your colour implicitly:
Lc: [-(yw - yc)] * P + [-(yw - yc)] * [xc]
[ xw - wc ] [ xw - xc ] [yc]
For every pair of red, green, and blue, define an explicit (parametric line). For example, the line between the red and green primaries is:
Lrg: P = [xr] + t * [xg - xr]
[yr] [yg - yr]
Substitute Lrg for P into Lc and solve for the parameter t. If 0 <= t <= 1, then you've got the answer and you don't need to try the other lines. Otherwise, substitute Lgb, and if necessary Lbr. If t is not in the range [0,1] then the intersection occurred outside the triangle. Once you have t, plug it into the original equation for Lrg (or whatever line gave a good solution) and you get the xy coordinate. Plug this into the linear transformation above (using z = 1 - x - y) to get the RGB values. At least one of R, G, or B should be exactly one (ie fully saturated in the RGB colour space). Since this is an involved procedure, I would suggest precomputing RGB's for all the wavelengths you'll need (or enough to interpolate) once for each display device you'll be using. If you know the chromaticity coordinates of your displays primaries and its white you can compute the linear transformation easily.
/* CIE 1931 chromaticity coordinates of spectral stimuli (only xy, z = 1 - x - y) */
float spectrum_xy[][2] = {
{0.1741, 0.0050}, {0.1740, 0.0050}, {0.1738, 0.0049},
{0.1736, 0.0049}, {0.1733, 0.0048}, {0.1730, 0.0048},
{0.1726, 0.0048}, {0.1721, 0.0048}, {0.1714, 0.0051},
{0.1703, 0.0058}, {0.1689, 0.0069}, {0.1669, 0.0086},
{0.1644, 0.0109}, {0.1611, 0.0138}, {0.1566, 0.0177},
{0.1510, 0.0227}, {0.1440, 0.0297}, {0.1355, 0.0399},
{0.1241, 0.0578}, {0.1096, 0.0868}, {0.0913, 0.1327},
{0.0687, 0.2007}, {0.0454, 0.2950}, {0.0235, 0.4127},
{0.0082, 0.5384}, {0.0039, 0.6548}, {0.0139, 0.7502},
{0.0389, 0.8120}, {0.0743, 0.8338}, {0.1142, 0.8262},
{0.1547, 0.8059}, {0.1929, 0.7816}, {0.2296, 0.7543},
{0.2658, 0.7243}, {0.3016, 0.6923}, {0.3373, 0.6589},
{0.3731, 0.6245}, {0.4087, 0.5896}, {0.4441, 0.5547},
{0.4788, 0.5202}, {0.5125, 0.4866}, {0.5448, 0.4544},
{0.5752, 0.4242}, {0.6029, 0.3965}, {0.6270, 0.3725},
{0.6482, 0.3514}, {0.6658, 0.3340}, {0.6801, 0.3197},
{0.6915, 0.3083}, {0.7006, 0.2993}, {0.7079, 0.2920},
{0.7140, 0.2859}, {0.7190, 0.2809}, {0.7230, 0.2770},
{0.7260, 0.2740}, {0.7283, 0.2717}, {0.7300, 0.2700},
{0.7311, 0.2689}, {0.7320, 0.2680}, {0.7327, 0.2673},
{0.7334, 0.2666}, {0.7340, 0.2660}, {0.7344, 0.2656},
{0.7346, 0.2654}, {0.7347, 0.2653}, {0.7347, 0.2653},
{0.7347, 0.2653}, {0.7347, 0.2653}, {0.7347, 0.2653},
{0.7347, 0.2653}, {0.7347, 0.2653}, {0.7347, 0.2653},
{0.7347, 0.2653}, {0.7347, 0.2653}, {0.7347, 0.2653},
{0.7347, 0.2653}, {0.7347, 0.2653}, {0.7347, 0.2653},
{0.7347, 0.2653}, {0.7347, 0.2653}, {0.7347, 0.2653}};
YCC colour space and image compressionWritten by Paul BourkeApril 2000
There are an infinite number of possible colour spaces instead of the common RGB (Red, Green, Blue) system most commonly used in computer graphics. Many of these other colour spaces are derived by applying linear functions of r, g, b. So for example, a colour space based upon 3 coordinates v1, v2, and v3 can be written as: v1 = Ar1 R + Ag1 G + Ab1 B v2 = Ar2 R + Ag2 G + Ab2 B v3 = Ar3 R + Ag3 G + Ab3 B Where the Ar, Ag, Ab are constants for a particular colour space. Similarly for any such system there are linear functions to go back to RGB space. The coefficients Dr, Dg, Dc can be derived by solving the above equations for r,g,b. For example: R = Dr1 v1 + Dg1 v2 + Db1 v3 G = Dr2 v1 + Dg2 v2 + Db2 v3 B = Dr3 v1 + Dg3 v2 + Db3 v3 The human visual system has much less dynamic range (acuity) for spatial variation in colour than for brightness (luminance), in other words, we are acutely aware of changes in the brightness of details than of small changes in hue. So rather than saving as RGB it can be more efficient to encode luminance in one channel and colour information (that has had the luminance contribution removed) in two other channels. The two colour channels can be encoded with less bandwidth by using a number of techniques, predominantly by reducing the precision, or as will be discussed here, reducing the spatial resolution. Since green dominates the luminance channel it makes sense to base the other two chrominance channels on luminance subtracted red and blue. Such luminance, red chrominance and blue chrominance systems are generally referred to as Y, Cr, and Cb. In what follows they will generally be referred this way or simply as YCC. Example: Kodak PhotoCD YCC
The Kodak PhotoYCC colour space was designed for encoding images with the PhotoCD system. It is based on both CCIR Recommendations 709 and 601-1, having a colour gamut defined by the CCIR 709 primaries and a luminance - chrominance representation of colour like CCIR 601-1's YCbCr. To convert from RGB to PhotoCD YCC, the following matrix operation is used (after appropriate gamma correction has been applied). Notice the major contribution to the Cr value is red and the main contribution to the Cb value is blue. The unbalanced scale difference between Chroma1 and Chroma2 is designed, according to Kodak, to follow the typical distribution of colours in real scenes. Y = 0.299 R + 0.587 G + 0.114 B Cr = 0.701 R - 0.587 G - 0.114 B Cb = -0.299 R - 0.587 G + 0.886 B The rationale behind these coefficients can be found by considering that the luminance subtracted blue (B-Y) signal reaches its extreme values at blue (R=0, G=0, B=1, Y=0.114, B-Y=0.886) and at yellow (R=1, G=1, B=0, Y=0.886, B-Y=-0.886). Similarly, the extrema of the luminance subtracted red (R-Y), +-0.701, occur at red and cyan. In a similar way there is a matrix for creating RGB colour values from any colour space created as discussed above. Note that in many cases and this applies to YCC colour spaces, it is possible to represent colours that cannot be represented in RGB space. For the Kodak system the reverse mapping from YCC into RGB is:
Given the human visual systems "preference" for luminance information, one can design an image compression system around YCC colour space. Consider an RGB image with Nx horizontal pixels and Ny vertical pixels. If each pixel is represented as one byte the the image size in bytes is Nx Ny 3. Consider storing the image in YCC space where the luminance channel Y is stored as one byte for each pixel but the two chrominance channels are only stored for each block of say 4x4 pixels. The resulting image would be Nx Ny + 2 (Nx/4 + Ny/4), this is an image 2 and 2/3rds smaller. Put another way, instead of using on average 3 bytes (24 bits) per pixel we would only be using 9 bits per pixel. ![]()
Note the chrominance is averaged over each 4x4 block. There is nothing particularly special about a 4x4 block instead of a 3x3 or 5x5 or other sizes. A 2x2 by two results in a factor 2 saving, a 3x3 grid results in a saving of 2.45. Larger grids give ever decreasing rates of return and soon impact on the image quality. The YCC colour space used follows that used by TIFF and JPEG (Rec 601-1)Y = 0.2989 R + 0.5866 G + 0.1145 B Cb = -0.1687 R - 0.3312 G + 0.5000 B Cr = 0.5000 R - 0.4183 G - 0.0816 B RGB values are normally on the scale of 0 to 1, or since they are stored as unsigned single bytes, 0 to 255. The resulting luminance value is also on the scale of 0 to 255, the chrominance values need 127.5 added to them so they can saved in an unsigned byte. Of course when the YCC values are turned back into RGB, then 127.5 must be first subtracted from the two chrominance values. The reverse transform is R = Y + 1.4022 Cr G = Y - 0.3456 Cb - 0.7145 Cr B = Y + 1.7710 Cb The full chrominance range of +-0.5 maps into a larger colour space than supported by RGB. The above equations can yield RGB values outside the 0 to 255 (or 0 to 1) range, these typically relate to very light or dark colours. The RGB values should be clipped so they lie within the allowed range after the transform from YCC to RGB is calculated. An image compressed this way is obviously degraded but could one tell the difference? Below are two images, the one on the left uses 24 bits per pixel and the one on the right uses 9 bits per pixel as described above.
The compression scheme above is most noticeable when there are rapid changes in hue but little change in luminance, in this case the 4x4 subsampling of the Cr and Cb channels is most noticeable. For images of real world scenes this happens surprisingly rarely, in the before and after example above it is virtually impossible to zoom in and find examples of the 4x4 subsampling. Similarly one would not generally use this sort of compression for low colour images, in that case other compression techniques are available. Appendix: Other standard colour space conversions
PAL television standard
NTSC television standard
References Color Monitor Colorimetry. SMPTE Recommended Practice RP 145-1987 CIE Colorimetry. Official recommendations of the International Commission on Illumination, Publication 15.2 1986 Effective Color Displays. Theory and Practice. D. Travis, Academic Press, 1991. ISBN 0-12-697690-2 Measuring Colour (Second edition). R.W.G. Hunt, Ellis Horwood 1991, ISBN 0-13-567686-x Precision requirements for digital colour reproduction. M. Stokes, M.D. Fairchild, R.S. Berns, ACM Transactions on graphics, v11 n4 1992 The Reproduction of Colour in Photography, Printing and Television. R.W.G. Hunt, Fountain Press, Tolworth, England, 1987
Colour Ramping for Data VisualisationWritten by Paul BourkeJuly 1996 Contribution: Ramp.cs by Russell Plume in DotNet C#. This note introduces the most commonly used colour ramps for mapping colours onto a range of scalar values as is often required in data visualisation. The colour space will be based upon the RGB system. Grey Scale
The most basic mapping of some scalar value to a colour ramp is to use either an intensity ramp from black to a single colour or use the grey scale ramp from black to white. Black normally being the low end of the range of values, and white the high end. On the colour cube this is a diagonal line between the two opposite corners, the red, green, blue components are all the same. ![]()
The map from black to white is usually just a linear ramp, for a
value (v) which varies from vmin to vmax, the colour is ![]()
The most commonly used colour ramp is often refer to as the "hot- to-cold" colour ramp. Blue is chosen for the low values, green for middle values, and red for the high as these seem "intuitive" bounds. One could ramp between these points on the colour cube but this involves moving diagonally across the faces of the cube. Instead we add the colours cyan and yellow so that the colour ramp only moves along the edges of the colour cube from blue to red. This not only makes the mapping easier and faster but introduces more colour variation. The following illustrates the path on the colour cube. ![]() The colour ramp is shown below along with the transition values. ![]() Again there is a linear relationship of the scalar value with colour within each of the 4 colour bands. In some applications the variable being represented with the colour map is circular in nature in which case a cyclic colour map is desirable. The above can be simply modified to pass through magenta to yield one of many possible circular colour maps. ![]()
A more general case ramps between N colours, each colour has a corresponding value within the range of values of the variable being mapped. The points within the colour cube can be linearly ramped between the points or the transition can be smoothed by some interpolation function such a bezier curve. For example a 3 colour ramp for terrain visualisation might choose 3 heights and three corresponding colours. ![]() Displayed as a colour ramp
![]() The resulting terrain map
![]() C Source for the "standard" hot-to-cold colour ramp.
Note about gamma
Please note that the above are not corrected for the gamma of the display device. As such the colours may indeed appear different on different displays. The gamma of displays can be adjusted and typically have a power relationship, that is, if (r,g,b) is the colour being displayed, it will appear as (rG,gG,bG). In order to achieve a display colour or (r,g,b) the inverse of the gamma function needs to be created, namely (r1/G,g1/G,b1/G). Note also that the gamma value G is not necessarily the same for each (r,g,b) component.
Simple method of storing colour rampsAdapted from OGLE (By Dr. Michael J. Gourlay)
Written By Paul Bourke Many applications in computer graphics use colour and/or opacity ramps, in particular, visualisation using volume rendering. In this and other cases one often just requires colour and opacity index tables for 256 states. The following is a straightforward approach to storing such index colour maps, it has been adopted from the OGLE volume rendering software, at least this means there is one other piece of software that uses the format rather than dreaming up an entirely new format. Example (ramp1.dat)
This is the standard blue to green to red colour map. The columns are the index value followed by the red, green, blue values ranging from 0 (no contribution) to 255 (full contribution).
Opacity maps are stored in the same way even though the RGB colour information is usually redundant (r == g == b). Having the opacity map separate from the colour map allows one to use them interchangeably, if the RGB values of a map used as an opacity map are not equal then the application can choose how to derive the single opacity value (eg: use the red channel, use the magnitude of the colour....). Collection of colour ramps and associated data file
HSV colour ramp/selectorWritten by Paul BourkeJuly 2005 A useful colour picker interface is often based upon the HSV colour system, sometimes the HSL. The layout of the colour table is often as follows although there is some variation in the functions used for saturation and value. All the colours in RGB space lie on the surface of the colour cube. ![]() Example As a web based paint selection interface, note the extra bar for grey scale selection.
![]()
Index ColourMacintosh palette -- PhotoShop colour tables
Written by Paul Bourke Index colour systems are still prevalent in many graphical computer systems. An index colour system is one in which colour is specified by an integer normally from 0 up to the number of colours in the colour table. Each entry in the colour table gives the red, green, blue components for that particular index. In such colour systems the colour table is sometimes fixed. In these cases you can only use the preset colours. When a particular colour is required which isn't in the table the closest may be used or a number of colours that are in the table may be dithered in order to approximate the desired colour. A more common situation is when the colour table is of a fixed size but the actual RGB values at each position in the table can be changed. Therefore, if you require a wide range of a particular hue you can load up the colour table accordingly. It also leads to situations where one might want to optimise the colour table to best represent a particular image. For example if an image only contains 100 different colours then irrespective of what these colours are, a colour table containing these colours will allow the image to be represented exactly. A much more common situation is when the colour table isn't large enough to hold all the different colours desired, in these cases one might engage in a process called "colour table optimisation" where one attempts to load the colour table with colours so that the image can be best represented. In yet other systems the colour table can be made as large as desired. One often then wants to create a colour table for a particular task. The remained of this document will describe the most unbiased method of creating a colour table in cases where you don't know what colours will be required and thus want an equal sampling of the RGB colour space ![]()
There are two processes involved. The first is creating the entries in the colour table, the second is given an RGB value determining the index of its closest representation in the table. In what follows, an RGB triple will be floating point numbers in the inclusive range [0,1]. If your colour space uses different ranges then simple scaling converts one range to the [0,1] range used here. To create a n sampling along each r,g,b axis will result in n3 colour values. Converting from (r,g,b) triples into the colour index is Some examples of colour tables are illustrated below. The index ranges from 0 top left, increasing left to right - top to bottom. The index in the bottom right cell is n3-1. 3x3x3 sampling![]()
4x4x4 sampling ![]()
5x5x5 sampling ![]()
6x6x6 sampling ![]()
Finding the index of the colour closest to a particular (r,g,b) triple is accomplished as follows where nint(x) is the nearest integer to x. Note
The table
The following is the C code that created the above colour table.
Source code PhotoShop Index Colour Table Files Performing colour remapping with indexed colour images in PhotoShop is particularly straightforward mainly because the colour table files are so easy to generate. The colour table files (which can be loaded into PhotoShop) consist of 256 RGB colour entries, each RGB colour component is stored as 1 byte. Each colour component ranges from 0 to 255. As such they are straightforward to generate mathematically with a programming language.
What is Gamma Correction?orWhy do some pictures appear dark on some displaysWritten by Paul BourkeOriginal: February 1994. Updated Jan 1998. The phosphors on the face of the monitor tube luminesce (or some other computer projection device) when struck by the beam generated by the electron gun sweeping out the scanlines. By increasing the intensity of the beam, the phosphor dot luminesces more brightly, and by reducing the intensity of the beam, the phosphor glows less brightly. The output of the phosphor is not directly proportional to electron beam strength. The response of the phosphors usually looks something like this: ![]()
where the dotted line shows ideal linear response, and the solid line approximates the observed response of a normal phosphor. This response characteristic is due to physical phenomena and can be described via a function of the form Typically monitors have a gamma from anything between 1.5 and 2.8 Subjectively, this causes the colors on the screen to appear darker than expected. Based on this behaviour, an inverse gamma correction function can be applied to compensate for this non-linear response: ![]()
Here, the solid line again represents the uncorrected phosphor response, the large dotted line is the inverse gamma function, and the fine dotted line is the resultant, linearized color response. Determining the gamma valueMost computer systems now days have standard interfaces/utilities for determining and setting the gamma value. For example the Macintosh has a control panel with the OS, SGI machines come with a utility called "gamma" which both reports and sets the gamma value. The following chart can be used to determine the combined gamma value for your system. ![]() Setting the gamma value To adjust the gamma value "roughly", set the contrast and brightness of your monitor to your preferred/comfortable level and use whatever gamma software comes with your hardware. In the absence of other information it is usual to set the effective gamma to 2.2, this is the standard employed for PhotoCD's. On SGI machines this normally means setting a "gamma" value of around 1.2, this is because SGI's are normally configured with a natural gamma of 2.6, the combined gamma value is 2.6 divided by this number. All well written image viewers should provide options for controlling the gamma or they should get the value from the system being used. For example on UNIX machine, the xv viewer can be called with the option -gamma 2.2. Unfortunately at the time of writing none of the two main WEB browsers support gamma correction for images in WWW pages, as a result the images tend to look dark on uncorrected monitors. This is a major problem when it comes to distributing images on a wide variety of systems. Fortunately the PNG format does support the specification of a colourmetric model and will go a long way to providing consistent image appearance across monitor hardware.
Converts to/from sRGB and LAB spacePresented as JavaScript, originally for Quartz ComposerWritten by Paul Bourke November 2018
The following present functions to convert to and from sRGB and LAB colour, in both cases going through XYZ as an intermediate stage. While presented as JavaScript, it does still uniquely define the transformations and should be easy to transcribe into other languages. Note the XYZ mappings require a reference illuminate white point, for example D65. sRGB to XYZ
function (__structure xyzcolour) main(__number rgbcolour[4])
{
var result = new Object();
result.xyzcolour = new Array();
var R = new Object();
var g = new Object();
var B = new Object();
if (rgbcolour[0] > 0.04045 )
R = Math.pow( ( (rgbcolour[0] + 0.055 ) / 1.055 ),2.4);
else
R = rgbcolour[0] / 12.92;
if (rgbcolour[1] > 0.04045 )
G = Math.pow( ( (rgbcolour[1] + 0.055 ) / 1.055 ),2.4);
else
G = rgbcolour[1] / 12.92;
if (rgbcolour[2] > 0.04045 )
B = Math.pow( ( (rgbcolour[2] + 0.055 ) / 1.055 ),2.4);
else
B = rgbcolour[2] / 12.92;
R = R * 100;
G = G * 100;
B = B * 100;
result.xyzcolour[0] = R * 0.4124 + G * 0.3576 + B * 0.1805;
result.xyzcolour[1] = R * 0.2126 + G * 0.7152 + B * 0.0722;
result.xyzcolour[2] = R * 0.0193 + G * 0.1192 + B * 0.9505;
result.xyzcolour[3] = rgbcolour[3];
return result;
}
XYZ to LAB
function (__structure labcolour) main(__number xyzcolour[4],__number xyzref[3])
{
var result = new Object();
result.labcolour = new Array();
var X = new Object();
var Y = new Object();
var Z = new Object();
X = xyzcolour[0] / xyzref[0];
Y = xyzcolour[1] / xyzref[1];
Z = xyzcolour[2] / xyzref[2];
if ( X > 0.008856 )
X = Math.pow( X , 1/3.0 );
else
X = ( 903.3 * X + 16.0 ) / 116.0;
if ( Y > 0.008856 )
Y = Math.pow( Y, 1/3.0 );
else
Y = ( 903.3 * Y + 16.0) / 116.0;
if ( Z > 0.008856 )
Z = Math.pow( Z, 1/3.0 );
else
Z = ( 903.3 * Z + 16.0) / 116.0;
result.labcolour[0] = ( 116 * Y ) - 16;
result.labcolour[1] = 500 * ( X - Y );
result.labcolour[2] = 200 * ( Y - Z );
result.labcolour[3] = xyzcolour[3];
return result;
}
LAB to XYZ
function (__structure xyzcolour) main(__number labcolour[4],__number xyzref[3])
{
var result = new Object();
result.xyzcolour = new Array();
var X = new Object();
var Y = new Object();
var Z = new Object();
Y = (labcolour[0] + 16.0) / 116.0;
X = labcolour[1] / 500.0 + Y;
Z = Y - labcolour[2] / 200.0;
Y = Adjust(Y);
X = Adjust(X);
Z = Adjust(Z);
result.xyzcolour[0] = X * xyzref[0];
result.xyzcolour[1] = Y * xyzref[1];
result.xyzcolour[2] = Z * xyzref[2];
result.xyzcolour[3] = labcolour[3];
return result;
}
function Adjust(a) {
if (Math.pow(a,3.0) > 0.008856)
return(Math.pow(a,3.0));
else
return((a - 16.0/116.0) / 7.787);
}
XYZ to sRGB
function (__structure rgbcolour) main(__number xyzcolour[4])
{
var result = new Object();
result.rgbcolour = new Array();
var R = new Object();
var G = new Object();
var B = new Object();
var X = new Object();
var Y = new Object();
var Z = new Object();
X = xyzcolour[0] / 100.0;
Y = xyzcolour[1] / 100.0;
Z = xyzcolour[2] / 100.0;
R = X * 3.2406 + Y * (-1.5372) + Z * (-0.4986);
G = X * (-0.9689) + Y * 1.8758 + Z * 0.0415;
B = X * 0.0557 + Y * (-0.2040) + Z * 1.0570;
R = Adjust(R);
G = Adjust(G);
B = Adjust(B);
R = Clip(R);
G = Clip(G);
B = Clip(B);
result.rgbcolour[0] = R * 255.0;
result.rgbcolour[1] = G * 255.0;
result.rgbcolour[2] = B * 255.0;
result.rgbcolour[3] = xyzcolour[3];
return result;
}
function Adjust(a) {
if (a > 0.0031308)
return(1.055*Math.pow(a,1.0/2.4)-0.055);
else
return(12.92*a);
}
function Clip(a) {
if (a > 1)
return(1);
else if (a < 0)
return(0);
else
return(a);
}
|