2010-11-09 21 views
2

J'ai remarqué que ma routine de conversion entre RGB888 24 bits et 16 bits RGB565 entraînait un assombrissement progressif des couleurs à chaque conversion ... La formule utilise une interpolation linéaire comme si ...RGB Conversion de couleurs de 24 à 16 bits - Les couleurs s'assombrissent

typedef struct _RGB24 RGB24; 
struct _RGB24 { 
    BYTE B; 
    BYTE G; 
    BYTE R; 
}; 

RGB24 *s; // source 
WORD *d; // destination 
WORD r; 
WORD g; 
WORD b; 

// Code to convert from 24-bit to 16 bit 
r = (WORD)((double)(s[x].r * 31)/255.0); 
g = (WORD)((double)(s[x].g * 63)/255.0); 
b = (WORD)((double)(s[x].b * 31)/255.0); 
d[x] = (r << REDSHIFT) | (g << GREENSHIFT) | (b << BLUESHIFT); 

// Code to convert from 16-bit to 24-bit 
s[x].r = (BYTE)((double)(((d[x] & REDMASK) >> REDSHIFT) * 255)/31.0); 
s[x].g = (BYTE)((double)(((d[x] & GREENMASK) >> GREENSHIFT) * 255)/63.0); 
s[x].b = (BYTE)((double)(((d[x] & BLUEMASK) >> BLUESHIFT) * 255)/31.0); 

La conversion de 16 bits à 24 bits est similaire, mais avec une interpolation inverse ... Je ne comprends pas comment les valeurs continuent en plus bas chaque fois qu'un la couleur est cyclée à travers l'équation si elles sont opposées ... A l'origine il n'y avait pas de distribution à doubler, mais je me suis dit que si je l'avais fait un point flottant, je n'aurais pas la retombée ...

Répondre

3

Lorsque vous convertissez vos valeurs doubles en MOT, les valeurs sont tronquées. Par exemple, (126 * 31)/255 = 15.439, qui est tronqué à 15. Comme les valeurs sont tronquées, elles diminuent progressivement à chaque itération. Vous devez introduire l'arrondi (en ajoutant 0,5 aux valeurs calculées avant de les convertir en nombres entiers)

Reprenons l'exemple, vous prenez alors 15 et reconvertir: (15 * 255)/31 = 123,387 qui tronque à 123

+0

Cool ... laissez-moi essayer ... merci pour l'idée – oldSkool

1

La diffusion double à WORD n'atteint pas la valeur double - elle tronque les chiffres décimaux. Vous devez utiliser une routine d'arrondi pour obtenir un comportement arrondi. Généralement, vous voulez round half to even. There is a Stack Overflow question on how to round in C++ if you need it.


Notez également que la conversion de 24 bits en 16 bits perd définitivement de l'information. Il est impossible d'insérer 24 bits d'information dans 16 bits, bien sûr. Vous ne pouvez pas le récupérer par conversion de 16 bits en 24 bits.

+0

Je sais, mais après la conversion, il semble qu'il resterait stable à une valeur, mais la conversion de l'information convertie à nouveau assombrit ... conversion qui assombrit à nouveau ... convertir qui assombrit à nouveau ... – oldSkool

+0

En d'autres termes, si je convertis une couleur de 16 bits en une couleur de 24 bits, ne la modifiez pas du tout, mais la convertissez en 16 bits, c'est plus sombre que l'original – oldSkool

+0

@ user482910: Je le réalise. J'ai modifié mon message avec plus d'informations. –

0

c'est parce que 16 bits fonctionne avec les valeurs multipliées par 2 par exemple 2 * 2 * 2 * 2 et sortira comme rrggbb et dans le même cas 32 bits, il multipliera l'ensemble des valeurs de bits avec 2.

en bref 16 bits 24 bits 32 bits fonctionne avec la multiplication de RVB avec 2 et vous montre les valeurs sous forme de couleur.
Bref, vous devriez trouver le concept de couleur de bit. vérifier sur Wikipedia espérons que cela vous aidera

+0

c'était un problème avec l'arrondissement, pas bitmasking – oldSkool

0

Puisque vous convertissez à doubler en tout cas, au moins l'utiliser pour éviter tout débordement, à savoir remplacer

r = (WORD)((double)(s[x].r * 31)/255.0); 

avec

r = (WORD)round(s[x].r/255.0 * 31.0); 

de cette façon le compilateur devrait également plier 31.0/255.0 dans un costant.

Évidemment, si cela doit être répété pour d'énormes quantités de pixels, il serait préférable de créer et d'utiliser une table de conversion (LUT) à la place. Ne pas utiliser le virgule flottante pour quelque chose de simple comme celui-ci:

+0

J'ai oublié de mentionner que la même chose s'applique également à la transformée inverse. – CAFxX

3

La façon normale que j'ai vu est de tronquer sur la conversion vers le bas mais de prolonger la conversion vers le haut (donc 0b11111 va à 0b11111111).

// Code to convert from 24-bit to 16 bit 
r = s[x].r >> (8-REDBITS); 
g = s[x].g >> (8-GREENBITS); 
b = s[x].b >> (8-BLUEBITS); 
d[x] = (r << REDSHIFT) | (g << GREENSHIFT) | (b << BLUESHIFT); 

// Code to convert from 16-bit to 24-bit 
s[x].r = (d[x] & REDMASK) >> REDSHIFT;      // 000abcde 
s[x].r = s[x].r << (8-REDBITS) | s[x].r >> (2*REDBITS-8);  // abcdeabc 
s[x].g = (d[x] & GREENMASK) >> GREENSHIFT;     // 00abcdef 
s[x].g = s[x].g << (8-GREENBITS) | s[x].g >> (2*GREENBITS-8); // abcdefab 
s[x].b = (d[x] & BLUEMASK) >> BLUESHIFT;      // 000abcde 
s[x].b = s[x].b << (8-BLUEBITS) | s[x].b >> (2*BLUEBITS-8); // abcdeabc