Blogs by Filip Hroch

Inside of sRGB gamut

Inside is a brief description of self-correction procedures for accurate colour reproductions including the gamut checking.

The crucial objective of displaying of FITS on sRGB displays is to transform intensity into the display range, while colours are preserved. The transformation, represented by intensity scaling, is necessary because the high dynamic range of FITS frames encounters intensity limits of current hardware. The process modifies colours, and occasionally places them outside of sRGB gamut.

Colour-spaces of displays

Modern displays operates in sRGB, or Adobe RGB, colour-spaces (commonly RGB spaces), which are standardised, and accepted by manufacturers for the best reproduction of coloured pictures. Technical characteristics of the spaces has begin in classical monitors, or TV tubes, utilising excitation of the screen luminophore bombarded by electrons. Notwithstanding based on distinct physical mechanisms, their technical characteristics are also emulated by a current hardware.

On the other side, the native colour-space describing of human vision is CIE 1931 XYZ. The space is a formal approximation of a spectral sensitivity of tristimulus receptors X, Y, Z of eye’s cone cells. XYZ has origin in roots of Nature, rather than made by mankind.

A faithful display of colours requires exact conversion between RGB luminance and perception in XYZ. The mutual mapping is complex, and highly non-linear. Only a part of XYZ space is displayable, and not all possible combinations of the intensity and colours can be represented in a given colour space. A domain of all available colours is known as gamut (sRGB gamut).

Intensity scaling in XYZ

A direct intensity scaling in RGB space does not work at all, as one can easy check.

Opposite to RGB, the linear intensity scaling in XYZ works as expected (the black level B, and the sensitivity s are parameters).

C’ = (C − B) ⁄ s,  for C = X, Y, Z

The transformation does not change a colour shade, if any saturation limit is not reached. Actually, one is equivalent to varying of the exposure time. [1]

However, the derived xyY colour-space CIE 1931 XYZ colour space (sec. CIE xy chromaticity diagram and the CIE xyY color space) offers more advantageous properties. Only Y component, representing luminosity, is scaled, and than X, Z are re-computed leaving colour shades unchanged.

Y’ = (Y − B) ⁄ s
x’, y’ = const.

xyY space is used by Fitspng and Munipack for intensity pre-scaling, because the operation is cheap (fast), and can be combined with the simulation of Nite vision. Values are normalised into interval 0 ≤ X’, Y’, Z’ ≤ 1.

Scaling in Luv

Scaling in xyY (or XYZ) works only for linear functions. If a non-linear function is used, the colour shade is modified.

Fortunately, the difficulty can be well maintained in CIE 1976 L*u*v* colour space [2], which is designed to preserve distances of colours. An disadvantage of the space is a non-linearity, an irregular shape of gamut, and input values should be normalised, by XYZ or xyY, already.

Luv has three coordinates. Luminance 0 ≤ L ≤ 100 is a (relative) perception of the source intensity (zero is for a black object, one hundred for white colour). Cartesian coordinates of colours are  − 200 ≤ u, v ≤ 200.

u, v can be converted to cylindrical coordinates for convenience. Hue, a shade of a colour, is an angle in cylindrical coordinates.

The radial distance of given colour from the white-point is chroma c:

c = ((u − uw)2 + (v − vw)2).

The term colour saturation is connected on chroma. For a constant luminance, small values of c means low saturated colours (near white), high values are bold colours.

The key property of Luv is that the relative chroma, defined as

c ⁄ L = const.

is conserved during non-linear scaling of luminance L, or the ratio c ⁄ L remain unchanged for any transformation of L.

The conservation of relative chroma can be easy demonstrated. A picture below is a snapshot of a landscape cloud scenery with Boží muka (wayside shrine) in South Moravia region.

The first illustration shows the scenery when the colour saturation has been uncorrected (L is modified, chroma c is unchanged). The non-linear scaling function was S/N like.

Boží muka, saturation uncorrected

A landscape picture, colour saturation uncorrected.

The second picture shows full colours, like colours of Nature seen by author. The conservation of relative chroma, following the same non-linear transformation, increases the dramaticity of the scene.

Boží muka, corrected saturation

The landscape, colour saturation correction applied

The approach works very well. Unfortunately, some points, specially for saturated pixels, can lie outside of sRGB gamut causing appearance of strangle colours.

