640x480x8 Display, 8bit RGB to VGA palette.
640x480x8 Display, 8bit RGB to VGA palette.
I have a 640x480x8 display meaning 1 byte per pixel. This is mostly because I want to restrain myself
and use as little memory as possible. Now I have found out that because of the 8bit, I use the VGA palette:
This was "fine" until I started to add icons / pictures that are exported to 8bit RGB.
I have been searching for a while now, through this forum and the reddit and not found a way to map 8bit RGB colors to the VGA palette.
Ive considered going through all the 255 possible colors and map them 1 to 1, but the shades of colors make this really hard.
Is this just an impossible task or have I not been searching hard enough?
I really hope there isn't a obvious answer that I have missed all this time
and use as little memory as possible. Now I have found out that because of the 8bit, I use the VGA palette:
This was "fine" until I started to add icons / pictures that are exported to 8bit RGB.
I have been searching for a while now, through this forum and the reddit and not found a way to map 8bit RGB colors to the VGA palette.
Ive considered going through all the 255 possible colors and map them 1 to 1, but the shades of colors make this really hard.
Is this just an impossible task or have I not been searching hard enough?
I really hope there isn't a obvious answer that I have missed all this time
-
- Member
- Posts: 5492
- Joined: Mon Mar 25, 2013 7:01 pm
Re: 640x480x8 Display, 8bit RGB to VGA palette.
This question was also posted elsewhere.
Since 640x480x8 is a VBE mode, you can use VBE functions to set the palette. Using your own palette should make things much easier, but you might still need to research quantization algorithms to map the colors in your image to the colors available on the screen.
Since 640x480x8 is a VBE mode, you can use VBE functions to set the palette. Using your own palette should make things much easier, but you might still need to research quantization algorithms to map the colors in your image to the colors available on the screen.
Re: 640x480x8 Display, 8bit RGB to VGA palette.
Change the palette to all combinations of RGBs that fit into 256 colors, e.g. 6 reds * 6 greens * 6 blues = 216 colors.
Then use e.g. Ordered dithering.
Then use e.g. Ordered dithering.
Re: 640x480x8 Display, 8bit RGB to VGA palette.
Personally I use a 676 palette, but if you want to map colors to the standard VGA palette, you could find the saturation and value, use a gray if the saturation is below the limit (depending on value) where the color is best approximated by a gray, otherwise use the appropriate row based on which grid square the value and saturation fall into. Might also check if the color is better approximated by one of the 12 non-gray colors in the first row, again by classifying according to HSV coordinates. For dithering, it is not so easy, haven't done it myself but you'll probably need to precompute a map from chroma and value to the closest set of three points in SV space, and then use the hue as well to get six colors to use for the mix.
Re: 640x480x8 Display, 8bit RGB to VGA palette.
Yes, posted it here and on reddit at the same time but it wasn't approved here until now!Octocontrabass wrote:This question was also posted elsewhere.
Since 640x480x8 is a VBE mode, you can use VBE functions to set the palette. Using your own palette should make things much easier, but you might still need to research quantization algorithms to map the colors in your image to the colors available on the screen.
Thanks again for your feedback, managed to solve it at last.
Re: 640x480x8 Display, 8bit RGB to VGA palette.
Thanks! I will have a look at Ordered dithering!alexfru wrote:Change the palette to all combinations of RGBs that fit into 256 colors, e.g. 6 reds * 6 greens * 6 blues = 216 colors.
Then use e.g. Ordered dithering.
- AndrewAPrice
- Member
- Posts: 2297
- Joined: Mon Jun 05, 2006 11:00 pm
- Location: USA (and Australia)
Re: 640x480x8 Display, 8bit RGB to VGA palette.
I'll explain a simple method if you don't care about dithering.joexbayer wrote:I have been searching for a while now, through this forum and the reddit and not found a way to map 8bit RGB colors to the VGA palette.
Ive considered going through all the 255 possible colors and map them 1 to 1, but the shades of colors make this really hard.
Let's assumine you have a palette->RGB lookup table, where you can look up "Palette Color 5" and get the RGB values for it.
Code: Select all
struct Color {
float red, green, blue;
};
Color palette[256];
To find the closest Palette Color from RGB color, loop through all your palette colors and return the one with the smallest error.
Code: Select all
int FindClosestPaletteColor(const Color& color) {
int closestPaletteColor = 0;
float smallest_error = INT_MAX;
for (int i = 0; i < 256; i++) {
float error = DifferenceBetweenColors(pallete[i], color);
if (error < smallest_error) {
smallest_error = error;
closestPaletteColor = i;
}
}
return closestPaletteColor;
}
Code: Select all
float DifferenceBetweenColors(const Color& a, const Color& b) {
float delta_red = a.red - b.red;
float delta_green = a.green - b.green;
float delta_blue = a.blue - b.blue;
float error = delta_red * delta_red + delta_green * delta_green + delta_blue * delta_blue;
}
We can very efficiently take a random RGB color, turn it into 5-bit (32 values) per channel RGB color, which gives us 32,768 possible colors. You could construct the lookup table like this:
Code: Select all
unsigned char palette_lookup_table[32768]; // 2^15.
void PopulateLookupTable() {
for (int red = 0; red < 32; red++) {
for (int green = 0; green < 32; green++) {
for (int blue = 0; blue < 32; blue++) {
palette_lookup_table[red + green * 32 + blue * (32 * 32)] =
FindClosestPaletteColor({static_cast<float>(red) / 31.0f,
static_cast<float>(green) / 31.0f,
static_cast<float>(blue) / 31.0f, 1.0f});
}
}
}
}
Now that you have your lookup table, we can efficiently lookup the closest palette index of any color:
Code: Select all
int ColorToPaletteIndex(const Color& color) const {
// Convert the color to 15-bits and look it up.
int red = static_cast<int>(color.red * 31.0f);
int green = static_cast<int>(color.green * 31.0f);
int blue = static_cast<int>(color.blue * 31.0f);
int color_index =
std::max(0, std::min(red + green * 32 + blue * 1024, 32767));
return palette_lookup_table[color_index];
}
Code: Select all
unsigned char palette_lookup_table[] = { ... };
My OS is Perception.
Re: 640x480x8 Display, 8bit RGB to VGA palette.
Thanks for the detailed response!AndrewAPrice wrote:I'll explain a simple method if you don't care about dithering.joexbayer wrote:I have been searching for a while now, through this forum and the reddit and not found a way to map 8bit RGB colors to the VGA palette.
Ive considered going through all the 255 possible colors and map them 1 to 1, but the shades of colors make this really hard.
Let's assumine you have a palette->RGB lookup table, where you can look up "Palette Color 5" and get the RGB values for it.I'm defining red/green/blue to be floats from 0.0 to 1.0, but they could be unsigned chars from 0 to 255.Code: Select all
struct Color { float red, green, blue; }; Color palette[256];
To find the closest Palette Color from RGB color, loop through all your palette colors and return the one with the smallest error.
For calculating how different two colors are, I'm just treating colors as a 3d vector and doing a simple squared distance, but there are other methods too.Code: Select all
int FindClosestPaletteColor(const Color& color) { int closestPaletteColor = 0; float smallest_error = INT_MAX; for (int i = 0; i < 256; i++) { float error = DifferenceBetweenColors(pallete[i], color); if (error < smallest_error) { smallest_error = error; closestPaletteColor = i; } } return closestPaletteColor; }
Now, FindClosestPaletteColor() is slow and inefficient to be called in real-time for every color. We can generate a lookup table!Code: Select all
float DifferenceBetweenColors(const Color& a, const Color& b) { float delta_red = a.red - b.red; float delta_green = a.green - b.green; float delta_blue = a.blue - b.blue; float error = delta_red * delta_red + delta_green * delta_green + delta_blue * delta_blue; }
We can very efficiently take a random RGB color, turn it into 5-bit (32 values) per channel RGB color, which gives us 32,768 possible colors. You could construct the lookup table like this:
unsigned char lookupTable[32768] would use 32KB of memory. If that's too much, you may get by with your lookup table being 4-bits (16 values) per channel which would only use 4KB of memory. Smaller than that I'd worry you'd be loosing too much precision.Code: Select all
unsigned char palette_lookup_table[32768]; // 2^15. void PopulateLookupTable() { for (int red = 0; red < 32; red++) { for (int green = 0; green < 32; green++) { for (int blue = 0; blue < 32; blue++) { palette_lookup_table[red + green * 32 + blue * (32 * 32)] = FindClosestPaletteColor({static_cast<float>(red) / 31.0f, static_cast<float>(green) / 31.0f, static_cast<float>(blue) / 31.0f, 1.0f}); } } } }
Now that you have your lookup table, we can efficiently lookup the closest palette index of any color:FindClosestPaletteColor() and PopulateLookupTable() could exist in some separate program so you only have to construct the table once and you can hardcode the lookup table into your program:Code: Select all
int ColorToPaletteIndex(const Color& color) const { // Convert the color to 15-bits and look it up. int red = static_cast<int>(color.red * 31.0f); int green = static_cast<int>(color.green * 31.0f); int blue = static_cast<int>(color.blue * 31.0f); int color_index = std::max(0, std::min(red + green * 32 + blue * 1024, 32767)); return palette_lookup_table[color_index]; }
Code: Select all
unsigned char palette_lookup_table[] = { ... };
I will have a look at it, currently I got it working by remapping the palette to 8bit RGB.
Although the limitation of no real gray colors is pushing me back to VGA.
Re: 640x480x8 Display, 8bit RGB to VGA palette.
Plan 9 has an interesting color map. color(6) goes into what it is and why, and has code to compute the palette. (Note: The code may come under the Lucent LPL which has an odd legal clause. It might be best to use the numbers it outputs but not include the code itself in your OS.)
I might post again with a screenshot of the colors program; I've been meaning to install a Plan 9 VM.
I might post again with a screenshot of the colors program; I've been meaning to install a Plan 9 VM.
Kaph — a modular OS intended to be easy and fun to administer and code for.
"May wisdom, fun, and the greater good shine forth in all your work." — Leo Brodie
"May wisdom, fun, and the greater good shine forth in all your work." — Leo Brodie
Re: 640x480x8 Display, 8bit RGB to VGA palette.
Here's the Plan 9 color chart as stated. I'm not sure why it's laid out like this, but the greys are on the diagonal.
- Attachments
-
- 9colors.png (5.51 KiB) Viewed 2522 times
Kaph — a modular OS intended to be easy and fun to administer and code for.
"May wisdom, fun, and the greater good shine forth in all your work." — Leo Brodie
"May wisdom, fun, and the greater good shine forth in all your work." — Leo Brodie