Both sides previous revisionPrevious revisionNext revision | Previous revision |
isp:hsl-_rgb [2021/07/24 11:02] – [Division-less division] Igor Yefmov | isp:hsl-_rgb [2022/04/04 23:32] (current) – external edit 127.0.0.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 "precise" and "optimized", as well as the discrepancy between the two methods. | The text below is based on a {{ https://docs.google.com/spreadsheets/d/1K3kp-Ofc46DEjLrNZLLeVAv1sQBafWe9N2UWncYa6CM/edit?usp=sharing | SUB2r ISP Excel workbook}}. That workbook provides a sort of playground where you can try various input data and see the final results, both "precise" and "optimized"((lower precision)), as well as the discrepancy between the two methods. |
===== Preface ===== | ===== Preface ===== |
Much is written and is available on the color space conversion from HSL to RGB (for example this [[https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB|Wikipedia article]]). However, not only this is not meant to be used with integer arithmetics, but is also very costly due to division operations. And once you realize that a 4K video running at 60FPS needs to do this conversion half a billion times a second(!) you see why this needs to be heavily optimized ;-) | Much is written and is available on the color space conversion from HSL to RGB (for example this [[https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB|Wikipedia article]]). However, not only this is not meant to be used with integer arithmetics, but is also very costly due to division operations. And once you realize that a 4K video running at 60FPS needs to do this conversion half a billion times a second(!) you see why this needs to be heavily optimized ;-) |
\[(R,G,B)=(R_1+m,G_1+m,B_1+m)\] | \[(R,G,B)=(R_1+m,G_1+m,B_1+m)\] |
| |
===== Step-by-step algorithm ===== | ===== Step-by-step algorithm (8x3 bit channel, 24-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: | Armed with the above information we can now compile the necessary sequence of calculations and format it into an easy-to-use table: |
| |
| 14 | \[m\] | \[L - C/2\] | ''9'' | \[0..510\] | <code>m = l - C / 2;</code> | \[\frac{1}{2^9}\] | | | 14 | \[m\] | \[L - C/2\] | ''9'' | \[0..510\] | <code>m = l - C / 2;</code> | \[\frac{1}{2^9}\] | |
| 15 | \[(R,G,B)\] | \[(R_1+m,G_1+m,B_1+m)\] | ''8'' | \[0..255\] | <code>R=R1+m; G=G1+m; B=B1+m;</code> | \[1\] | | | 15 | \[(R,G,B)\] | \[(R_1+m,G_1+m,B_1+m)\] | ''8'' | \[0..255\] | <code>R=R1+m; G=G1+m; B=B1+m;</code> | \[1\] | |
| |
| |
| ===== 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 ^ bits ^ range ^ C-like code ^ factor((multiply by that much to get the "real" value)) ^ |
| | 1 | \[H\] | \[hue(pixel)\] | ''14''\\ signed | \[-8192..+8191\] mapped into \(-180^\circ..+180^\circ\) | <code>H = pixel.hue();</code> | \[\frac{180}{2^{13}}\] | |
| | 2 | \[S\] | \[sat(pixel)\] | ''9'' | \[0..511\] | <code>S = pixel.sat();</code> | \[^1/_2\] | |
| | 3 | \[L\] | \[luma(pixel)\] | ''12'' | \[0..4095\] mapped into \(0..255\) | <code>L = pixel.luma();</code> | \[\frac{1}{2^4}\] | |
| | 4 | \[h\] | \[(H+360^\circ) \bmod 360^\circ\] | ''14'' | \[0..16383\] mapped into \(0^\circ..+360^\circ\) | <code>h = (H > 0 ? H : H + 16383);</code> | \[\frac{360}{2^{14}}\] | |
| | 5 | \[L^\prime\] | \[1-|2L-1|\] | ''12'' | | <code>L_prime = 2^12 - abs(2 * L - 2^12);</code> | \[\frac{1}{2^{12}}\] | |
| | 6 | \[C\] | \[L^\prime \times S\] | ''21'' | | <code>C = L_prime * s;</code> | \[\frac{1}{2^{21}}\] | |
| | 7 | \[H^\prime\] | \[\frac{H}{60^\circ}\] | ''23'' | \[0..2^23-1\] mapped into \(0..6\) | <code>Hp = H * 273;</code> | \[\frac{180}{2^{27}}\] | |
| | 8 | \[H^\prime_2\] | \[H^\prime \bmod 2\] | ''21'' | | <code>Hp2 = Hp - (91 * 2^14) * (Hp * 90) >> 27)</code>((optimized from <code>Hp2 = Hp % (2^14 * 273 / 3);</code>)) | \[\frac{180}{2^{27}}\] | |
| | 9 | \[H^\prime_{2-1}\] | \[H^\prime \bmod 2 - 1\] | ''21''\\ signed | | <code>Hp2m1 = Hp2 - 2^13 * 91;</code> | \[\frac{180}{2^{27}}\] | |
| | 11 | \[H^\prime_{final}\] | \[1-|H^\prime \bmod 2 - 1|\] | ''21'' | | <code>Hpf = 91 * 2^13 - abs(Hp2m1);</code> | \[\frac{180}{2^{27}}\] | |
| | 12 | \[X\] | \[C \times H^\prime_{final}\] | ''21'' | | <code>X = ((C * Hpf * 180) >> 27);</code> | \[\frac{1}{2^21}\] | |
| | 13 | \[(R_1,G_1,B_1)\] | multi-branch | ''21'' | | <code>if(Hp < 745472*1){ |
| /*(C,X,0)*/ |
| }else if(Hp < 745472*2){ |
| /*(X,C,0)*/ |
| }//...</code> | \[\] | |
| | 14 | \[m\] | \[L - C/2\] | ''12'' | | <code>m = L - (C / 2^9) / 2;</code> | \[\frac{1}{2^{12}}\] | |
| | 15 | \[(R,G,B)\] | \[(R_1+m,G_1+m,B_1+m)\] | ''10'' | \[0..1023\] | <code>R=(R1/2^9+m)/2^2; G=(G1/2^9+m)/2^2; B=(B1/2^9+m)/2^2;</code> | \[1\] | |
| |