Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionLast revisionBoth sides next revision | ||
isp:brightness [2023/09/06 10:44] – [Integer arithmetic] Igor Yefmov | isp:brightness [2023/09/10 21:01] – [Calculation reference] Igor Yefmov | ||
---|---|---|---|
Line 6: | Line 6: | ||
===== In RGB color space ===== | ===== In RGB color space ===== | ||
- | In RGB color space the operation is a matrix multiplication of the RGB's vector by a given " | + | The mathematically correct way to do the brightness is to first convert into HSL color space, adjust |
- | Considering that the luminance is calculated as (see [[isp:luminance]]) | + | ==== Algorithm ==== |
+ | Here' | ||
+ | - calculate luminosity | ||
+ | - adjust the brightness additively and clamp the value to range \([0..4095]\) | ||
+ | - figure out the slope for each components based on whether luma is below or above 50% and set chroma components to values that correspond to that 50% luma | ||
+ | - figure out if the new luma is going to cross the 50% boundary and if so - "flip the slopes" | ||
+ | - recalculate RGB components | ||
- | \[lum = 0.2126 * R + 0.7152 * G + 0.0722 * B\] | + | ==== Calculation reference ==== |
- | Further consider that the brightness is simply | + | 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}\] | ||
+ | |||
+ | Brightness adjustment is a trivial addition, clamping the value to its proper limits: | ||
\[ | \[ | ||
- | \begin{bmatrix} | + | L` = L + br \\ |
- | R \\ | + | L` \in [0..4095] |
- | G \\ | + | |
- | B | + | |
- | \end{bmatrix} | + | |
- | + | + | |
- | \begin{bmatrix} | + | |
- | 0.2126 * br \\ | + | |
- | 0.7152 * br \\ | + | |
- | 0.0722 * br | + | |
- | \end{bmatrix} | + | |
\] | \] | ||
- | ==== Integer arithmetic ==== | + | The slope \(k_R\) |
- | Of course when implemented on FPGA the preference is to use integer arithmetic, so for 12-bit RGB components and a 12-bit signed | + | \[ |
+ | k_{R} = | ||
+ | \begin{cases} | ||
+ | R / L & \text{if} \; L \leq 2047 \\ | ||
+ | \frac{R - 2047}{L - 2047} & \text{if} \; L > 2047 | ||
+ | \end{cases} | ||
+ | \] | ||
+ | Finding the " | ||
\[ | \[ | ||
- | \begin{bmatrix} | + | R = |
- | R \\ | + | \begin{cases} |
- | G \\ | + | k_R * 2047 & \text{if} \; L \leq 2047 \\ |
- | B | + | 255 - k_R * 2047 & \text{if} \; L > 2047 |
- | \end{bmatrix} | + | \end{cases} |
- | + | + | |
- | \begin{bmatrix} | + | |
- | 871 \\ | + | |
- | 2929 \\ | + | |
- | 297 | + | |
- | \end{bmatrix} \times br \times \frac{1}{1024} \\ | + | |
\] | \] | ||
+ | |||
+ | If we are crossing the middle luma boundary as the result of this adjustment - flip the slope: | ||
+ | \[ | ||
+ | k_R = 2 - k_R | ||
+ | \] | ||
+ | |||
+ | Applying the new \(L`\) to R component and clamping the result is trivial: | ||
+ | |||
+ | \[ | ||
+ | R` = k_R * (L` - 2047) + R \\ | ||
+ | R` \in [0..4095] | ||
+ | \] | ||
+ | |||
+ | \(G\) and \(B\) calculations are similar to \(R\). | ||
===== In HSL color space ===== | ===== In HSL color space ===== |