RGB565 与 RGB888的相互转换



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


RGB色彩模式(也翻译为“红绿蓝”,比较少用)是工业界的一种颜色标准,是通过对红(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第三个字节。

细心地哥们一定会发现如果我们是低位往高位上转的话,就存在一些数据精度的丢失问题,

在网上查了写资料,借鉴了一下别人的方法;所谓的量化补偿,讲一下量化压缩与量化补偿吧

  在进行色彩格式转换的时候,经常会遇到色彩量化位数的改变,比如说从 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. 如果仍然有未填充的位,继续使用原始数据的低位进行循环补偿

 

本文出自 “驿落黄昏” 博客,请务必保留此出处http://yiluohuanghun.blog.51cto.com/3407300/860798



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

是怎么做补偿的,接下来就从代码的角度看看我们具体如何实现这样的转换。


代码: 

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

(1) RGB565 -> RGB888

[java] view plaincopy
  1. <span style="font-size:14px;">rr = byte[1] & 0xf8;  
  2. gg = (byte[1] << 5) | ((byte[0] & 0xe0) >> 3);  
  3. bb = byte[0] << 3;  
  4.   
  5. // 补偿  
  6. rr = rr | ((rr & 0x38) >> 3);  
  7. gg = gg | ((gg & 0x0c) >> 2);  
  8. bb = bb | ((bb & 0x38) >> 3); </span>  


另外,也看到了一位大师的两种做法,转自: http://bbs.csdn.net/topics/350153377

(2) RGB888 -> RGB555

  1. for(int j = 0; j < abs(bmih.biHeight); j++)  
  2.     {  
  3.         WORD *pTemp = (WORD *)(pData + WIDTHBYTES(bmih.biWidth * 16) * j);  
  4.    
  5.         for(int i = 0; i < bmih.biWidth; i++)  
  6.         {  
  7. #if 1  
  8.             *pTemp++ = ((WORD)(*pR++ << 8) & 0xf800) | ((WORD)(*pG++ << 3) & 0x07e0) | ((WORD)(*pB++ >> 3) & 0x001f);  
  9. #else  
  10.             int nR = (*pR++ + 4) >> 3;  
  11.             int nG = (*pG++ + 2) >> 2;  
  12.             int nB = (*pB++ + 4) >> 3;  
  13.             if(nR > 31) nR = 31;  
  14.             if(nG > 63) nG = 63;  
  15.             if(nB > 31) nB = 31;  
  16.             *pTemp++ = (nR << 11) | (nG << 5) | nB;  
  17. #endif  
  18.         }  
  19.     }  



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

  1. #define RGB565_MASK_RED 0xF800 
  2. #define RGB565_MASK_GREEN 0x07E0 
  3. #define RGB565_MASK_BLUE 0x001F 
  4. rgb5652rgb888 : 
  5. unsigned short *pRGB16 = (unsigned short *)lParam; 
  6. for(int i=0; i<176*144; i++) 
  7.      unsigned short RGB16 = *pRGB16; 
  8.      g_rgbbuf[i*3+2] = (RGB16&RGB565_MASK_RED) >> 11;   
  9.      g_rgbbuf[i*3+1] = (RGB16&RGB565_MASK_GREEN) >> 5; 
  10.      g_rgbbuf[i*3+0] = (RGB16&RGB565_MASK_BLUE); 
  11.      g_rgbbuf[i*3+2] <<= 3; 
  12.      g_rgbbuf[i*3+1] <<= 2; 
  13.      g_rgbbuf[i*3+0] <<= 3; 
  14.      pRGB16++; 

另一种:

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

R8 = ( R5 * 527 + 23 ) >> 6;
G8 = ( G6 * 259 + 33 ) >> 6;
B8 = ( B5 * 527 + 23 ) >> 6;

It uses only: MUL, ADD and SHR -> so it is pretty fast! From the other side it is compatible in 100% to floating point mapping with proper 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);

Some extra cents: If you are interested in 888 to 565 conversion, this works very well too:

R5 = ( R8 * 249 + 1014 ) >> 11;
G6 = ( G8 * 253 +  505 ) >> 10;
B5 = ( B8 * 249 + 1014 ) >> 11;

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



关于上面按比例转到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;
}


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

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

阅读更多

没有更多推荐了,返回首页