Honguito98
Honguito98

Reputation: 694

Find nearest RGB value using color palette array in C

I have some part of code done, but in some comparisons, nearest values are incorrectly. Example:

Correct:

Rgb value | Value from array
0xFFFFFD  = 0xFFFFFF

Incorrect: Fixed code

Rgb value | Value from array
0xF4F939  = 0xFF0000 (should be 0xFFFF00)

Console Output: (Correct)

C:\Users\honguito\Desktop\Bat\Game_Batch_Files\24_to_8_bitmap>24_to_8_bit_palett
e
The closest color of 0xFFFFFD is: '0xFFFFFF'

C:\Users\honguito\Desktop\Bat\Game_Batch_Files\24_to_8_bitmap>

Console Output: (Incorrect)

C:\Users\honguito\Desktop\Bat\Game_Batch_Files\24_to_8_bitmap>24_to_8_bit_palett
e
The closest color of 0xF4F939 is: '0xFF0000'

C:\Users\honguito\Desktop\Bat\Game_Batch_Files\24_to_8_bitmap>

Those RGB color code are listed in an array:

int data[] = {
    0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080,
    0xC0C0C0, 0xC0DCC0, 0xA6CAF0, 0x402000, 0x602000, 0x802000, 0xA02000,
    0xC02000, 0xE02000, 0x004000, 0x204000, 0x404000, 0x604000, 0x804000,
    0xA04000, 0xC04000, 0xE04000, 0x006000, 0x206000, 0x406000, 0x606000,
    0x806000, 0xA06000, 0xC06000, 0xE06000, 0x008000, 0x208000, 0x408000,
    0x608000, 0x808000, 0xA08000, 0xC08000, 0xE08000, 0x00A000, 0x20A000,
    0x40A000, 0x60A000, 0x80A000, 0xA0A000, 0xC0A000, 0xE0A000, 0x00C000,
    0x20C000, 0x40C000, 0x60C000, 0x80C000, 0xA0C000, 0xC0C000, 0xE0C000,
    0x00E000, 0x20E000, 0x40E000, 0x60E000, 0x80E000, 0xA0E000, 0xC0E000,
    0xE0E000, 0x000040, 0x200040, 0x400040, 0x600040, 0x800040, 0xA00040,
    0xC00040, 0xE00040, 0x002040, 0x202040, 0x402040, 0x602040, 0x802040,
    0xA02040, 0xC02040, 0xE02040, 0x004040, 0x204040, 0x404040, 0x604040,
    0x804040, 0xA04040, 0xC04040, 0xE04040, 0x006040, 0x206040, 0x406040,
    0x606040, 0x806040, 0xA06040, 0xC06040, 0xE06040, 0x008040, 0x208040,
    0x408040, 0x608040, 0x808040, 0xA08040, 0xC08040, 0xE08040, 0x00A040,
    0x20A040, 0x40A040, 0x60A040, 0x80A040, 0xA0A040, 0xC0A040, 0xE0A040,
    0x00C040, 0x20C040, 0x40C040, 0x60C040, 0x80C040, 0xA0C040, 0xC0C040,
    0xE0C040, 0x00E040, 0x20E040, 0x40E040, 0x60E040, 0x80E040, 0xA0E040,
    0xC0E040, 0xE0E040, 0x000080, 0x200080, 0x400080, 0x600080, 0x800080,
    0xA00080, 0xC00080, 0xE00080, 0x002080, 0x202080, 0x402080, 0x602080,
    0x802080, 0xA02080, 0xC02080, 0xE02080, 0x004080, 0x204080, 0x404080,
    0x604080, 0x804080, 0xA04080, 0xC04080, 0xE04080, 0x006080, 0x206080,
    0x406080, 0x606080, 0x806080, 0xA06080, 0xC06080, 0xE06080, 0x008080,
    0x208080, 0x408080, 0x608080, 0x808080, 0xA08080, 0xC08080, 0xE08080,
    0x00A080, 0x20A080, 0x40A080, 0x60A080, 0x80A080, 0xA0A080, 0xC0A080,
    0xE0A080, 0x00C080, 0x20C080, 0x40C080, 0x60C080, 0x80C080, 0xA0C080,
    0xC0C080, 0xE0C080, 0x00E080, 0x20E080, 0x40E080, 0x60E080, 0x80E080,
    0xA0E080, 0xC0E080, 0xE0E080, 0x0000C0, 0x2000C0, 0x4000C0, 0x6000C0,
    0x8000C0, 0xA000C0, 0xC000C0, 0xE000C0, 0x0020C0, 0x2020C0, 0x4020C0,
    0x6020C0, 0x8020C0, 0xA020C0, 0xC020C0, 0xE020C0, 0x0040C0, 0x2040C0,
    0x4040C0, 0x6040C0, 0x8040C0, 0xA040C0, 0xC040C0, 0xE040C0, 0x0060C0,
    0x2060C0, 0x4060C0, 0x6060C0, 0x8060C0, 0xA060C0, 0xC060C0, 0xE060C0,
    0x0080C0, 0x2080C0, 0x4080C0, 0x6080C0, 0x8080C0, 0xA080C0, 0xC080C0,
    0xE080C0, 0x00A0C0, 0x20A0C0, 0x40A0C0, 0x60A0C0, 0x80A0C0, 0xA0A0C0,
    0xC0A0C0, 0xE0A0C0, 0x00C0C0, 0x20C0C0, 0x40C0C0, 0x60C0C0, 0x80C0C0,
    0xA0C0C0, 0xFFFBF0, 0xA0A0A4, 0x808080, 0xFF0000, 0x00FF00, 0xFFFF00,
    0x0000FF, 0xFF00FF, 0x00FFFF, 0xFFFFFF
};

