RGB 24位转16位颜色转换 - 颜色变暗

4
我发现我的将RGB888 24位转换为16位RGB565的程序每次转换时颜色都会逐渐变暗...该公式使用线性插值如下所示...
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);

从16位到24位的转换类似,但是需要反向插值...如果它们是相反的,我不明白为什么每次通过方程循环颜色时值都会越来越低...最初没有将其转换为double类型,但是我认为如果我将其作为浮点数除法,则不会出现衰减...但它仍然存在...

5个回答

4

不要在像这样简单的事情上使用浮点数。我看到的正常方式是在向下转换时截断,但在向上转换时扩展(因此0b11111变成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

4
当您将双精度浮点数转换为WORD时,会截断值。例如,(126 * 31)/255 = 15.439,但被截断为15。由于值被截断,它们在每次迭代中逐渐变小。因此,您需要引入四舍五入(在将它们转换为整数之前加上0.5)。
继续上面的例子,然后取15并转换回来: (15 * 255)/31 = 123.387,但仅保留整数部分得到123。

1

我知道,但是在转换之后,它似乎会保持一个稳定的值,但是再次转换信息时又变暗了...再次转换又变暗了...再次转换又变暗了...等等。 - oldSkool
换句话说,如果我将16位颜色转换为24位颜色,不做任何修改,然后将其转换回16位,它比原始颜色暗。 - oldSkool
@user482910:我意识到了。我已经编辑了我的帖子并添加了更多信息。 - In silico

0

这是因为16位使用乘以2的值,例如2*2*2*2,结果将以rrggbb形式呈现。在32位情况下,它会将整个位值乘以2。

简而言之,16位、24位和32位通过rgb乘以2来工作,并以颜色形式显示值。
简要概述一下,您应该找到有关位颜色的概念。在维基百科上查看,希望能帮到您。


这是一个舍入问题,而不是位掩码问题。 - oldSkool

0

既然你要转换为double,那么至少使用它来避免溢出,即替换

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

使用

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

这样编译器也应该将31.0/255.0折叠成常量。

显然,如果需要对大量像素进行重复操作,最好创建和使用查找表(lookup table)。


我忘了提到同样适用于反向变换。 - CAFxX

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接