本文内容不是完全原创,参考了网上部分精华,做了整理。
RGB色彩模式(也翻译为“红绿蓝”,比较少用)是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)
三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道
的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。
就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第三个字节。
量化位数从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
按照上面的图,我们大体知道了 RGB888 -> RGB565是怎么压缩的,也知道了RGB565- > RGB888
是怎么做补偿的,接下来就从代码的角度看看我们具体如何实现这样的转换。
代码:
(rr , gg, bb是属于byte类型,一字节大小)
(1) RGB565 -> RGB888
-
“font-size:14px;”
>rr =
byte
[
1
] &
0xf8
;
- gg = (byte[1] << 5) | ((byte[0] & 0xe0) >> 3);
- bb = byte[0] << 3;
- // 补偿
- rr = rr | ((rr & 0x38) >> 3);
- gg = gg | ((gg & 0x0c) >> 2);
- bb = bb | ((bb & 0x38) >> 3);
另外,也看到了一位大师的两种做法,转自: http://bbs.csdn.net/topics/
(2) RGB888 -> RGB555
- for(int j = 0; j < abs(bmih.biHeight); j++)
- {
- WORD *pTemp = (WORD *)(pData + WIDTHBYTES(bmih.biWidth * 16) * j);
- 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//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/
- //——————————————————————-
- //转换
- static int rgb565_to_rgb888(const void * psrc, int w, int h, void * pdst)
- {
- int srclinesize = UpAlign4(w * 2);
- int dstlinesize = UpAlign4(w * 3);
- const unsigned char * psrcline;
- const unsigned short * psrcdot;
- unsigned char * pdstline;
- unsigned char * pdstdot;
- int i,j;
- if (!psrc || !pdst || w <= 0 || h <= 0) {
- printf(“rgb565_to_rgb888 : parameter error\n”);
- return -1;
- }
- psrcline = (const unsigned char *)psrc;
- pdstline = (unsigned char *)pdst;
- for (i=0; i
- psrcdot = (const unsigned short *)psrcline;
- pdstdot = pdstline;
- for (j=0; j
- //565 b|g|r -> 888 r|g|b
- *pdstdot++ = (unsigned char)(((*psrcdot) >> 0 ) << 3);
- *pdstdot++ = (unsigned char)(((*psrcdot) >> 5 ) << 2);
- *pdstdot++ = (unsigned char)(((*psrcdot) >> 11) << 3);
- psrcdot++;
- }
- psrcline += srclinesize;
- pdstline += dstlinesize;
- }
- return 0;
- }
- static int rgb888_to_rgb565(const void * psrc, int w, int h, void * pdst)
- {
- int srclinesize = UpAlign4(w * 3);
- int dstlinesize = UpAlign4(w * 2);
- const unsigned char * psrcline;
- const unsigned char * psrcdot;
- unsigned char * pdstline;
- unsigned short * pdstdot;
- int i,j;
- if (!psrc || !pdst || w <= 0 || h <= 0) {
- printf(“rgb888_to_rgb565 : parameter error\n”);
- return -1;
- }
- psrcline = (const unsigned char *)psrc;
- pdstline = (unsigned char *)pdst;
- for (i=0; i
- psrcdot = psrcline;
- pdstdot = (unsigned short *)pdstline;
- for (j=0; j
- //888 r|g|b -> 565 b|g|r
- *pdstdot = (((psrcdot[0] >> 3) & 0x1F) << 0)//r
- |(((psrcdot[1] >> 2) & 0x3F) << 5)//g
- |(((psrcdot[2] >> 3) & 0x1F) << 11);//b
- psrcdot += 3;
- pdstdot++;
- }
- psrcline += srclinesize;
- pdstline += dstlinesize;
- }
- return 0;
- }
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/209501.html原文链接:https://javaforall.net
