RGB888转RGB565

 

今天在REVIEW代码的时候,发现了这样一个宏定义:

#define COLOR_TO_MTK_COLOR_SIMUL(color) ((((color) >> 19) & 0x1f) << 11) \
                                            |((((color) >> 10) & 0x3f) << 5) \
                                            |(((color) >> 3) & 0x1f)

大家知道这个宏是用来干什么的吗?

仔细分析后,原来就是实现了RGB888到RGB565的转换,查阅相关资料后,发现网络上有一篇牛人写的东东,在此和大家分享。

讲一下量化压缩与量化补偿吧

  在进行色彩格式转换的时候,经常会遇到色彩量化位数的改变,比如说从 24bit RGB888 到 16bit RGB565 的色彩转换。所谓量化压缩与量化补偿都是我个人所提出的概念,现说明如下。

  量化压缩,举例:

  24bit RGB888 -> 16bit RGB565 的转换

  24ibt RGB888 R7 R6 R5 R4 R3 R2 R1 R0 G7 G6 G5 G4 G3 G2 G1 G0 B7 B6 B5 B4 B3 B2 B1 B0

  16bit RGB656 R7 R6 R5 R4 R3 G7 G6 G5 G4 G3 G2 B7 B6 B5 B4 B3

  量化位数从8bit到5bit或6bit,取原8bit的高位,量化上做了压缩,却损失了精度。

  量化补偿,举例:

  16bit RGB565 -> 24bit RGB888 的转换

  16bit RGB656 R4 R3 R2 R1 R0 G5 G4 G3 G2 G1 G0 B4 B3 B2 B1 B0

  24ibt RGB888 R4 R3 R2 R1 R0 0 0 0 G5 G4 G3 G2 G1 G0 0 0 B4 B3 B2 B1 B0 0 0 0

  24ibt RGB888 R4 R3 R2 R1 R0 R2 R1 R0 G5 G4 G3 G2 G1 G0 G1 G0 B4 B3 B2 B1 B0 B2 B1 B0

  说明:第二行的 24bit RGB888 数据为转换后,未进行补偿的数据,在精度上会有损失

  第三行的 24bit RGB888 数据为经过量化补偿的数据,对低位做了量化补偿

  可以很容易的证明,这样的补偿方法是一种合理的线性补偿。补偿的原理很简单,大家仔细想一下就明白了,因此不再详细说明。

  总结一下:

  量化压缩的方法:三个字取高位

  量化补偿的方法:

  1. 将原数据填充至高位

  2. 对于低位,用原始数据的低位进行补偿

  3. 如果仍然有未填充的位,继续使用原始数据的低位进行循环补偿

  解释一下循环补偿的概念:

  8bit RGB332 -> 24bit RGB888 的转换

  8bit RGB332 R2 R1 R0 G2 G1 G0 B1 B0

  24bit RGB888 R2 R1 R0 0 0 0 0 0 G2 G1 G0 0 0 0 0 0 B1 B0 0 0 0 0 0 0

  24bit RGB888 R2 R1 R0 R2 R1 R0 0 0 G2 G1 G0 G2 G1 G0 0 0 B1 B0 B1 B0 0 0 0 0

  24bit RGB888 R2 R1 R0 R2 R1 R0 R2 R1 G2 G1 G0 G2 G1 G0 G2 G1 B1 B0 B1 B0 B1 B0 0 0

  24bit RGB888 R2 R1 R0 R2 R1 R0 R2 R1 G2 G1 G0 G2 G1 G0 G2 G1 B1 B0 B1 B0 B1 B0 B1 B0

  看了这个,应该明白则么回事了吧,其中B分量,进行了四轮的补偿,达到要求。

  量化补偿的必要性,从直觉上讲,我所提出的这种补偿方法是正确的(因为我并没有严格的去证明),进行这样的补偿,在做色彩各式转换的时候,能够明显的改善色彩效果,减少精度上的损失。

 bitmap图片是一个RGB888,每个像素由3个字节组成,R->8bit,G->8bit,B->8bit;

  RGB565 的每个pixels是由2字节组成,R->5bit,G->6bit,B->5bit。

