Kodi DSPlayer – DirectShow Player for Windows
Floating Point Math, Color Gamuts and Illegal RGB Values

What Is a Color Gamut?

When doing any type of color matrixing in image processing, we are generally working with floating point numbers. This is true when converting from Y'CbCr to R'G'B'.

Floating point numbers are numbers that contain decimal places that can move up or down (float) to accommodate a wide range of values. For RGB, floating point values for red, green and blue range between 0 and 1.0, where 0 = black and 1.0 = white. Decimal amounts such as 0.804329 are also possible. These decimal values can be converted to 0-255 or 0-1023 bit depths by rounding to the nearest decimal — 0.804239 floating point = 205 RGB (0.804239 x 255 = 205.080945). Whole numbers without decimals (0-255) are called integers, and this is how color information is presented. So a conversion from floating point (0.804) to integer (205) is required when presenting color information in standard bit depths. A 32-bit floating point number has six significant digits (e.g., 0.523456), where the significance starts after the first nonzero digit. Large floating point, decimal numbers offer a lot of precision in displaying colors to lower bit depths. This makes floating point numbers desirable for color space mapping.
Image

Having a floating decimal allows for the values to fluctuate above 1.0 and below 0. For example, conversion between YCbCr and RGB requires floating point numbers (preferably, 32-bit) because the YCbCr color gamut is slightly larger than the RGB color gamut. Not using floating point numbers would cause a loss of some values if the conversion between YCbCr and RGB was carried out more than once. Tone mapping focused on compressing luminance also creates the possibility pushing floating point values outside the defined color gamut.

Tone mapping can be summarized by two steps:
  • A TMO (tone mapping operator) selectively reduces the luminance (Y) of tone mapped pixels to fit the visible range of the display (either globally or locally);
  • Chrominance (CbCr) is compressed or color corrected to desaturate all colors as they lose luminance.

Note: Tone mapping in madVR is carried out by TMO BT.2390.

You should be left with a pixel that has less brightness with the same relative hue and saturation. However, reductions in luminance and changes in chromaticity will produce some floating point RGB values that are below 0 or above 1.0 (outside the 10-bit RGB limit of 64-940) because luminance and RGB color do not scale 1:1 linearly with gamut compression.

Tone mapping has two primary goals: Maintain local contrast relationships amongst neighboring values and retain the same perceptual color appearance of each pixel. This is achieved by altering the luminance of each pixel while maintaining its hue: The exact ratio of red, green and blue in each color. When hue is assumed constant, luminance is reduced by compressing all three RGB color channels uniformly.

In reality, this type of linear compression does not reflect how RGB color is described by color physics. In RGB color spaces, luminance is distributed independently across each of the red, green and blue color channels in different amounts. When you add up the luminance of each channel, you get the total pixel luminance.

RGB Image Separated into Its Three Color Channels:
Image


Tone compression maintains a constant hue while adjusting local contrast, so the ratio of luminance assigned to each RGB color channel is always fixed. However, RGB luminance does not have fixed ratios, as the ratio of red, green and blue luminance is actually continually fluctuating with increases or decreases in gamut volume in order to ensure equal differences continue to exist between adjacent color values. Compressing the RGB channels uniformly through luminance compression then causes some RGB channels to lose more luminance and saturation than others, as the weights between each color channel change as gamut volume is lost, and some pixels are pushed outside the compressed color gamut.   

RGB converts to YCbCr by applying a weighted average to each of the three RGB channels: red, green and blue, to create the pixel luminance, Y. The weights specified by each RGB color space are specific to that color space; Rec.2020 defines Y' as red (26%) + green (68%) + Blue (6%). Rec.709 defines Y' as red (21%) + green (72%) + Blue (7%). You can see that each RGB gamut defines a rigid relationship between the gamut primaries, so that red, green and blue are always mixed in specific quantities to create colors that fit within the defined color gamut.

The reason why these weights exists relates to what is known as the luminosity of color. Every color has its own natural luminance with respect to white, where red, green and blue are combined at 100% saturation. Green is more luminant than red or blue, and red has more luminance than blue. A 1,000 nits HDR mastering monitor has a peak white of 1,000 nits, but the brightest pure blue might only be 80 nits. The luminance of the primary and secondary colors are interrelated and ultimately limited in brightness by the brightest color they can reproduce when mixed at full saturation: peak white.

Tone mapping is removing luminance from pixels that are too bright for the display to reproduce while maintaining both local contrast and hue. This can be done in any color space, but it is most often carried out in a perceptual color space such as YCbCr or ICtCp. In these color spaces, the luminance or lightness of the pixel, Y, is independent of the chroma information, CbCr or CtCp, so you can remove luminance from the pixel and still maintain the same color while controlling the brightness difference between two values by changing its brightness.

