This is an old revision of the document!
Brightness
In the simplest terms the “brightness” of a pixel is its luminosity value as perceived by a human eye (making infrared and gamma rays \(0\) “bright”). There are quite a few competing standards and definitions of what the means exactly, but for our purposes we will use the \(L\) component of the HSL color space as our “brightness” value of a pixel.
Again, in the simplest terms, increasing or reducing pixel's brightness can be interpreted as adding or subtracting a fixed “gain” value (others may argue that a more natural approach would be to use a multiplier, while others still may bring the “vibrancy” approach into picture).
In RGB color space
The mathematically correct way to do the brightness is to first convert into HSL color space, adjust the L (luma) component, and then convert back into RGB. That gives the correct result but costs way too many transistors and cycles. So we've got improvise!
Here's the algorithm to follow, assuming \(R, G, B \in [0..4095] and br \in [-1024..+1023]\):
- calculate luminosity
- figure out the slope for each components based on whether luma is below or above 50%
- figure out if the new luma is going to cross the 50% boundary
- if luma does cross the 50% boundary figure out the knee point's value (chroma component for luma at 50%) and assign it to chroma component
- recalculate the slope based on new range
- just adjust the brightness additively and clamp the value to range \([0..4095]\)
- recalculate RGB components
To calculate luminosity we just find the max and min of the triplet and get a simple average: \[L = \frac{min(R, G, B)+max(R, G, B)}{2}\]
The slope \(k_R\) for the red component calculation depends on whether \(L\) is above or below the middle: \[ k_{R} = \begin{cases} R / L & \text{if} \; L \leq 2047 \\ \frac{R - 2047}{L - 2047} & \text{if} \; L > 2047 \end{cases} \]
Similarly find the \(k_G\) and \(k_B\) for green and blue components respectively.
Brightness adjustment is a trivial addition, clamping the value to its proper limits:
\[ L` = L + br \\ L` \in [0..4095] \]
Apply the new \(L`\) to R component and clamp the result:
\[ R` = k_R * (L` - 2047) + R \\ R` \in [0..4095] \]
Similarly perform calculations for green and blue components.
In HSL color space
When using the HSL color space the adjustment is as simple as elementary school's arithmetic operation. Namely - just a simple addition.
With that the implementation of the Brightness adjustment can be as simple as the following (where the “luma”, or brightness component \(\in[0..100]%%\)):
// pseudo-code void brightness(/*array of pixels*/image, int _br){ for(const & pixel: image){ pixel.luma = std::clamp(pixel.luma + _br, 0, 100); } }