转换的思路是取出原图的点,对没个采样进行运算。

#define RGB565_MASK_RED        0xF800   
  1. #define RGB565_MASK_GREEN                         0x07E0   
  2. #define RGB565_MASK_BLUE                         0x001F   
  3.   
  4. void rgb565_2_rgb24(BYTE *rgb24, WORD rgb565)  
  5. {   
  6.  //extract RGB   
  7.  rgb24[2] = (rgb565 & RGB565_MASK_RED) >> 11;     
  8.  rgb24[1] = (rgb565 & RGB565_MASK_GREEN) >> 5;  
  9.  rgb24[0] = (rgb565 & RGB565_MASK_BLUE);  
  10.   
  11.  //amplify the image   
  12.  rgb24[2] <<= 3;  
  13.  rgb24[1] <<= 2;  
  14.  rgb24[0] <<= 3;  
  15. }   
  1. #define RGB565_MASK_RED        0xF800   
  2. #define RGB565_MASK_GREEN                         0x07E0   
  3. #define RGB565_MASK_BLUE                         0x001F   
  4.   
  5. void rgb565_2_rgb24(BYTE *rgb24, WORD rgb565)  
  6. {   
  7.  //extract RGB   
  8.  rgb24[2] = (rgb565 & RGB565_MASK_RED) >> 11;     
  9.  rgb24[1] = (rgb565 & RGB565_MASK_GREEN) >> 5;  
  10.  rgb24[0] = (rgb565 & RGB565_MASK_BLUE);  
  11.   
  12.  //amplify the image   
  13.  rgb24[2] <<= 3;  
  14.  rgb24[1] <<= 2;  
  15.  rgb24[0] <<= 3;  
  16. }   

  1. USHORT rgb_24_2_565(int r, int g, int b)  
  2. {  
  3.     return (USHORT)(((unsigned(r) << 8) & 0xF800) |   
  4.             ((unsigned(g) << 3) & 0x7E0)  |  
  5.             ((unsigned(b) >> 3)));  
  6. }  
  1. USHORT rgb_24_2_565(int r, int g, int b)  
  2. {  
  3.     return (USHORT)(((unsigned(r) << 8) & 0xF800) |   
  4.             ((unsigned(g) << 3) & 0x7E0)  |  
  5.             ((unsigned(b) >> 3)));  
  6. }  

USHORT rgb_24_2_555(int r, int g, int b)  
  1. {  
  2.     return (USHORT)(((unsigned(r) << 7) & 0x7C00) |   
  3.             ((unsigned(g) << 2) & 0x3E0)  |  
  4.             ((unsigned(b) >> 3)));  
  5. }  
  6.   
  7. COLORREF rgb_555_2_24(int rgb555)  
  8. {  
  9.     unsigned r = ((rgb555 >> 7) & 0xF8);  
  10.     unsigned g = ((rgb555 >> 2) & 0xF8);  
  11.     unsigned b = ((rgb555 << 3) & 0xF8);  
  12.     return RGB(r,g,b);  
  13. }  
  14.   
  15. void rgb_555_2_bgr24(BYTE* p, int rgb555)  
  16. {  
  17.     p[0] = ((rgb555 << 3) & 0xF8);  
  18.     p[1] = ((rgb555 >> 2) & 0xF8);  
  19.     p[2] = ((rgb555 >> 7) & 0xF8);  
  20. }  
 
  1. USHORT rgb_24_2_555(int r, int g, int b)  
  2. {  
  3.     return (USHORT)(((unsigned(r) << 7) & 0x7C00) |   
  4.             ((unsigned(g) << 2) & 0x3E0)  |  
  5.             ((unsigned(b) >> 3)));  
  6. }  
  7.   
  8. COLORREF rgb_555_2_24(int rgb555)  
  9. {  
  10.     unsigned r = ((rgb555 >> 7) & 0xF8);  
  11.     unsigned g = ((rgb555 >> 2) & 0xF8);  
  12.     unsigned b = ((rgb555 << 3) & 0xF8);  
  13.     return RGB(r,g,b);  
  14. }  
  15.   
  16. void rgb_555_2_bgr24(BYTE* p, int rgb555)  
  17. {  
  18.     p[0] = ((rgb555 << 3) & 0xF8);  
  19.     p[1] = ((rgb555 >> 2) & 0xF8);  
  20.     p[2] = ((rgb555 >> 7) & 0xF8);  
  21. }  

 

