Find nearest RGB value using color palette array in C

橙三吉。 提交于 2019-12-07 23:11:53

问题


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?


回答1:


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



回答2:


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?



来源:https://stackoverflow.com/questions/25612694/find-nearest-rgb-value-using-color-palette-array-in-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!