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
- 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);
另外一位大师的两种技巧...转自:[()
(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
- //-------------------------------------------------------------------
- //转换
- 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;
- }
