Re: [Gimp-developer] [Gimp-user] Time to fork BABL and GEGL

Since a few questions have popped up on IRC and it really is a weird
concept to grasp I thought I'd expand a bit on the color math that is
being discussed here. Sorry it is so long, I hope it is somewhat
entertaining though  :)

Simon Budig (simon budig de) wrote:
I think you are missing that "unbounded" also allows *negative* R, G or B
coordinates. That makes the colors imaginary in the sRGB color space,
but it still is possible to convert them to all other RGB color spaces.

Unbounded sRGB can express all the colors XYZ can express.
Transformations from userRGB to sRGB to userRGB are lossless.

The normal sighted human eye contains three types of cones which respond
differently to a given light spectra. In 1931 researchers have tried to
map the response of these cone types by having people stare at
projection screens and match colors. The results of these experiments
were combined and resulted in the definition of a "CIE standard
observer", with the most important aspect being functions describing the
"standard" response of the three cone types to light wavelengths:

The "Tristimulus values" X, Y, Z refer to the three cone types. They can
be determined by weighting the spectral power distribution with the
resp. response curve and then computing the integral over the wavelength
range from 380 to 780nm.

Related to XYZ is "xy", which simply is the color information normalized
to a given intensity: x = X/(X+Y+Z) and y=Y/(X+Y+Z).

The horseshoe-diagram you see frequently when colors are discussed
( ) lives in the
"xy" plane.

Note that these are absolute colors we're talking about here. For a
given spectral power distribution we end up with certain XYZ values.
This totally ignores other aspects of the human vision system. In
particular knowing the XYZ coordinate of a color does not help at all in
determining if something is perceived as "white". This is where the
"whitepoint" becomes relevant. For example if you look at a piece
of letter paper lighted by candle light you perceive it as white, since
your eye is trained to take the color of the environment light source
into account. Also experiences are relevant as well. You just assume
that this piece of paper is white, since this is what you are used to
and then your vision system takes this as a reference point.

If you'd see the same XYZ color in a daylight context, you'd probably be
surprised how reddish yellow it actually is. Taking a photo of a
candlelight scene with a digital camera set to a "daylight" whitepoint
will give you an idea. No, the yellow color is not the camera lying to
you, it is the eye not being allowed to lie to you.

Another important aspect of the XYZ system is, that it contains
"imaginary colors": Color coordinates where it is impossible to create
light spectra for. If you look at the color matching functions
referenced above you see why: they do have huge overlaps, most
wavelengths trigger two or even all three of the cone types
simultaneously. Looked at it from the math point of view that
means for example that "if Y is nonzero, then X or Z will be nonzero as

The XYZ coordinate (0, 1, 0) is an imaginary color. It is impossible to
construct a real world light spectrum that results in this XYZ
coordinate. Pure light with about 520nm wavelengh might get you close,
but you still have X and Z components > 0. The rounded boundary in the
horseshoe diagram represents the pure wavelengths and the weird shape is
determined by the overlaps in the color matching functions.

XYZ is very useful in that it is a good tool to describe absolute colors
and it is a superset of all the color impressions the "CIE standard
observer" can perceive. It is the "safe bet" of color spaces.

However, since "pure X", "pure Y" and "pure Z" are basically a physical
impossibility they cannot be used to build real world computer monitors.
It has turned out that variants of Red/Green/Blue are a useful
compromise to compose color impressions. The Phosphors used in CRTs and
the filters used in LCDs have a specific spectral distribution and can
be varied in their intensity, resulting in an absolute XYZ coordinate.
In the real world we have a maximum brightness for each of the
components and reducing the intensity moves the XYZ coordinate on a
straight line towards (0,0,0), i.e. black.

Since the integral math behaves additively the three independent
components construct a skewed cube in the XYZ color space. This is the
"gamut": the range of color impressions that can be shown with this
particular monitor. If you now normalize the intensities of the
coordinates within this skewed cube you end up with a triangle in the
xy-space, which is useful to describe the range of colors available to
you with a given set of base colors:

The corners of the triangle are the xy-coordinates of the
phosphors/filters used. These are the "primaries" or "chromaticities" of
the given RGB space. (Note that ProPhotoRGB uses primaries which are
imaginary colors. There never will be a computer monitor using
ProPhotoRGB primaries.)

The triangle shape is no random accident: It is the convex hull of the
three primaries: the points within are a weighted sum of the three
corners, where the sum of the weights = 1.

Since physics does not allow for "subtracting" color spectra from each
other we cannot escape from this triangle to display more colors. This
is where the sRGB color space has severe problems representing color
impressions with intense and pure colors which are perfectly within the
realm of the real world. Using sRGB primaries to additively construct
your color will impose harsh limits on you.

...that is if you are concerned about the real world implementation in a
computer monitor.

When we talk about "unbounded" sRGB in the Gegl/Babl context we do away
with this restrictions: We allow absurdly high intensities way beyond
the physical capabilities of a specific light source. And we allow for
negative intensities.

Yes, negative intensities are 100% absurd and wrong when you think about
them in terms of implementing computer monitors.

However, we don't need to model a real computer monitor. We are not
bound to the laws of physics when dealing with pixels in memory.

Allowing negative coefficients for the RGB values makes it possible to
escape the dreaded gamut triangle. In fact this makes the unbounded sRGB
color space as expressive as AdobeRGB, ProPhotoRGB and XYZ.

To reiterate: Every XYZ coordinate can be represented in the terms of
sRGB primaries.

For example:

The Green Primary of the AdobeRGB 1998 colorspace is - specified with
its own primaries - at the coordinates (0, 1, 0) (which is somewhat

Using e.g. the slightly convoluted color calculator at we can convert this to
 XYZ = ( 0.185554, 0.627349, 0.070687 ).

(Note that there is a normalization involved here: AdobeRGB (1, 1, 1) is
converted to an XYZ value scaled to Y = 1.0. We also get the xy
coordinate of the green point here: xy = (0.21, 0.71) )

This in turn translated into unbounded linear sRGB yields:

   sRGB = (-0.398283, 1.0, -0.042939)

And thats it. The color represented by (0,1,0) in AdobeRGB is equivalent
to the color represented by (-0.40, 1.0, -0.04) in unbounded linear sRGB
("bablRGB"). Yes, there are negative coefficients, no, we don't need to
worry about them.

And we can use the same math in reverse to reconstruct the AdobeRGB
value to use it as userRGB for our multiplication operation. We end up
at RGB=(0,1,0) where we started.

Note that there is nothing special about the sRGB that makes this
possible. The same math would work with any other primaries, as long as
they don't form a line in the xy diagram (i.e. they need to be linearily
independant in XYZ).

However, for this to work we absolutely must not clamp negative values
to zero. As soon as we do that huge errors will be introduced.

Gegl/Babl don't - at least not for the float types. We're sane there.

If anybody wants to dive deeper into that topic: Browse Bruce Lindblooms
site. It has tons of valuable ressources, gives you formulae for various
conversions and gives a lot of great insights.

I hope this helps,
              simon budig de    

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]