Advertisement

RGB565 与 RGB888的相互转换

阅读量:

本文内容不是完全原创,参考了网上部分精华,做了整理。

RGB色彩模式(也可译为"Red, Green, and Blue")是一种工业界广泛采用的颜色标准,在基于红(R)、绿(G)和蓝(B)颜色通道的基础上组成特定颜色的一种标准

红、绿、蓝三通道的变化与三者之间的叠加从而生成多种多样的颜色其中RGB代表红绿蓝三通道

现行标准基本涵盖了人类视力所能够感知的所有颜色,并成为目前被广泛应用的色彩体系。

就RGB888->RGB565而言:其转换的具体思路如下:(注:只代表个人的方法)
1.取RGB888中第一个字节的高5位作为转换后的RGB565的第二个字节的高5位
2.取RGB888中第二个字节的高3位作为转换后的RGB565第二个字节的低3位
3.取RGB888中第二个字节的第4--6位,作为转换后的RGB565第一个字节的高3位
4.取RGB888中第二个字节的第三个字节的高5位作为转换后的RGB565第一个字节的低5位
就RGB565->RGB888而言:
RGB565的存储方式为:
R4 R3 R2 R1 R0 G5 G4 G3 G2 G1 G0 B4 B3 B2 B1 B0
1.取RGB565第一个字节中低5位作为RGB888的高5位
2.取RGB565第二个字节中的低3位,将其左移5位,作为RGB888第二个字节的高5位
3.取RGB565第一个字节的高3位将其右移3位,作为RGB888第二个字节的4--6位
4.取RGB565第二个字节中的高5位作为RGB888第三个字节。

细心的人必然发现当我们从低位向高位进行数值提升时, 会不可避免地造成数据精度的损失

上网查阅了相关资料并参考了一些他人的方法;所谓量化补偿,请介绍一下其与量化压缩之间的关系吧

当处理色彩格式转换时

在RGB 565 16bit格式中进行色彩转换。其中量化压缩和量化补偿均为本人提出的概念。

量化压缩,举例:

将24位RGB 888格式的数据转换为16位RGB 565格式。
该变换过程涉及将R、G、B通道的数据分别映射至目标格式中相应的比特位置。
其中:

  • 原始数据中的R7-R0、G7-G0、B7-B0对应目标数据中的R7-R0、G7-G6、B7-B6;
  • 原始数据中的R3-R1和G3-G1对应目标数据中的R3-R1和G3-G2;
  • 原始数据中的B3对应目标数据中的B3。
    此方法通过减少比特深度实现了压缩效果。
    值得注意的是:
  • 在此过程中,
  • 将原始图像的高阶比特信息进行了舍弃,
  • 这种操作虽然降低了存储效率,
  • 却导致图像质量的下降,
  • 具体表现取决于如何合理分配比特资源。
    对于逆向过程:
  • 将目标图像的低阶比特扩展回高阶位置,
  • 这种操作被称为量化补偿。
    举个例子:
    假设我们有一个基于...的技术参数配置,
    其中:
    ...
    通过这种方法能够实现高质量图像的有效重建。

注释

这篇文章源自 驿落黄昏 博客页面,请确保此链接的正确性。

按照上面的图,我们大体知道了 RGB888 -> RGB565是怎么压缩的,也知道了RGB565- > RGB888

是具体如何进行补偿的呢?接下来我们将深入从代码实现的角度分析具体的转换方式。

代码:

(rr , gg, bb是属于byte类型,一字节大小)

(1) RGB565 -> RGB888

[java] [ view plain]( "view plain") copy

  1. rr = byte[1] & 0xf8;
  2. gg = (byte[1] << 5) | ((byte[0] & 0xe0) >> 3);
  3. bb = byte[0] << 3;
  4. // 补偿
  5. rr = rr | ((rr & 0x38) >> 3);
  6. gg = gg | ((gg & 0x0c) >> 2);
  7. bb = bb | ((bb & 0x38) >> 3);

