Understanding HSVL - Tutorial - Guillermo Algora - Visual Effects Compositor

Guillermo Algora
Go to content
1. HUE:

Hue is an attribute to classify colours based on their dominant wavelength and with independence of intensity (saturation) or lightness (luminance). Hues are usually represented in a 360° color wheel (as in Nuke) or in a spectrum bar.
There are 12 main hues in a color wheel, each of them every 30°:
red, orange, yellow, chartreuse green, green, spring green, cyan, azure, blue, violet, magenta and rose. .
The Hue value represents the angle on the color wheel. In Nuke, we can find the Hue from the sampled area displayed at the bottom right-hand corner of the 'Viewer Panel'. Given that Hue is independent of Saturation and Brightness, this characteristic can be very useful when it comes to matching the tone of two different elements while leaving their other attributes unchanged:

We will convert our element to the HSL
colorspace. This colorspace maps the Hue, Saturation and Luminance of the image into the red, green and blue channels respectively. We can now modify the Hue (i.e. rotate around the colour wheel) by increasing or reducing the value in the red channel until we have a match to the Hue value of the other element. And, if desired, we could also adjust the Saturation and Luminance by tweaking the green and blue channels. For the task, we can employ a Grade Node, I recommend to use the 'Offset' operation as it is purely adding / subtracting value.
Now, let's take a look at how the Hue value is calculated:

  • Identify the maximum (max) and minimum (min) of red, green and blue values.

  • If the values of the three channels are the same or max = 0:
    Hue is zero (the color posses 0 saturation). However, keep in mind that also pure red is represented with a Hue value of 0.

  • If red = max:
    Hue = 60 * ((green - blue) / (max - min))

  • If green = max:
    Hue = 60 * (2.0 + (blue - red) / (max - min))

  • If blue = max:
  Hue = 60 * (4.0 + (red - green) / (max - min))

As we have seen, Hue can serve as a powerful tool to identify whether the tone of two elements match without having to consider other factors.

Saturation is independent of Hue or Luminance and is an indicator of the intensity of a colour. Highly saturated colours appear "stronger" and by increasing Saturation we are "revealing" more of the Hue present in the color, for example, being "more red", "more blue", etc. This is because, while zero Saturation (i.e. grey) indicates that all the three channels have the same value (R=G=B) and low Saturation implies that the three channels are closely aligned, high Saturation signifies a strong disparity in the values of the three channels. Increasing Saturation pulls the values in the channels further apart, thus increasing the dominant Hue, while reducing Saturation pulls the values from the channels closer together.

Let's see how the Saturation value (as displayed in the Nuke 'Viewer Panel') is calculated:

  • Identify the maximum (max) and minimum (min) between the red, green and blue values.
  • Saturation = (max - min) / max.

As for the Saturation Node, it works as follows:

First, Nuke fully desaturates the image using the chosen luminance formula, as selected in the 'math dropdown' menu within the node.
There are four methods:

This luminance method is also the one utilised for the calculation of the 'Luminance' parameter in the 'Viewer Panel'.
  • Luminance = R * 0.2126 + G * 0.7152 + B * 0.0722

Ccir 601:
  • Luminance = R * 0.299 + G * 0.587 + B * 0.114

  • Luminance = (R + G + B) / 3

This luminance method is the one used for the calculation of the 'Value' parameter in the 'Viewer Panel'.
  • Luminance = max(R, G, B)

Once that process is completed, it proceeds to do a linear interpolation (lerp) between the fully desaturated (a) and the original value (b), using the Node's Saturation value (t) as the interpolation factor (i.e. mix value):

Output = lerp(a, b, t)

When t  is 0, the function returns the a value: full desaturation, i.e. whole conversion to the chosen luminance method.
When t  is 1, it returns the b value: original value.
Otherwise, it returns a value at the t  point in between the two (according to the saturation value).

In simpler terms, desaturation within Nuke's Saturation Node entails converting the image to luminance (with different luminance mathematical options) and blending it with the original image, where the blending value is determined by the Saturation parameter.

When t  exceeds 1 (indicating an increase in Saturation), the lerp function extends the linear trend beyond the range of the two input values, producing values that follow the same linear progression established between the input values, which can sometimes result in values transitioning from positive to negative. There may be slight deviations to the linear trend due to rounding errors or accuracy limitations in the calculations.

Value in Nuke's 'Viewer Panel' is the most straightforward, representing the highest value from the three colour channels: R, G or B.
It is also commonly known as Brightness. When employed as a matte, the outcome is similar to a Luminance Keyer but without the bias of the rec.709 coefficients. Consequently, it can generate a more balanced "brightness" key based on value rather than luminance perception. Luminance is geared towards human visual perception, while Value or Brightness reflect more the actual intensity of an image in terms of its values. Nonetheless, neither is better or worse, they just serve different purposes. Use them as you see fit.

To use Value, one approach might be to convert to the HSV colorspace using a Colorspace Node (which stores it in the blue channel). However, I have experienced that this approach produces a slightly lifted brightness "map". For an accurate representation of Value as presented in the 'Viewer Panel,' it is best to use the Keyer Node in 'max' operation or an Expression Node with the following expression: max(r, g, b).

L in the Nuke's 'Viewer Panel' stands for Luminance, computed with the rec.709 coefficients (a weighted sum of red, green and blue):

