Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision |
isp:hsl-_rgb [2019/05/27 23:07] – [Detailed algorithm] Igor Yefmov | isp:hsl-_rgb [2019/05/27 23:51] – Igor Yefmov |
---|
* \(H\) (hue) is a signed ''14''-bit field that maps into \([-180°..+180°]\) range | * \(H\) (hue) is a signed ''14''-bit field that maps into \([-180°..+180°]\) range |
* \(S\) (saturation) is an ''8''-bit unsigned value which maps into \([0\%..100\%]\) range | * \(S\) (saturation) is an ''8''-bit unsigned value which maps into \([0\%..100\%]\) range |
* \(L\) (luminosity) is a ''9''-bit unsigned value that maps into \([0\%..100\%]\) range just like the \(saturation\) above | * \(L\) (luminosity) is a ''9''-bit unsigned value that maps into \([0\%..100\%]\) range, very much like the \(saturation\) above |
| |
The output of this conversion is an \(RGB\) triplet ''24''-bits wide with ''8'' bits unsigned value per color channel in range \([0..255]\) | The output of this conversion is an \(RGB\) triplet ''24''-bits wide with ''8'' bits unsigned value per color channel in range \([0..255]\) |
| |
The last part, losing the 14 LSB, doesn't have to be done right away and with the goal of preserving as much precision as possible this operation can be postponed until later time (just need to remember that the "real" value is now augmented by that \(2^{14}\) factor and adjust accordingly). | The last part, losing the 14 LSB, doesn't have to be done right away and with the goal of preserving as much precision as possible this operation can be postponed until later time (just need to remember that the "real" value is now augmented by that \(2^{14}\) factor and adjust accordingly). |
===== Step-by-step algorithm ===== | |
| |
==== Precise calculations ==== | ===== Precise calculations ===== |
As a refresher this is how [[https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB|Wikipedia]] lists the way to convert HSL to RGB: | As a refresher this is how [[https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB|Wikipedia]] lists the way to convert HSL to RGB: |
| |
\[(R,G,B)=(R_1+m,G_1+m,B_1+m)\] | \[(R,G,B)=(R_1+m,G_1+m,B_1+m)\] |
| |
==== Detailed algorithm ==== | ===== 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: | Armed with the above information we can now compile the necessary sequence of calculations and format it into an easy-to-use table: |
| |
| 2 | \[s\] | \[sat(pixel)\] | ''8'' | \[0..255\] | <code>s = pixel.sat();</code> | \[1\] | | | 2 | \[s\] | \[sat(pixel)\] | ''8'' | \[0..255\] | <code>s = pixel.sat();</code> | \[1\] | |
| 3 | \[l\] | \[luma(pixel)\] | ''9'' | \[0..511\] mapped into \(0..255\) | <code>l = pixel.luma();</code> | \[^1/_2\] | | | 3 | \[l\] | \[luma(pixel)\] | ''9'' | \[0..511\] mapped into \(0..255\) | <code>l = pixel.luma();</code> | \[^1/_2\] | |
| 4 | \[H\] | \[(H+360^\circ) \bmod 360^\circ\] | ''12'' | \[0..4096\] mapped into \(0^\circ..+360^\circ\) | <code>H = ((h > 0 ? h : h + 16384) >> 2);</code> ((alternatively optimized into:<code>h1 = h / 4; | | 4 | \[H\] | \[(H+360^\circ) \bmod 360^\circ\] | ''12'' | \[0..4096\] mapped into \(0^\circ..+360^\circ\) | <code>h1 = (h >> 2); |
H = (h1 > 0 ? h1 : h1 + 4096);</code>)) | \[\frac{45}{2^{9}}\] | | H = (h1 > 0 ? h1 : h1 + 4096);</code> ((optimized from<code>H = ((h > 0 ? h : h + 16384) >> 2);</code>)) | \[\frac{45}{2^{9}}\] | |
| | \(S\)((not needed for calculations)) | \[\frac{S}{255}\] | | \[0..1\] | | | | | | \(S\)((not needed for calculations)) | \[\frac{S}{255}\] | | \[0..1\] | | | |
| | \(L\)((not needed for calculations)) | \[\frac{S}{511}\] | | \[0..1\] | | | | | | \(L\)((not needed for calculations)) | \[\frac{S}{511}\] | | \[0..1\] | | | |
| 5 | \[L^\prime\] | \[1-|2L-1|\] | ''9'' | \[0..510\] | <code>L_prime = 2^9 - abs(2 * L - 2^9);</code> | \[\frac{1}{2^9}\] | | | 5 | \[L^\prime\] | \[1-|2L-1|\] | ''9'' | \[0..510\] | <code>L_prime = 2^9 - abs(2 * L - 2^9);</code> | \[\frac{1}{2^9}\] | |
| 6 | \[C\] | \[L^\prime \times S\] | ''9'' | \[0..510\] | <code>C = L_prime * s / 2^8</code> | \[\frac{1}{2^9}\] | | | 6 | \[C\] | \[L^\prime \times S\] | ''9'' | \[0..510\] | <code>C = ((L_prime * s) >> 8);</code> | \[\frac{1}{2^9}\] | |
| 7 | \[H^\prime\] | \[\frac{H}{60^\circ}\] | ''12'' | \[0..4095\] mapped into \(0..6\) | <code>Hp = H * 273 / 2^9</code> | \[\frac{45}{2^{14}}\] | | | 7 | \[H^\prime\] | \[\frac{H}{60^\circ}\] | ''12'' | \[0..4095\] mapped into \(0..6\) | <code>Hp = ((H * 273) >> 9);</code> | \[\frac{45}{2^{14}}\] | |
| 8 | \[H^\prime_2\] | \[H^\prime \bmod 2\] | ''10'' | \[0..727\] | <code>Hp2 = Hp - (91 * 2^3) * ((Hp * 90) >> 16)</code>((optimized from <code>Hp2 = Hp % (2^3 * 273 / 3);</code>)) | \[\frac{45}{2^{14}}\] | | | 8 | \[H^\prime_2\] | \[H^\prime \bmod 2\] | ''10'' | \[0..727\] | <code>Hp2 = Hp - (91 * 2^3) * ((Hp * 90) >> 16)</code>((optimized from <code>Hp2 = Hp % (2^3 * 273 / 3);</code>)) | \[\frac{45}{2^{14}}\] | |
| 9 | \[\] | \[\] | '''' | \[\] | <code></code> | \[\] | | | 9 | \[H^\prime_{2-1}\] | \[H^\prime \bmod 2 - 1\] | ''10''\\ signed | \[-364..+363\] | <code>Hp2m1 = Hp2 - 2^2 * 91;</code> | \[\frac{45}{2^{14}}\] | |
| 10 | \[\] | \[\] | '''' | \[\] | <code></code> | \[\] | | | 11 | \[H^\prime_{final}\] | \[1-|H^\prime \bmod 2 - 1|\] | ''9'' | \[0..364\] mapped into \(0..1\) | <code>Hpf = 91 * 2^2 - abs(Hp2m1);</code> | \[\frac{45}{2^{14}}\] | |
| | 12 | \[X\] | \[C \times H^\prime_{final}\] | ''9'' | \[0..510\] | <code>X = ((C * Hpf * 180) >> 16);</code> | \[\frac{1}{2^9}\] | |
| | 13 | \[(R_1,G_1,B_1)\] | multi-branch | ''9'' | \[0..510\] | <code>if(Hp < 364*1){ |
| /*(C,X,0)*/ |
| }else if(Hp < 364*2){ |
| /*(X,C,0)*/ |
| }//...</code> | \[\] | |
| | 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\] | |
| |