10 February 2021, 01:08 | #1 |
Lemon. / Core Design
Join Date: Mar 2016
Location: Tier 5
Posts: 1,213
|
Converting 8bit colour components to 4bit
How do YOU do it?
I guess the simplest way is to >> 4 But... then $EF as an 8 bit component is closer to $F (as a 4bit) than it is to $E I know that when converying from 4bit to 8bit, the general concensus is to use $xyz -> $xxyyzz (ie. $4C3 would become $44CC33), but going back the other way there are issues perhaps ? |
10 February 2021, 01:15 | #2 |
Registered User
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,430
|
I've done this in code just once so far, but I did indeed just do >> 4 in my script. But reading your post, I'm now thinking about using a floating point divide and rounding that instead. This would be more accurate, after all.
However, there may be better ways yet. Perhaps some sort of perceptual conversion where the conversion keeps in mind that human eyes don't really do linear colour might even be a neat trick. Don't have an algorithm at the ready, but common wisdom has it that our eyes are more sensitive to green than any other colour so perhaps rounding green up and the rest down might do the trick? Then again, perhaps a simple linear conversion is best after all. Might test that out for fun. |
10 February 2021, 01:19 | #3 |
Lemon. / Core Design
Join Date: Mar 2016
Location: Tier 5
Posts: 1,213
|
Yes, probably rounding each component up or down to the nearest $X0 value?
So $E7 would round to $E0, and $E8 to $F0 I know some people swear by dividing each component by 17 (as going from 4bit to 8bit, you do the equivalent of a multiply by 17).. but then this has issues where (for example) $FFFFFF is the only 8bit RGB value that would generate $FFF as a 4bit colour value |
10 February 2021, 01:31 | #4 |
Registered User
Join Date: Jun 2020
Location: Druidia
Posts: 389
|
I'm sure you've though of this but you could go with:
fourbit = (eightbit + 8) / 17 |
10 February 2021, 02:25 | #5 |
Registered User
Join Date: Feb 2021
Location: Becej / Serbia
Posts: 120
|
This really depends on what you want to accomplish.
The mathematically most perfect solution is the one written above (y = (x + 8) div 17), however in that solution you will get less white and black pixels than any other color. You will end up with 9 8bit colors being remapped to black and white and 17 colors being remapped to the rest. The fastest approach with >> 4 will give you less precise colors, but every single 4bit value will have 16 corresponding 8bit values so the actual output might look better. Alternatively you can use pattern dithering with (x+d) div 17 where the d values can be taken from this table: 1, 9, 3, 11 13, 5, 15, 7 4, 12, 2, 10 16, 8, 14, 6 It's pretty straightforward since you can just use (x and 3) and (y and 3) to get the values from the dither table. note: The dither table starts from 1 instead of 0 because this way the average we get is 8.5 which is pretty good for average rounding. If you don't want the div, you can go with y = ((x << 4) - x + d) >> 8, just need to scale the dither table up (or just use a constant d=128 for rounding). |
10 February 2021, 23:27 | #6 | |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 54
Posts: 4,483
|
Quote:
And my reasoning was to use code that would allow me to reverse the duplication of the nibble when doing RGB4 to RGB8. So I used the central RGB8 color and 'draw around' it an area using it as a pivot. This give me usually 8+1+8 values (excluding the reduced extremes and a different negligible point at 8). Visually: Code:
0 1 2 3 4 5 6 7 8 9 A B C D E F 00 00 00 00 00 00 00 00 00 01 01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 01 01 02 02 02 02 02 02 02 20 02 02 02 02 02 02 02 02 02 02 03 03 03 03 03 03 30 03 03 03 03 03 03 03 03 03 03 03 04 04 04 04 04 40 04 04 04 04 04 04 04 04 04 04 04 04 05 05 05 05 50 05 05 05 05 05 05 05 05 05 05 05 05 05 06 06 06 60 06 06 06 06 06 06 06 06 06 06 06 06 06 06 07 07 70 07 07 07 07 07 07 07 07 07 07 07 07 07 07 07 08 80 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 90 08 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 A0 09 09 0A 0A 0A 0A 0A 0A 0A 0A 0A 0A 0A 0A 0A 0A B0 0A 0A 0A 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B C0 0B 0B 0B 0B 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C D0 0C 0C 0C 0C 0C 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D E0 0D 0D 0D 0D 0D 0D 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E F0 0E 0E 0E 0E 0E 0E 0E 0F 0F 0F 0F 0F 0F 0F 0F 0F Code:
move.b d0,d1 lsr.b #4,d1 sub.b d1,d0 addq.b #8,d0 lsr.b #4,d0 I have no idea if there is a similar accepted algorithm in the literature, but it is as simple, fast and correct (for me) . |
|
10 February 2021, 23:44 | #7 |
Lemon. / Core Design
Join Date: Mar 2016
Location: Tier 5
Posts: 1,213
|
Yeah, I like that one Ross!! Remaps a good range of pure black and pure white
it's a conundrum that's plagued my mind for a long time So simple from 4bit -> 8bit, but so many ways going back the other way, which to all intents and purposes, will never be entirely correct. I guess it's how it looks visually, that's the only way to determine what method will give the best results. |
19 February 2021, 15:08 | #8 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,647
|
Range is 15 vs 255, not 16 vs 256, so just shifting will make all colors but 255 darker. (E.g. $1f -> $1)
Rounding will make bright colors darker, dark colors brighter, and be kind of randomly all right in the middle. (E.g. $12 -> $2) $11, $22, and so on compensates for 15/16 by multiplying by 17. It's pretty close (99.61%). This spreads out the range of 15 evenly across 255. So the correct color going the other way for $1 is $11, not $18 or $17 (rounding). It must be spread out. (Rounding must be done w/r to 17, not 16.) So the correct color reduction is divide (rounded) by 17. This can be done with a 256-byte LUT (or a 128 byte one if you want to shuffle nibbles around ) generated with addq.w #8,d0;divu #17,d0. Last edited by Photon; 19 February 2021 at 15:14. |
19 February 2021, 20:13 | #9 |
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,292
|
You don't need a division. As posted earlier, y = ((x << 4) - x + d) >> 8 for all 8 bit numbers. Try to proof this (Hint: Neumann series).
|
19 February 2021, 20:49 | #10 |
Registered User
Join Date: Jun 2016
Location: europe
Posts: 1,050
|
These are not equal in all 3 cases (columns are i, round(i/17.0), (i-(i>>4)+8)>>4, ((i<<4)-i+128)>>8):
Code:
08: 00 01 00 * 19: 01 02 01 * 2a: 02 03 02 * 3b: 03 04 03 * 4c: 04 05 04 * 5d: 05 06 05 * 6e: 06 07 06 * 7f: 07 08 07 * 91: 09 09 08 * a2: 0a 0a 09 * b3: 0b 0b 0a * c4: 0c 0c 0b * d5: 0d 0d 0c * e6: 0e 0e 0d * f7: 0f 0f 0e * |
19 February 2021, 21:18 | #11 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,647
|
Well, I have answered the question asked.
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Painting components for Amiga | Signman | support.Other | 0 | 10 October 2019 02:39 |
A4000 components | slk486 | support.Hardware | 26 | 04 May 2010 20:09 |
Wanted: A500 components | Specksynder | MarketPlace | 0 | 30 October 2009 16:18 |
wanted minimig components | jimbob005 | MarketPlace | 1 | 20 June 2008 17:17 |
Help converting an 8bit ISA slot to 16bit ISA slot | Smiley | support.Hardware | 4 | 25 April 2006 11:20 |
|
|