L = R * 0.2126 + G * 0.7152 +  B * 0.0722

Luminance with these coefficients aims to match human visual perception. These were derived from extensive psycho-physical experiments that sought to quantify the relative importance of different color channels in determining luminance perception.

  • Red light, being towards the longer wavelength end of the visible spectrum, has a significant impact on our perception of brightness. The value 0.2126 aims to accurately represent the luminance contribution of red hues in a way that aligns with human visual sensitivity.

  • Green light is at the peak of human visual sensitivity. Our eyes are most responsive to green wavelengths, making them crucial for perceiving fine details and overall image brightness. The coefficient 0.7152 reflects this heightened sensitivity and was chosen to emphasize the importance of the green channel in determining image luminance accurately.

  • Blue light, while less impactful on overall brightness perception compared to red and green, is essential for achieving accurate color balance and reproducing subtle variations in hue and saturation, especially in shadow and highlight areas. The coefficient 0.0722 represents the relatively lower contribution of blue light to overall luminance, reflecting its role in maintaining color fidelity while minimizing its influence on perceived brightness.

rec.709 came after Ccir 601 (also known as rec.601), which was widely used in analog and early digital video systems. While the Ccir 601 coefficients were considered suitable for their time, they are not as optimised for modern high-definition video systems. Thus, rec.709 was later developed and aimed to improve color reproduction and fidelity for high-definition television (HDTV) systems. The "rec" prefix stands for "recommendation", set by the International Telecommunication Union (ITU), while the number signifies the specific recommendation number assigned to this standard.
5. 'Alternate colorspace values for the sample' menu:

The dropdown menu, positioned at the bottom right corner of the 'Viewer Panel', offers additional parameters to be displayed for the values of the sampled area (crtl+ click or crtl + shift + drag), which are by default represented in HSLV. It offers the following options:

Colorspace values measured in f-stops at 1/48th of a second shutter speed (e.g. f/5.9 @48th sec).

Nuke maps 18% grey to the center f-stop setting, which is set to 8 by default. In other words, by default a value of 0.18 across the three channels is displayed as f-stop 8, with the f-stop then adjusting higher or lower upon on the sampled values.

This mode, however, can be changed from f-stops to exposure stops. To do so, access the 'Viewer' Properties Panel (by hovering the mouse over the 'Viewer' and pressing 'S') and then change the center f-stop setting to 0. In this configuration, Nuke will provide us with EV (Exposure Values). An EV=0 corresponds to 18% grey, and again from there up or down upon the values (+ / - n). For example, a value of 0.25 across the three channels signifies a +0.5 exposure stop relative to 0.18 (EV=0). To align 0.25 with 0.18, we would decrease the exposure by 0.5 stops. Being able to neutralise our element to the 18% grey can be useful in different contexts, as it serves as a standard, practical and consistent reference point for lighting, color balance and exposure calculations.

RGB colorspace values (e.g. 25, 25, 25, 255).

8-bit color refers to a color depth in computing that uses 8 bits per pixel to represent a color. This means that each pixel can be one of 256 colors (28 = 256). The concept of 28 comes from binary mathematics. When you have 8 binary digits (or bits) available, each bit can represent two states (0 or 1). Therefore, the total number of possible combinations of these 8 bits is calculated by raising 2 to the power of 8.

8-bit Hex:
The same colorspace values as 8-bit, but displayed in hexadecimal (e.g. 1A 1A 1A FF).

In hexadecimal notation, each digit can represent 16 possible values (0-9 and A-F, where A represents 10, B represents 11, and so on up to F representing 15). Since each hexadecimal digit can represent 16 different values (0-15), with two hexadecimal digits you can represent 16*16 = 256 different values. This matches the range of values needed to represent each color component in an 8-bit color system (0 to 255). The hexadecimal value 00 represents the minimum intensity (0) for a color component, while FF represents the maximum intensity (255) for a color component. So, in 8-bit hex, color values are represented using two hexadecimal digits for each color component (two for red, two for green, and two for blue), resulting in a total of six hexadecimal digits to represent a color in the RGB colorspace. For instance, the color white would be represented as #FFFFFF in 8-bit hex notation.

Logarithmic colorspace values (e.g. 397, 397, 397).

The official documentation in regards to this is scarce, however, it seems to roughly match  a conversion to the Cineon Logarithmic colorspace presented in an integer form, with some particular implementation.

The default setting, shows colorspace values as Hue, Saturation, Value and Luminance, the later being also referred as 'Level' in the Nuke Documentation (e.g. 318, 0.46, 1, 0.65586).
6. HSVL Tool as a Keyer:

The HSVL Tool, apart from being a Hue replacement node, can indeed serve as a very interesting and powerful keyer. The prowess of this node as a keyer relies on the fact that it works around the selected tone in the source color parameter ('srccolor'). In other words, the selected tone is the pivotal point that guides everything else in the matte subsequently. For example, when keying based on Brightness, the brightest area will be the selected tone, and from there the rest will follow.

The principle applying to all the available modes, the node offers the possibility to key based on Hue, Saturation or Brightness individually, as well as the combined Hue/Saturation, Hue/Brightness or Saturation/Brightness. Selecting the output method is not very intuitive, but it's located at the end of node's properties, right under the output mask channel (dropdown) menu.
Back to content