为什么多次将RGB888转换为RGB565会导致颜色损失?

pau*_*ulm 0 c++ qt

如果我使用Qt执行以下操作:

  1. 在QImage :: Format_RGB32中加载位图.
  2. 将其像素转换为RGB565(没有Qt格式,所以我必须"手动").
  3. 创建一个与步骤1中加载的位图大小相同的新位图.
  4. 将RGB565缓冲区像素转换回RGB88,进入步骤3中创建的图像.
  5. 从步骤4创建的图像看起来像步骤1中的图像,但是如果比较RGB值,它们就不完全相同.

重复步骤2到5会导致最终图像失去颜色 - 它似乎变得更暗和更暗.

这是我的转换功能:

qRgb RGB565ToRGB888( unsigned short int aTextel )
{
    unsigned char r = (((aTextel)&0x01F) <<3);
    unsigned char g = (((aTextel)&0x03E0) >>2);
    unsigned char b = (((aTextel)&0x7C00 )>>7);
    return qRgb( r, g, b, 255 );
}

unsigned short int RGB888ToRGB565( QRgb aPixel )
{
    int red = ( aPixel >> 16) & 0xFF;
    int green = ( aPixel >> 8 ) & 0xFF;
    int blue =  aPixel & 0xFF;

    unsigned short  B = (blue >> 3) & 0x001F;
    unsigned short  G = ((green >> 2) < 5) & 0x07E0;
    unsigned short  R = ((red >> 3) < 11) & 0xF800;

    return (unsigned short int) (R | G | B);
}
Run Code Online (Sandbox Code Playgroud)

我从我的测试图像中找到的一个不能正确转换的例子是4278192128,它从RGB565转换回RGB888为4278190080.

编辑:我还应该提到原始源数据是RGB565(我的测试RGB888图像是从中创建的).我只是转换为RGB888用于显示目的,但之后想转换回RGB565而不是保留两份数据.

lee*_*mes 8

事先我想提一下两个转换函数中的组件顺序是不一样的.在565 - > 888转换中,您假设红色分量使用低位(0x001F),但在对红色分量的5位进行编码时,将它们置于高位(0xF800).假设您想要一个类似于0xAARRGGBB(RGB565中的二进制表示0bRRRRRGGGGGGBBBBB)的组件顺序,则需要更改方法中的变量名称RGB565ToRGB888.我在下面的代码中解决了这个问题.

您的RGB565到RGB888转换是错误的.对于绿色通道,您提取5位,结果只能为7位而不是8位.对于蓝色通道,您采用以下位,这是一个重大错误.这应该解决它:

QRgb RGB565ToRGB888( unsigned short int aTextel )
{
    // changed order of variable names
    unsigned char b = (((aTextel)&0x001F) << 3);
    unsigned char g = (((aTextel)&0x07E0) >> 3); // Fixed: shift >> 5 and << 2
    unsigned char r = (((aTextel)&0xF800) >> 8); // shift >> 11 and << 3
    return qRgb( r, g, b, 255 );
}
Run Code Online (Sandbox Code Playgroud)

在另一个函数中,您不小心写了少于运算符而不是左移运算符.这应该解决它:

unsigned short int RGB888ToRGB565( QRgb aPixel )
{
    int red   = ( aPixel >> 16) & 0xFF;  // why not qRed(aPixel) etc. ?
    int green = ( aPixel >> 8 ) & 0xFF;
    int blue  =   aPixel        & 0xFF;

    unsigned short  B =  (blue  >> 3)        & 0x001F;
    unsigned short  G = ((green >> 2) <<  5) & 0x07E0; // not <
    unsigned short  R = ((red   >> 3) << 11) & 0xF800; // not <

    return (unsigned short int) (R | G | B);
}
Run Code Online (Sandbox Code Playgroud)

请注意,您可以使用已有的(内置)功能qRed,qGreen,qBlue对于成分提取类似于qRgb从分量的彩色建筑.

另请注意,最终的位掩码RGB888ToRGB565是可选的,因为组件值在8位范围内,您先通过右侧裁剪它们,然后左移这些值.