So perceptual color spaces such as YCbCr and ICtCp are hue linear across luminance, which is what you want if red is to remain red, green is to remain green and blue is to remain blue after tone mapping is applied. Where perceptual color spaces go wrong is that they don’t account for the rigid relationship between each RGB color channel with respect to white.

If you had a yellow hue and manipulated the luminance channel, Y, the luminance slider assumes you have all the luminance you need for that specific hue all the way from black to peak white. An RGB color space, on the other hand, has only as much of that yellow hue as you have white, so it knows where the gamut boundaries are in relation to each red, green and blue color channel. The perceptual color space is only concerned with maintaining the same perceived brightness difference between two colors (its weighted local contrast relationship) and not the limits imposed by the rigid RGB gamut.

You could try to rectify this by tone mapping in RGB. However, if the ratio of red, green and blue is to be maintained (which defines the original hue), you still end up with a situation where removing luminance by compressing all three RGB color channels linearly leads to the display running out of saturation for certain hues that have been compressed by tone mapping.

Because RGB gamuts enforce fixed relationships for adjacent colors, collapsing an uneven 3D color gamut uniformly downwards through luminance compression causes larger losses in luminance for highly-saturated colors along the edges of the gamut than the colors located near white, as these saturated colors reach black faster than less saturated colors found closer to the white point. As a result, tone mapping focused on luminance compression can create many out-of-gamut pixels for displays that have too little luminance left to render certain highly-saturated colors found at the edges of the gamut with the saturation necessary to create the same local contrast called for by tone mapping. This is where gamut mapping becomes necessary.

sRGB Gamut in 3D Space:
Image

Most current tone mapping formulas are generic methods to preserve color perception (hue, saturation and local contrast) with changes in luminance without considering the complex 3D color volume of the destination color gamut. Gamut mapping deals with any out-of-gamut values created by tone mapping by making finer adjustments to the pixel luminance and chrominance after tone mapping is applied. Some local contrast is sacrificed in order to move each color value back into the gamut with as few compromises as necessary. This is done by prioritizing different perceptual aspects of each color — hue, saturation or luminance — to produce a consistent gamut mapping solution across all scenes.

Let's elaborate with some examples of illegal floating pointing color values after tone compression and conversion back to RGB.

The image below is taken from a high dynamic range camera and plotted on a standard CIE color diagram:

Image

The dots that fall within the gamut all have RGB values >= 0 and <= 1.0, if they fit into the gamut. But you'll notice some dots fall outside the gamut. Values in the top right have B (blue) < 0. Values in the bottom left have both R (red) < 0, and G (green) < 0. These are negative RGB values, which means the colors are too saturated for the defined gamut. A color such as this cannot be shown by the available colors of the display. 

Example of an Image with Negative RGB Values (Neon Sign):
Image


The issue of out-of-gamut colors is relevant to tone mapping in two ways:

The first issue is with pixels with Y values larger than the display range:
  • An input PQ Y value might be 0.2;
  • If the target curve = 400 nits, then the mastering display is 25 times brighter than the target display (10,000/400 = 25);
  • Y = 0.2 x 25 = 5;
  • A Y value of 5.0 is too large for the target display range of 0.0 to 1.0;
  • This pixel is out-of-gamut and will have to be tone mapped. 

The second issue is RGB values that do not fit into the gamut after tone mapping:
  • Even Y values clamped to 0.0 and 1.0 can produce out-of-gamut colors;
  • Unlike RGBYCbCr values (or any other perceptual color space such as ICtCp used by madVR) are not independent;
  • Arbitrarily choosing Y, Cb or Cr values can lead to one or more high negative or positive RGB channels (-0.0 to +1.0);
  • This is even the case after some desaturation of chrominance values;
  • This can apply to any tone mapped pixels (0 nits up to the content peak) depending on its unique position in the original gamut;
  • Pixels pushed out-of-gamut will have to be moved back in-gamut with gamut mapping.

A value such as (-0.5, 0.0, 0.0) is out-of-gamut. This notation means red information would have to be removed from any other color it is combined with. This color value must be mapped back into the gamut to be converted into a standard integer. The easiest way to do this is to make it (0.0, 0.0, 0.0). The problem is the pixel is more approximate to +0.5 than 0.0, so it would actually be more accurate to add some white to the color to desaturate it until it fits into the target gamut. The size of the negative number doesn't denote its position in the gamut, but is a measure of its brightness or intensity.

