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

时间:2012-06-13 03:53:52

标签: c++ qt

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

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

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

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

1 个答案:

答案 0 :(得分:8)

事先我想提一下两个转换函数中的组件顺序是不一样的。在565 - &gt;在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 );
}

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

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

请注意,您可以使用现有的(内联)函数qRedqGreenqBlue进行类似于qRgb的组件提取,以便从组件进行颜色构建。

另请注意,RGB888ToRGB565中的最终位掩码是可选的,因为元件值在8位范围内,您可以先右移,然后左移这些值。