The first-aid to remove the faulty colours offers bracketing of their coordinates into some interval, say c < 282, 0 ≤ L ≤ 100. It is efficient for saturated, or noisy, pixels, and gives visually acceptable results in many situations.

Another approach can be replacing the faulty colours by white, or black, in generally. It is efficient in cases when the both luminosity and chroma are out of the intervals.

However, careful evaluation of the gamut boundary can improve the first-aid approach.

Inside of sRGB gamut

sRGB gamut in Luv has a really complex shape. The gamut can not be described by a simple geometric object, so I made a grid of boundary values, the cover, of the gamut in both luminance and hue. Luminance is sliced onto one hundred of layers, hue is one point per degree. The cover values are compared to current value, and if one is outside, the grid chroma is used.

The validity check assumes that coordinates of both luminance and hue are correct, but c is incorrect. This is a very unsure approach, the coordinates are mutually dependent in principle. All the values are uncertain, but I assume luminance and hue as trustworthy, as an average of three channels. Similar, chroma c is the geometric mean, so c can be used rather than single coordinates u, v. The approach can be improved by some filtering technique, for example, adding information from neighbourhood pixels.

To illustrate importance of gamut range checking, I selected an image taken inside an orange cylinder of caterpillar model, a playground toy for children. The toxic orange is the true colour for experiments with the saturation. One is so close of gamut edge, so values are quickly moved outside, if luminosity is changed.

A scenery as view inside a caterpillar

A preview of a view from inside of a caterpillar

To show the algorithms in action, the sensitivity parameter has been set on maximum. The asymptotic colour for completely saturated pixels is white. It is exactly what users expected for over-exposed frames, by my opinion.

A scenery as view inside a caterpillar

Sensitivity enhanced.

The final illustration shows the same frame with all corrections switched off. The toxic yellow, and the yellow-toned grass, moves spectators to another, pretty artificial, world. The saturation correction is important, the gamut checking plays only supporting role. Supplementary tuning of parameters does not leads to vanish of the artificial colours.

A scenery as view inside a caterpillar

Sensitivity enhanced, no correction applied.

The gamut correction procedure is usually applied on minority of pixels. Experiments show that it is more frequent while correcting of toxic colours, like the caterpillar, and for noisy images. The noise is common for (astronomical) exposures in darkness, when it helps to suppress unexpected random colours.

Really saturated pixels, when detector lost some information from a channel, are untouched by this approach. It should be done by more detailed analysis of the original data. dcraw offers -H, -C switches which sometimes helps.

An algorithm

This algorithm summarise current implementation of colour processing in both Fitspng (fitspng.c: colour_picture()), and Munipack (fitsdisplay.cpp: FitsDisplay::GetColour()).

The input values are CIE 1931 XYZ, the output is in sRGB space of the display.

  1. Establish desired parameters of conversion
  2. Convert XYZ to xyY, scale Y’ = (Y − B) ⁄ s, ensure Y’ > 0, and convert back to XYZ.
  3. Convert XYZ to Luv, compute chrome c and hue.
  4. Save relative saturation s = c ⁄ L.
  5. Scale L’ = Itt(L) by choice function.
  6. Update chrome c’ = sL.
  7. Modify saturation by user choice S.
  8. Check if c is inside gamut, clip it to outer boundary.
  9. Compute modified u’, v
  10. Convert modified L’, u’, v to XYZ and finally to sRGB

It is important to separate linear pre-scaling and non-linear scaling on two steps. The pre-scaling normalises non-limited intensities of XYZ to unit interval. The non-linear scaling is computed in the Luv space with the relative saturation conservation in mind, and with luminosity limited to interval from zero to one hundred.

Conclusions

The proper scaling of intensity of colour pictures should be done in CIE 1931 XYZ, or xyY, and Luv spaces.

The scaling should be separated on two steps: the linear scaling in XYZ, or xyY, and the non-linear in Luv. Colours scaled by a non-linear function should have its saturation updated.

Scaled values should be checked, and corrected if they lies outside of the appropriate gamut. It reduces the saturation induced by irregularities and the colour noise.


Footnotes

[1]Another remarkable application is shrinking of pictures by averaging, when the arithmetic mean becomes a value of a new single pixel. I bring to mind, median is not a linear operation, it can make a noise to be worse.
[2]Colours can be corrected in a space with uniform colour distances as both CIE L*a*b* and CIE L*u*v* are. I prefers Luv because it is computationally advantageous (one cubic square only).