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

发布于 2024-10-02 03:05:19 字数 936 浏览 1 评论 0原文

我注意到我在 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 位到 16 位的转换24 位类似,但具有反向插值...我不明白每次颜色在方程中循环时,如果它们是相反的,值如何变得越来越低...最初没有强制转换为双倍,但是我想如果我把它做成浮点除法,它就不会产生衰减......但它仍然存在......

I noticed that my routine to convert between RGB888 24-bit to 16-bit RGB565 resulted in darkening of the colors progressively each time a conversion took place... The formula uses linear interpolation like so...

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

The conversion from 16-bit to 24-bit is similar but with reverse interpolation... I don't understand how the values keep getting lower and lower each time a color is cycled through the equation if they are opposites... Originally there was no cast to double, but I figured if I made it a floating point divide it would not have the falloff... but it still does...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

吃颗糖壮壮胆 2024-10-09 03:05:19

当您将双精度值转换为 WORD 时,这些值将被截断。例如,
(126 * 31)/ 255 = 15.439,被截断为 15。由于值被截断,因此它们在每次迭代中逐渐变低。您需要引入舍入(在将计算值转换为整数之前将其添加 0.5)

继续该示例,然后取 15 并转换回来:
(15 * 255)/31 = 123.387 截断为 123

When you convert your double values to WORD, the values are being truncated. For example,
(126 * 31)/ 255 = 15.439, which is truncated to 15. Because the values are truncated, they get progressively lower through each iteration. You need to introduce rounding (by adding 0.5 to the calculated values before converting them to integers)

Continuing the example, you then take 15 and convert back:
(15 * 255)/31 = 123.387 which truncates to 123

一场信仰旅途 2024-10-09 03:05:19

不要将浮点用于像这样简单的事情。我见过的正常方法是在下转换时截断,但在上转换时扩展(因此 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

Don't use floating point for something simple like this. Normal way I've seen is to truncate on the down-conversion but extend on the up-conversion (so 0b11111 goes to 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
潇烟暮雨 2024-10-09 03:05:19

double 转换为 WORD 不会对 double 值进行四舍五入 - 它会截断十进制数字。您需要使用某种舍入例程来获得舍入行为。通常,您需要将一半舍入为偶数Stack Overflow 上有一个关于如何在需要时在 C++ 中进行舍入的问题


另请注意,从 24 位到 16 位的转换会永久丢失信息。当然,不可能将 24 位信息装入 16 位信息。您无法通过从 16 位转换回 24 位来恢复它。

Casting double to WORD doesn't round the double value - it truncates the decimal digits. You need to use some kind of rounding routine to get rounding behavior. Typically you want to round half to even. There is a Stack Overflow question on how to round in C++ if you need it.


Also note that the conversion from 24 bit to 16 bits permanently loses information. It's impossible to fit 24 bits of information into 16 bits, of course. You can't get it back by conversion from 16 bits back to 24 bits.

流绪微梦 2024-10-09 03:05:19

这是因为 16 位适用于乘以 2 的值
2*2*2*2,它将显示为 rrggbb,在相同的 32 位情况下,它将把整个位值乘以 2。

简而言之,16 位、24 位、32 位将 rgb 与 2 相乘,并显示值以颜色的形式。
简而言之,您应该找到位颜色的概念。查一下维基百科希望对你有帮助

it is because 16 bit works with the values multiplied with 2 for example
2*2*2*2 and it will come out as rrggbb and in same 32 bit case it will multiply the whole bit values with 2.

in short 16 bit 24 bit 32 bit works with multiplication of rgb with 2 and shows you the values in form of color.
for brief u should find the concept of bit color. check it on Wikipedia hope it will help you

冷情妓 2024-10-09 03:05:19

既然你无论如何都要转换为 double,至少使用它来避免溢出,即以这种方式替换

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

为,

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

编译器也应该将 31.0/255.0 折叠在常量中。

显然,如果必须对大量像素重复此操作,则最好创建并使用 LUT(查找表)。

Since you're converting to double anyway, at least use it to avoid overflow, i.e. replace

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

with

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

in this way the compiler should also fold 31.0/255.0 in a costant.

Obviously if this has to be repeated for huge quantities of pixels, it would be preferable to create and use a LUT (lookup table) instead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文