Alexander Zhak
Alexander Zhak

Reputation: 9272

Convert 24-bit color to 4-bit RGBI

I need to convert 24-bit colors to 4-bit RGBI (1 bit for Red, Green, Blue + Intensity).

Converting to 3-bit RGB is rather simple: set color bit if greater than 127, clear otherwise. However, there's only one intensity bit for all three channels, so what's the correct way to set it (if any)?

First I thought about dividing 8-bit channel to three parts like below:

But then I thought that probably the correct way would be to set intensity bit only if two of three channels are greater than 127. But in that case pure R, G, or B will not have intensity ever set (for example, in case of rbg(0,0,200)

Any advice is highly appreciated

Upvotes: 2

Views: 3162

Answers (1)

Ilmari Karonen
Ilmari Karonen

Reputation: 50328

A simple way to find the closest 4-bit RGBI approximation of a color is to consider the two possibilities for the intensity bit separately. That is to say, first find the closest RGB0 and RGB1 approximations for the color (which is easy to do, just by dividing each color axis at the appropriate point), and the determine which of these approximations is better.

Here's a simple C-ish pseudocode description of this algorithm:

// find the closest RGBx approximation of a 24-bit RGB color, for x = 0 or 1
function rgbx_approx(red, green, blue, x) {
    threshold = (x + 1) * 255 / 3;
    r = (red > threshold ? 1 : 0);
    g = (green > threshold ? 1 : 0);
    b = (blue > threshold ? 1 : 0);
    return (r, g, b);
}

// convert a 4-bit RGBI color back to 24-bit RGB
function rgbi_to_rgb24(r, g, b, i) {
   red = (2*r + i) * 255 / 3;
   green = (2*g + i) * 255 / 3;
   blue = (2*b + i) * 255 / 3;
   return (red, green, blue);
}

// return the (squared) Euclidean distance between two RGB colors
function color_distance(red_a, green_a, blue_a, red_b, green_b, blue_b) {
   d_red = red_a - red_b;
   d_green = green_a - green_b;
   d_blue = blue_a - blue_b;
   return (d_red * d_red) + (d_green * d_green) + (d_blue * d_blue);
}

// find the closest 4-bit RGBI approximation (by Euclidean distance) to a 24-bit RGB color
function rgbi_approx(red, green, blue) {
    // find best RGB0 and RGB1 approximations:
    (r0, g0, b0) = rgbx_approx(red, green, blue, 0);
    (r1, g1, b1) = rgbx_approx(red, green, blue, 1);

    // convert them back to 24-bit RGB:
    (red0, green0, blue0) = rgbi_to_rgb24(r0, g0, b0, 0);
    (red1, green1, blue1) = rgbi_to_rgb24(r1, g1, b1, 1);

    // return the color closer to the original:
    d0 = color_distance(red, green, blue, red0, green0, blue0);
    d1 = color_distance(red, green, blue, red1, green1, blue1);

    if (d0 <= d1) return (r0, g0, b0, 0);
    else return (r1, g1, b1, 1);
}

Alternatively, you could simply use any generic fixed-palette color quantization algorithm. This may yield better results if your actual color palette is not a pure evenly spaced RGBI palette like the code above assumes, but rather something like e.g. the CGA tweaked RGBI palette.

Upvotes: 3

Related Questions