本文内容不是完全原创,参考了网上部分精华,做了整理。
RGB色彩模式(也翻译为“红绿蓝”,比较少用)是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)
三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道
的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。
按照上面的图,我们大体知道了 RGB888 -> RGB565是怎么压缩的,也知道了RGB565- > RGB888
是怎么做补偿的,接下来就从代码的角度看看我们具体如何实现这样的转换。
代码:
(rr , gg, bb是属于byte类型,一字节大小)
(1) RGB565 -> RGB888
- <span style="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); </span>
另外,也看到了一位大师的两种做法,转自: http://bbs.csdn.net/topics/350153377
(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;
- }
以下来自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
- //-------------------------------------------------------------------
- //转换
- 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<h; i++) {
- psrcdot = (const unsigned short *)psrcline;
- pdstdot = pdstline;
- for (j=0; j<w; 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<h; i++) {
- psrcdot = psrcline;
- pdstdot = (unsigned short *)pdstline;
- for (j=0; j<w; 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;
- }