Then to get the nearest number I do:

nearest = findKey(data, pcolor);

And this is the complete code:

#include <stdio.h>

int main () {

    //int pcolor = 0xF4F939;
    int pcolor = 0xFFFFFD;
    //int pcolor = 0x700000;
    //int pcolor = 0x21A0C0;
    int cmp[256];
    int cmp2[256];
    int data[] = {
        0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080,
        0xC0C0C0, 0xC0DCC0, 0xA6CAF0, 0x402000, 0x602000, 0x802000, 0xA02000,
        0xC02000, 0xE02000, 0x004000, 0x204000, 0x404000, 0x604000, 0x804000,
        0xA04000, 0xC04000, 0xE04000, 0x006000, 0x206000, 0x406000, 0x606000,
        0x806000, 0xA06000, 0xC06000, 0xE06000, 0x008000, 0x208000, 0x408000,
        0x608000, 0x808000, 0xA08000, 0xC08000, 0xE08000, 0x00A000, 0x20A000,
        0x40A000, 0x60A000, 0x80A000, 0xA0A000, 0xC0A000, 0xE0A000, 0x00C000,
        0x20C000, 0x40C000, 0x60C000, 0x80C000, 0xA0C000, 0xC0C000, 0xE0C000,
        0x00E000, 0x20E000, 0x40E000, 0x60E000, 0x80E000, 0xA0E000, 0xC0E000,
        0xE0E000, 0x000040, 0x200040, 0x400040, 0x600040, 0x800040, 0xA00040,
        0xC00040, 0xE00040, 0x002040, 0x202040, 0x402040, 0x602040, 0x802040,
        0xA02040, 0xC02040, 0xE02040, 0x004040, 0x204040, 0x404040, 0x604040,
        0x804040, 0xA04040, 0xC04040, 0xE04040, 0x006040, 0x206040, 0x406040,
        0x606040, 0x806040, 0xA06040, 0xC06040, 0xE06040, 0x008040, 0x208040,
        0x408040, 0x608040, 0x808040, 0xA08040, 0xC08040, 0xE08040, 0x00A040,
        0x20A040, 0x40A040, 0x60A040, 0x80A040, 0xA0A040, 0xC0A040, 0xE0A040,
        0x00C040, 0x20C040, 0x40C040, 0x60C040, 0x80C040, 0xA0C040, 0xC0C040,
        0xE0C040, 0x00E040, 0x20E040, 0x40E040, 0x60E040, 0x80E040, 0xA0E040,
        0xC0E040, 0xE0E040, 0x000080, 0x200080, 0x400080, 0x600080, 0x800080,
        0xA00080, 0xC00080, 0xE00080, 0x002080, 0x202080, 0x402080, 0x602080,
        0x802080, 0xA02080, 0xC02080, 0xE02080, 0x004080, 0x204080, 0x404080,
        0x604080, 0x804080, 0xA04080, 0xC04080, 0xE04080, 0x006080, 0x206080,
        0x406080, 0x606080, 0x806080, 0xA06080, 0xC06080, 0xE06080, 0x008080,
        0x208080, 0x408080, 0x608080, 0x808080, 0xA08080, 0xC08080, 0xE08080,
        0x00A080, 0x20A080, 0x40A080, 0x60A080, 0x80A080, 0xA0A080, 0xC0A080,
        0xE0A080, 0x00C080, 0x20C080, 0x40C080, 0x60C080, 0x80C080, 0xA0C080,
        0xC0C080, 0xE0C080, 0x00E080, 0x20E080, 0x40E080, 0x60E080, 0x80E080,
        0xA0E080, 0xC0E080, 0xE0E080, 0x0000C0, 0x2000C0, 0x4000C0, 0x6000C0,
        0x8000C0, 0xA000C0, 0xC000C0, 0xE000C0, 0x0020C0, 0x2020C0, 0x4020C0,
        0x6020C0, 0x8020C0, 0xA020C0, 0xC020C0, 0xE020C0, 0x0040C0, 0x2040C0,
        0x4040C0, 0x6040C0, 0x8040C0, 0xA040C0, 0xC040C0, 0xE040C0, 0x0060C0,
        0x2060C0, 0x4060C0, 0x6060C0, 0x8060C0, 0xA060C0, 0xC060C0, 0xE060C0,
        0x0080C0, 0x2080C0, 0x4080C0, 0x6080C0, 0x8080C0, 0xA080C0, 0xC080C0,
        0xE080C0, 0x00A0C0, 0x20A0C0, 0x40A0C0, 0x60A0C0, 0x80A0C0, 0xA0A0C0,
        0xC0A0C0, 0xE0A0C0, 0x00C0C0, 0x20C0C0, 0x40C0C0, 0x60C0C0, 0x80C0C0,
        0xA0C0C0, 0xFFFBF0, 0xA0A0A4, 0x808080, 0xFF0000, 0x00FF00, 0xFFFF00,
        0x0000FF, 0xFF00FF, 0x00FFFF, 0xFFFFFF
    };

    int nearIndex,nearest, result;

    nearest = findKey(data, pcolor);    
    printf("The closest color of 0x%X is: '0x%X'\n", pcolor, nearest);
    //system("pause");
}


