OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 1:13 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 10 posts ] 
Author Message
 Post subject: 640x480x8 Display, 8bit RGB to VGA palette.
PostPosted: Sun Mar 12, 2023 1:53 am 
Offline

Joined: Sat Feb 25, 2023 2:02 pm
Posts: 7
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:
Image
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 :D

_________________
https://github.com/joexbayer/RetrOS-32


Top
 Profile  
 
 Post subject: Re: 640x480x8 Display, 8bit RGB to VGA palette.
PostPosted: Mon Apr 03, 2023 6:01 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5100
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.


Top
 Profile  
 
 Post subject: Re: 640x480x8 Display, 8bit RGB to VGA palette.
PostPosted: Mon Apr 03, 2023 6:50 pm 
Offline
Member
Member

Joined: Tue Mar 04, 2014 5:27 am
Posts: 1108
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.


Top
 Profile  
 
 Post subject: Re: 640x480x8 Display, 8bit RGB to VGA palette.
PostPosted: Mon Apr 03, 2023 8:41 pm 
Offline
Member
Member

Joined: Sat Nov 21, 2009 5:11 pm
Posts: 852
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.


Top
 Profile  
 
 Post subject: Re: 640x480x8 Display, 8bit RGB to VGA palette.
PostPosted: Tue Apr 04, 2023 1:23 am 
Offline

Joined: Sat Feb 25, 2023 2:02 pm
Posts: 7
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.


Yes, posted it here and on reddit at the same time but it wasn't approved here until now! :D
Thanks again for your feedback, managed to solve it at last.

_________________
https://github.com/joexbayer/RetrOS-32


Top
 Profile  
 
 Post subject: Re: 640x480x8 Display, 8bit RGB to VGA palette.
PostPosted: Tue Apr 04, 2023 1:23 am 
Offline

Joined: Sat Feb 25, 2023 2:02 pm
Posts: 7
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.


Thanks! I will have a look at Ordered dithering! :)

_________________
https://github.com/joexbayer/RetrOS-32


Top
 Profile  
 
 Post subject: Re: 640x480x8 Display, 8bit RGB to VGA palette.
PostPosted: Fri May 05, 2023 8:47 am 
Offline
Member
Member
User avatar

Joined: Mon Jun 05, 2006 11:00 pm
Posts: 2293
Location: USA (and Australia)
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.


I'll explain a simple method if you don't care about dithering.

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:
struct Color {
    float red, green, blue;
};

Color palette[256];


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.

To find the closest Palette Color from RGB color, loop through all your palette colors and return the one with the smallest error.

Code:
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;
}


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:
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;
}


Now, FindClosestPaletteColor() is slow and inefficient to be called in real-time for every color. We can generate a lookup table!

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:
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});
      }
    }
  }
}


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.

Now that you have your lookup table, we can efficiently lookup the closest palette index of any color:
Code:
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];
}


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:
unsigned char palette_lookup_table[] = { ... };

_________________
My OS is Perception.


Top
 Profile  
 
 Post subject: Re: 640x480x8 Display, 8bit RGB to VGA palette.
PostPosted: Tue May 16, 2023 7:08 am 
Offline

Joined: Sat Feb 25, 2023 2:02 pm
Posts: 7
AndrewAPrice wrote:
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.


I'll explain a simple method if you don't care about dithering.

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:
struct Color {
    float red, green, blue;
};

Color palette[256];


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.

To find the closest Palette Color from RGB color, loop through all your palette colors and return the one with the smallest error.

Code:
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;
}


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:
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;
}


Now, FindClosestPaletteColor() is slow and inefficient to be called in real-time for every color. We can generate a lookup table!

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:
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});
      }
    }
  }
}


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.

Now that you have your lookup table, we can efficiently lookup the closest palette index of any color:
Code:
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];
}


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:
unsigned char palette_lookup_table[] = { ... };


Thanks for the detailed response!
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.

_________________
https://github.com/joexbayer/RetrOS-32


Top
 Profile  
 
 Post subject: Re: 640x480x8 Display, 8bit RGB to VGA palette.
PostPosted: Sat May 20, 2023 8:41 am 
Offline
Member
Member
User avatar

Joined: Mon May 22, 2017 5:56 am
Posts: 812
Location: Hyperspace
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.

_________________
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


Top
 Profile  
 
 Post subject: Re: 640x480x8 Display, 8bit RGB to VGA palette.
PostPosted: Sun May 21, 2023 12:38 am 
Offline
Member
Member
User avatar

Joined: Mon May 22, 2017 5:56 am
Posts: 812
Location: Hyperspace
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
9colors.png [ 5.51 KiB | Viewed 1357 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
Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 59 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group