另外一位大师的两种技巧...转自:[()

(2) RGB888 -> RGB555

[cpp] [ view plain]( "view plain") copy

for(int k = 0; k < abs(bmih.biHeight); k++) {
WORD pTemp = (WORD) pData;
pTemp += WIDTHBYTES(bmih.biWidth * 16) * k;
for(int i = 0; i < bmih.biWidth; i++) {
#if 1
*(pTemp++) = (((WORD)(pR++) << 8) & 0xf800) | (((WORD)(pG++) << 3) & 0x07e0) | (((WORD)(pB++) >> 3) & 0x001f);
#else
int nR = (*pR++ + 4) >> 3;
int nG = (*pG++ + 2) >> 2;
int nB = (*pB++ + 4) >> 3;
if(nR >31)nR=31; if(nG>63)nG=63;if(nB>31)nB=31;
*(pTemp++) = (nR <<11)|(nG<<5)|nB;
#endif
}
}

以下是另外的实现方式 ( 注意处理数据的类型)

复制代码
 #define RGB565_MASK_RED 0xF800

 #define RGB565_MASK_GREEN 0x07E0 
 #define RGB565_MASK_BLUE 0x001F 
 
    
 rgb5652rgb888  : 
 
    
 unsigned short *pRGB16 = (unsigned short *)lParam; 
 for(int i=0; i<176*144; i++) 
 { 
      unsigned short RGB16 = *pRGB16; 
      g_rgbbuf[i*3+2] = (RGB16&RGB565_MASK_RED) >> 11;   
      g_rgbbuf[i*3+1] = (RGB16&RGB565_MASK_GREEN) >> 5; 
      g_rgbbuf[i*3+0] = (RGB16&RGB565_MASK_BLUE); 
      g_rgbbuf[i*3+2] <<= 3; 
      g_rgbbuf[i*3+1] <<= 2; 
      g_rgbbuf[i*3+0] <<= 3; 
      pRGB16++; 
 }

另一种:

复制代码
 rgb5652rgb888(unsigned char *image,unsigned char *image888)

 { 
 unsigned char R,G,B; 
 B=(*image) & 0x1F;//000BBBBB 
 G=( *(image+1) << 3 ) & 0x38 + ( *image >> 5 ) & 0x07 ;//得到00GGGGGG00 
 R=( *(image+1) >> 3 ) & 0x1F; //得到000RRRRR 
 *(image888+0)=B * 255 / 63; // 把5bits映射到8bits去,自己可以优化一下算法,下同 
 *(image888+1)=G * 255 / 127; 
 *(image888+2)=R * 255 / 63; 
 }

本站文章除注明转载外均为 站内原创 或编译版本 欢迎任何方式 转录 请务请注明出处 尊重他人劳动 同学习 共成长

转载请注明:文章转载自: 罗索实验室 [ http://www.rosoo.net/a/201006/9669.html]

以下来自stackoverflow : http://stackoverflow.com/questions/2442576/how-does-one-convert-16-bit-rgb565-to-24-bit-rgb88

以下来自stackoverflow : http://stackoverflow.com/questions/2442576/the-conversion-process-involves-several-steps

复制代码
 R8 = ( R5 * 527 + 23 ) >> 6;

    
 G8 = ( G6 * 259 + 33 ) >> 6;
    
 B8 = ( B5 * 527 + 23 ) >> 6;
    
 
    
    
    AI写代码

This operation exclusively employs: MUL, ADD, and SHR instructions, rendering it exceptionally swift. On the contrary, this operation maintains a full compatibility with floating-point mappings, ensuring precise rounding.

复制代码
 // R8 = (int) floor( R5 * 255.0 / 31.0 + 0.5);

    
 // G8 = (int) floor( G6 * 255.0 / 63.0 + 0.5);
    
 // B8 = (int) floor( R5 * 255.0 / 31.0 + 0.5);
    
    
    
    
    AI写代码

Additionally, if you're looking for a specific solution for converting from 888 to 565, this proves highly effective.

复制代码
 R5 = ( R8 * 249 + 1014 ) >> 11;

    
 G6 = ( G8 * 253 +  505 ) >> 10;
    
 B5 = ( B8 * 249 + 1014 ) >> 11;
    
    
    
    
    AI写代码

(这组我看不懂,也没用过,但有人说是可用的,在此转给大家看看)

关于上面按比例转到8 bit的方法 ( 255 / 63 ), 我看到了另外一个实例,也转过来下:

复制代码
 #include <opencv2/core/core.hpp>

    
 #include <iostream>
    
  
    
 using namespace std;
    
 using namespace cv;
    
  
    
 #define RED_MASK 0xF800
    
 #define GREEN_MASK 0x07E0
    
 #define BLUE_MASK 0x001F
    
  
    
  
    
 int main(int argc, char* argv[])
    
 {
    
     IplImage *rgb565Image = cvCreateImage(cvSize(800, 480), IPL_DEPTH_16U, 1);
    
     IplImage *rgb888Image = cvCreateImage(cvSize(800, 480), IPL_DEPTH_8U, 3);
    
  
    
     unsigned short* rgb565Data = (unsigned short*)rgb565Image->imageData;
    
     int rgb565Step = rgb565Image->widthStep / sizeof(unsigned short);
    
  
    
     uchar* rgb888Data = (uchar*)rgb888Image->imageData;
    
  
    
     float factor5Bit = 255.0 / 31.0;
    
     float factor6Bit = 255.0 / 63.0;
    
  
    
     for(int i = 0; i < rgb565Image->height; i++)
    
     {
    
     for(int j = 0; j < rgb565Image->width; j++)
    
     {
    
         unsigned short rgb565 = rgb565Data[i*rgb565Step + j];
    
         uchar r5 = (rgb565 & RED_MASK)   >> 11;
    
         uchar g6 = (rgb565 & GREEN_MASK) >> 5;
    
         uchar b5 = (rgb565 & BLUE_MASK);
    
  
    
         // round answer to closest intensity in 8-bit space...
    
         uchar r8 = floor((r5 * factor5Bit) + 0.5);
    
         uchar g8 = floor((g6 * factor6Bit) + 0.5);
    
         uchar b8 = floor((b5 * factor5Bit) + 0.5);
    
  
    
         rgb888Data[i*rgb888Image->widthStep + j]       = r8;
    
         rgb888Data[i*rgb888Image->widthStep + (j + 1)] = g8;
    
         rgb888Data[i*rgb888Image->widthStep + (j + 2)] = b8;
    
     }
    
     }
    
  
    
     return 0;
    
 }
    
    
    
    
    AI写代码

以下片段转自:http://kerlubasola.iteye.com/blog/1579736

[cpp] [ view plain]( "view plain") copy

  1. //-------------------------------------------------------------------
  2. //转换
  3. static int rgb565_to_rgb888(const void * psrc, int w, int h, void * pdst)
  4. {
  5. int srclinesize = UpAlign4(w * 2);
  6. int dstlinesize = UpAlign4(w * 3);
  7. const unsigned char * psrcline;
  8. const unsigned short * psrcdot;
  9. unsigned char * pdstline;
  10. unsigned char * pdstdot;
  11. int i,j;
  12. if (!psrc || !pdst || w <= 0 || h <= 0) {
  13. printf("rgb565_to_rgb888 : parameter error\n");
  14. return -1;
  15. }
  16. psrcline = (const unsigned char *)psrc;
  17. pdstline = (unsigned char *)pdst;
  18. for (i=0; i<h; i++) {
  19. psrcdot = (const unsigned short *)psrcline;
  20. pdstdot = pdstline;
  21. for (j=0; j<w; j++) {
  22. //565 b|g|r -> 888 r|g|b
  23. *pdstdot++ = (unsigned char)(((*psrcdot) >> 0 ) << 3);
  24. *pdstdot++ = (unsigned char)(((*psrcdot) >> 5 ) << 2);
  25. *pdstdot++ = (unsigned char)(((*psrcdot) >> 11) << 3);
  26. psrcdot++;
  27. }
  28. psrcline += srclinesize;
  29. pdstline += dstlinesize;
  30. }
  31. return 0;
  32. }
  33. static int rgb888_to_rgb565(const void * psrc, int w, int h, void * pdst)
  34. {
  35. int srclinesize = UpAlign4(w * 3);
  36. int dstlinesize = UpAlign4(w * 2);
  37. const unsigned char * psrcline;
  38. const unsigned char * psrcdot;
  39. unsigned char * pdstline;
  40. unsigned short * pdstdot;
  41. int i,j;
  42. if (!psrc || !pdst || w <= 0 || h <= 0) {
  43. printf("rgb888_to_rgb565 : parameter error\n");
  44. return -1;
  45. }
  46. psrcline = (const unsigned char *)psrc;
  47. pdstline = (unsigned char *)pdst;
  48. for (i=0; i<h; i++) {
  49. psrcdot = psrcline;
  50. pdstdot = (unsigned short *)pdstline;
  51. for (j=0; j<w; j++) {
  52. //888 r|g|b -> 565 b|g|r
  53. *pdstdot = (((psrcdot[0] >> 3) & 0x1F) << 0)//r
  54. |(((psrcdot[1] >> 2) & 0x3F) << 5)//g
  55. |(((psrcdot[2] >> 3) & 0x1F) << 11);//b
  56. psrcdot += 3;
  57. pdstdot++;
  58. }
  59. psrcline += srclinesize;
  60. pdstline += dstlinesize;
  61. }
  62. return 0;
  63. }

全部评论 (0)

还没有任何评论哟~