int findKey(int Array1[], int key){
    int diff = abs( key - Array1[0]);
    int Num1 = 0;
    int Num2 = 0;
    for (int a = 0; a < 256; a++) {
            if (diff > abs( key - Array1[a] )) {
            diff = abs( key - Array1[a]);
            Num1 = Array1[a];
        }
    }
    return Num1;
    }

There are some unused variables and old code.

Any ideas?

Upvotes: 4

Views: 4010

Answers (2)

John Hascall
John Hascall

Reputation: 9416

I would think that using the 3-D distance formula would be a more accurate way to compute the 'nearest' color (since you only care about comparing, you can skip the sqrt() at the end).

dist_r = abs(r1 - r2);
dist_g = abs(g1 - g2);
dist_b = abs(b1 - b2);
dist_3d_sqd = (dist_r * dist_r) + (dist_g * dist_g) + (dist_b * dist_b

actually you can skip the abs() calls too, but putting them in makes it clearer, perhaps?

Upvotes: 3

Paolo
Paolo

Reputation: 15847

To find the "optical" closest color you have to estimate the difference between the color components of the two color you're comparing.

In order to do that you have to split the 24 bit value into 8 bit color components r, g, b.

Then you compare the components.

A naive method to do that is just sum the absolute value of the difference of the respective components.

More accurate formulas can be found googling, I guess.

// two colors to compare

int c1;
int c2;

// split c1 and c2 into their respective color components

r1 = c1 / 0x010000;
g1 = (c1 % 0x010000) / 0x00100;
b1 = c1 % 0x000100;

r2 = c2 / 0x010000;
g2 = (c2 % 0x010000) / 0x00100;
b2 = c2 % 0x000100;

// color "distance"

diff = abs( r1 - r2 ) + abs( g1 - g2 ) + abs ( b1 - b2 );

Upvotes: 4

Related Questions