#define RGB565_Val(r,g,b) (WORD)((r)<<11 | (g)<<5 | (b))   
  1. WORD rgb555_2_rgb565(WORD rgb555)  
  2. {  
  3.    BYTE r,g,b;  
  4.    FLOAT fRate = 63/31;  
  5.    //Get R G B    
  6.    r = (BYTE)(((rgb555 >> 7) & 0xF8)>>3);  
  7.    g = (BYTE)((((rgb555 >> 2) & 0xF8)>>3)*fRate);  
  8.    b = (BYTE)(((rgb555 << 3) & 0xF8)>>3);  
  9.    *(WORD *)pDest = RGB565_Val(RDest,GDest,BDest);  
### 将RGB888格式换为RGB565格式的方法 RGB888是一种每种颜色(红、绿、蓝)占用8位的色彩表示方式,而RGB565则是红色占5位、绿色占6位、蓝色占5位的一种压缩形式。为了将RGB888换为RGB565,需要提取原始RGB值中的高有效位并将其重新组合。 以下是具体的实现方法: #### 换逻辑 1. 提取RGB888中各颜色分量的高有效位。 2. 对这些高有效位进行移位操作以便适配RGB565的颜色分布。 3. 使用按位或运算符`|`将三个颜色分量拼接成最终的16位数值。 具体代码如下所示: ```c unsigned short RGB888ToRGB565(unsigned int n888Color) { unsigned short n565Color = 0; // 获取RGB单色,并截取高位 unsigned char cRed = (n888Color & 0x00ff0000) >> 19; unsigned char cGreen = (n888Color & 0x0000ff00) >> 10; unsigned char cBlue = (n888Color & 0x000000ff) >> 3; // 连接 n565Color = (cRed << 11) | (cGreen << 5) | (cBlue); return n565Color; } ``` 此函数接受一个代表RGB888颜色的32位整数作为输入参数 `n888Color`,并通过一系列位操作计算出对应的RGB565颜色值[^2]。 #### 测试示例 假设有一个RGB888颜色值 `(255, 255, 255)` 表示白色,则可以调用上述函数来获取其RGB565版本: ```c int main() { unsigned int rgb888 = 0xFFFFFF; // 白色 unsigned short rgb565 = RGB888ToRGB565(rgb888); printf("RGB888: %X -> RGB565: %X\n", rgb888, rgb565); return 0; } ``` 运行该测试代码会打印出相应的十六进制结果,验证换过程是否正确[^2]。 --- #### JavaScript 实现 如果希望在JavaScript环境中完成同样的功能,也可以采用类似的算法: ```javascript function RGB888_to_RGB565(color) { let r = (color >> 16) & 0xFF; // Extract Red component let g = (color >> 8) & 0xFF; // Extract Green component let b = color & 0xFF; // Extract Blue component // Shift down to fit into 5/6 bits and combine them together. let red = (r >> 3) << 11; let green = (g >> 2) << 5; let blue = (b >> 3); return red | green | blue; } // Example usage: let rgb888 = 0xFFFFFF; // White color console.log(`RGB888: ${rgb888.toString(16)} -> RGB565: ${RGB888_to_RGB565(rgb888).toString(16)}`); ``` 这段脚本同样实现了从RGB888RGB565变,并通过简单的控制台输出展示效果[^3]。 --- ### 注意事项 - 在实际应用中需注意端序问题(Little Endian vs Big Endian),这可能影响二进制数据存储顺序从而改变读写行为。 - 如果源图像较大,在批量处理像素时应考虑性能优化措施如SIMD指令集加速等技术手段提升效率。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值