RGB565 与 RGB888的相互转换

RGB565 与 RGB888的相互转换本文内容不是完全原创 参考了网上部分精华 做了整理 RGB 色彩模式 也翻译为 红绿蓝 比较少用 是工业界的一种颜色标准 是通过对红 R 绿 G 蓝 B 三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的 RGB 即是代表红 绿 蓝三个通道的颜色 这个标准几乎包括了人类视力所能感知的所有颜色 是目前运用最广的颜色系统之一 就

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


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//




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

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


代码: 

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

(1) RGB565 -> RGB888

[java]  view plain copy



  1. “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);   


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

(2) RGB888 -> RGB555

[cpp]  view plain copy

  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//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 
    
      #include 
     
       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/

[cpp]  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.     
  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
  23.         psrcdot = (const unsigned short *)psrcline;    
  24.         pdstdot = pdstline;    
  25.         for (j=0; 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
  59.         psrcdot = psrcline;    
  60.         pdstdot = (unsigned short *)pdstline;    
  61.         for (j=0; 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. }    





版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/209501.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 上午9:05
下一篇 2026年3月19日 上午9:05


相关推荐

  • winhex 搜索零号扇区

    winhex 搜索零号扇区

    2026年3月13日
    2
  • Java异常处理习题

    Java异常处理习题一、选择题1、java中用来抛出异常的关键字是()A.try     B.catch   C.throw         D.finally 2、关于异常,下列说法正确的是()A.异常是一种对象       B.一旦程序运行,异常将被创建C.为了保证程序运行速度,要尽量避免异常控制     D.以上说法都不对 3、()类是所有异常类的父类。A.Th

    2022年5月12日
    80
  • java冒泡排序代码_Java冒泡排序

    java冒泡排序代码_Java冒泡排序一、冒泡排序:利用冒泡排序对数组进行排序二、基本概念:依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。至此第一趟结束,将最大的数放到了最后。在第二趟:仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再小于第2…

    2022年7月8日
    16
  • C++输入字符串的几种方式

    C++输入字符串的几种方式最近有复习到 C 基础知识 这里总结下在 C 中输入字符串的几种方式 有需要的可以参考 1 cin gt gt voidCin1 输入一个数字 inta b cin gt gt a gt gt b cout lt lt a b lt

    2026年3月18日
    1
  • Wappalyzer 网站技术分析软件「建议收藏」

    Wappalyzer 网站技术分析软件「建议收藏」Wappalyzer工具支持分析目标网站所采用的平台构架、网站环境、服务器配置环境、JavaScript框架、编程语言等参数,同时还可以显示目标站点使用该技术的网站比例,例如有多少网站使用的是Wordpress、有多少网站使用AddThis第三方服务,其他还有网页服务器、分析工具、CDN、留言系统、控制台、网络空间等等,可以让你从使用比例中得出目前最流行的技术。使用方法:1.打开

    2022年5月12日
    79
  • LINUX版navicat15永久激活码(注册激活)

    (LINUX版navicat15永久激活码)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html…

    2022年3月28日
    431

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号