Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
isp:hsl-_rgb [2019/05/27 14:44] – [Division-less division] Igor Yefmov | isp:hsl-_rgb [2022/04/04 23:32] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== HSL->RGB ====== | ====== HSL->RGB ====== | ||
- | The text below is based on an Excel workbook attached to this page: {{ :isp:hsl-rgb.xlsm |}}. That Excel file provides a sort of playground where you can try various input data and see the final results, both " | + | The text below is based on a {{ https://docs.google.com/ |
===== Preface ===== | ===== Preface ===== | ||
- | Much is written and is available on the color space conversion from HSL to RGB (for example this [[https:// | + | Much is written and is available on the color space conversion from HSL to RGB (for example this [[https:// |
The below article details the way to perform this conversion without the use of division operations with high enough precision as to satisfy the imaging pipeline quality requirements for the SUB2r camera based on Artix-7 100T FPGA. | The below article details the way to perform this conversion without the use of division operations with high enough precision as to satisfy the imaging pipeline quality requirements for the SUB2r camera based on Artix-7 100T FPGA. | ||
Line 10: | Line 10: | ||
* \(H\) (hue) is a signed '' | * \(H\) (hue) is a signed '' | ||
* \(S\) (saturation) is an '' | * \(S\) (saturation) is an '' | ||
- | * \(L\) (luminosity) is a '' | + | * \(L\) (luminosity) is a '' |
The output of this conversion is an \(RGB\) triplet '' | The output of this conversion is an \(RGB\) triplet '' | ||
Line 20: | Line 20: | ||
\[\frac{1}{x} = \frac{1*N}{x*N}\] | \[\frac{1}{x} = \frac{1*N}{x*N}\] | ||
and choosing \(N\) such that \(x*N\) is a whole power of \(2\) we have an optimization where a division is replaced by a pair of a multiplication followed by a (super cheap!) bit-shift operation by \(Z\) bits: | and choosing \(N\) such that \(x*N\) is a whole power of \(2\) we have an optimization where a division is replaced by a pair of a multiplication followed by a (super cheap!) bit-shift operation by \(Z\) bits: | ||
- | \[\frac{C}{x} = C*\frac{1}{x} = C*\frac{1*N}{x*N} = C*\frac{N}{2^Z} = [(C*N)>>Z]\] | + | \[\frac{C}{x} = C*\frac{1}{x} = C*\frac{1*N}{x*N}\Bigg|_{\{x*N=2^Z\}} = C*\frac{N}{2^Z} = [(C*N) |
The value \(Z\) depends on the needed precision and, of course, the higher the \(Z\) the less precision loss there will be in the end. | The value \(Z\) depends on the needed precision and, of course, the higher the \(Z\) the less precision loss there will be in the end. | ||
Line 28: | Line 28: | ||
The last part, losing the 14 LSB, doesn' | The last part, losing the 14 LSB, doesn' | ||
- | ===== Step-by-step algorithm ===== | + | |
+ | ===== Precise calculations ===== | ||
+ | As a refresher this is how [[https:// | ||
+ | |||
+ | Given a color with hue \(H ∈ [0°, 360°]\), saturation \(S_{HSL} ∈ [0, 1]\), and lightness \(L ∈ [0, 1]\), we first find chroma: | ||
+ | \[ C = (1 - \left\vert 2 L - 1 \right\vert) \times S_{HSL} \] | ||
+ | |||
+ | Then we can find a point \((R_1, G_1, B_1)\) along the bottom three faces of the RGB cube, with the same hue and chroma as our color (using the intermediate value \(X\) for the second largest component of this color): | ||
+ | \[ H^\prime = \frac{H}{60^\circ} \] | ||
+ | \[ X = C \times (1 - |H^\prime \bmod 2 - 1|) \] | ||
+ | \[ | ||
+ | (R_1, G_1, B_1) = | ||
+ | \begin{cases} | ||
+ | (0, 0, 0) & | ||
+ | (C, X, 0) & | ||
+ | (X, C, 0) & | ||
+ | (0, C, X) & | ||
+ | (0, X, C) & | ||
+ | (X, 0, C) & | ||
+ | (C, 0, X) & | ||
+ | \end{cases} | ||
+ | \] | ||
+ | |||
+ | Overlap (when \(H^\prime\) is an integer) occurs because two ways to calculate the value are equivalent: \(X = 0\) or \(X = C\), as appropriate. | ||
+ | |||
+ | Finally, we can find \(R, G, B\) by adding the same amount to each component, to match lightness: | ||
+ | |||
+ | \[m=L-C/ | ||
+ | \[(R, | ||
+ | |||
+ | ===== Step-by-step algorithm | ||
+ | Armed with the above information we can now compile the necessary sequence of calculations and format it into an easy-to-use table: | ||
+ | |||
+ | ^ # ^ name ^ math excerpt from Wikipedia | ||
+ | | 1 | \[h\] | \[hue(pixel)\] | '' | ||
+ | | 2 | \[s\] | \[sat(pixel)\] | '' | ||
+ | | 3 | \[l\] | \[luma(pixel)\] | '' | ||
+ | | 4 | \[H\] | \[(H+360^\circ) \bmod 360^\circ\] | '' | ||
+ | H = (h1 > 0 ? h1 : h1 + 4096);</ | ||
+ | | | \(S\)((not needed for calculations)) | \[\frac{S}{255}\] | | \[0..1\] | | | | ||
+ | | | \(L\)((not needed for calculations)) | \[\frac{S}{511}\] | | \[0..1\] | | | | ||
+ | | 5 | \[L^\prime\] | \[1-|2L-1|\] | '' | ||
+ | | 6 | \[C\] | \[L^\prime \times S\] | '' | ||
+ | | 7 | \[H^\prime\] | \[\frac{H}{60^\circ}\] | '' | ||
+ | | 8 | \[H^\prime_2\] | \[H^\prime \bmod 2\] | '' | ||
+ | | 9 | \[H^\prime_{2-1}\] | \[H^\prime \bmod 2 - 1\] | '' | ||
+ | | 11 | \[H^\prime_{final}\] | \[1-|H^\prime \bmod 2 - 1|\] | '' | ||
+ | | 12 | \[X\] | \[C \times H^\prime_{final}\] | '' | ||
+ | | 13 | \[(R_1, | ||
+ | / | ||
+ | }else if(Hp < 364*2){ | ||
+ | / | ||
+ | }// | ||
+ | | 14 | \[m\] | \[L - C/2\] | '' | ||
+ | | 15 | \[(R,G,B)\] | \[(R_1+m, | ||
+ | |||
+ | |||
+ | ===== Step-by-step algorithm (10x3 bit channel, 30-bit RGB) ===== | ||
+ | Armed with the above information we can now compile the necessary sequence of calculations and format it into an easy-to-use table: | ||
+ | |||
+ | ^ # ^ name ^ math excerpt from Wikipedia | ||
+ | | 1 | \[H\] | \[hue(pixel)\] | '' | ||
+ | | 2 | \[S\] | \[sat(pixel)\] | '' | ||
+ | | 3 | \[L\] | \[luma(pixel)\] | '' | ||
+ | | 4 | \[h\] | \[(H+360^\circ) \bmod 360^\circ\] | '' | ||
+ | | 5 | \[L^\prime\] | \[1-|2L-1|\] | '' | ||
+ | | 6 | \[C\] | \[L^\prime \times S\] | '' | ||
+ | | 7 | \[H^\prime\] | \[\frac{H}{60^\circ}\] | '' | ||
+ | | 8 | \[H^\prime_2\] | \[H^\prime \bmod 2\] | '' | ||
+ | | 9 | \[H^\prime_{2-1}\] | \[H^\prime \bmod 2 - 1\] | '' | ||
+ | | 11 | \[H^\prime_{final}\] | \[1-|H^\prime \bmod 2 - 1|\] | '' | ||
+ | | 12 | \[X\] | \[C \times H^\prime_{final}\] | '' | ||
+ | | 13 | \[(R_1, | ||
+ | / | ||
+ | }else if(Hp < 745472*2){ | ||
+ | / | ||
+ | }// | ||
+ | | 14 | \[m\] | \[L - C/2\] | '' | ||
+ | | 15 | \[(R,G,B)\] | \[(R_1+m, | ||