Color values greater than 1.0 are in the gamut but out-of-display range. A standard red would have a value of (1.0, 0.0, 0.0). A tone mapped red might end up with a value of (2.0, 0.0, 0.0), which would produce a very intense, glowing red. This red pixel has too much luminance and becomes (1.0, 0.0, 0.0). It is simply not possible to display a 1,000 nits red on a display calibrated for 1,000 nits white.

Similarly, a value such as (-0.5, 2.0, 0.0) means the pixel is both out-of-gamut and out-of-display range. This value implies the display has run out of highly-saturated reds at the required level of luminance. A pixel that is both too bright and too saturated is a common outcome of heavy luminance compression applied to specular highlights. It could also be clamped to 0 to 1.0, or some attempt could be made to retain the original appearance of the pixel by selectively adjusting the balance of luminance and desaturation. The most saturated colors are found at the edge of the color gamut and these tend to be the colors most often pushed outside the destination gamut.

Highly-Saturated Pixel Out-of-Gamut & Display Range:
Image

In summary, gamut mapping is used to deal with undisplayable colors by making additional adjustments to luminance and chrominance after tone mapping to produce legal RGB integers. Large luminance reductions will produce many out-of-gamut pixels due to the non-linear relationship between luminance and RGB color gamuts. The techniques to deal with this are varied, but will always result in some compromise in either hue, saturation or luminance that describe the original color appearance of each pixel.

The recommended approach to gamut mapping after tone mapping is to sacrifice some local contrast (either luminance or saturation) in order to maintain a constant hue for each color: Preserve the ratio of red, green and blue while independently adjusting luminance and/or chrominance. To accomplish this, the hue angle of every pixel is maintained relative to the white point and luminance (which can move the pixel downwards towards the gamut top edge) and/or chrominance (which can move the pixel inwards towards the white point) are reduced until the pixel fits within the target gamut. This treatment describes each color with three unique variables: hue, saturation and luminance, to consistently present a fixed hue while sacrificing one or more of the other variables.

A constant hue approach to gamut mapping is the recommendation of Dolby because changing the hue of any color will be more noticeable in most scenes than changing its saturation or luminance. This also follows the original theory of tone mapping in perceptual color spaces such as YCbCr or ICtCp that also treat all hues as constant with changes in luminance.

Displays that clip out-of-gamut color values or compress any of the RGB channels independently will create noticeable hue shifts for certain colors (e.g., red and orange can become yellow; blue can become purple, etc.). While this may improve the appearance of some scenes, it will create glaringly obvious color choices in others when certain memory colors are involved.

Examples of Hue Shifts Caused by Poor Gamut Mapping:

La La Land Correct Hue
La La Land Incorrect Hue

Life Untouched HDR Demo Correct Hue
Life Untouched HDR Demo Incorrect Hue

Colors that are both too bright and too saturated (too tall and too wide for the target gamut) require a compromise between preserving greater luminance or saturation, but never both at the same time, as the two share a direct relationship. Specular highlights that are pale and undersaturated tend to be undesirable for most viewers, so gamut mapping that preserves greater color saturation is typically valued more than luminance detail. Specular highlights that were originally mastered with a high color volume tend to look most impactful when luminance is lowered just enough for the display to render them with adequate saturation while still preserving the original hue.

White Paper Discussion on Tone Mapping and Gamut Mapping
Reply


Messages In This Thread
Lockup on STOP issue resolved! - by MKANET - 2015-04-11, 21:59
RE: 4G aware patch - by MagikMark - 2015-09-08, 03:27
Alt-F4 no longer quits - by JeffA - 2015-10-31, 20:38
H265 playback - by rew88 - 2017-11-04, 00:41
RE: H265 playback - by ashlar - 2017-11-04, 16:21
RE: H265 playback - by rew88 - 2017-11-05, 01:34
RE: H265 playback - by ashlar - 2017-11-05, 16:48
RE: H265 playback - by rew88 - 2017-11-05, 23:08
RE: H265 playback - by ashlar - 2017-11-06, 12:00
Leia 18 - by terpsarlington - 2017-11-21, 03:51
RE: Leia 18 - by spencerjford - 2017-11-21, 06:24
RE: Kodi DSPlayer – DirectShow Player for Windows - by Warner306 - 2018-05-07, 06:59
Display Modes / Refresh Rates - by goofer69 - 2019-09-20, 00:19
RE: Display Modes / Refresh Rates - by ashlar - 2019-09-20, 00:39
RE: Display Modes / Refresh Rates - by ashlar - 2019-09-20, 19:35
DSPlayer 23.810 to 23.976 - by Runakanta - 2018-05-09, 03:24
RE: DSPlayer 23.810 to 23.976 - by Warner306 - 2018-05-10, 01:32
Logout Mark Read Team Forum Stats Members Help
Kodi DSPlayer – DirectShow Player for Windows47