一、RGB简介
l RGB色彩模式
RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。
l RGB的应用
目前的显示器大都是采用了RGB颜色标准。
电脑屏幕上的所有颜色,都由这红色绿色蓝色三种色光按照不同的比例混合而成的。一组红色绿色蓝色就是一个最小的显示单位。屏幕上的任何一个颜色都可以由一组RGB值来记录和表达。
在电脑中,RGB的所谓“多少”就是指亮度,并使用整数来表示。通常情况下,RGB各有256级亮度,用数字表示为从0、1、2...直到255。
l RGB原理
RGB是从颜色发光的原理来设计定的,通俗点说它的颜色混合方式就好像有红、绿、蓝三盏灯,当它们的光相互叠合的时候,色彩相混,而亮度却等于两者亮度之总和,越混合亮度越高,即加法混合。
有色光可被无色光冲淡并变亮。
加法混合的特点:越叠加越明亮。
红、绿、蓝三个颜色通道每种色各分为255阶亮度,在0时“灯”最弱是关掉的,而在255时“灯”最亮。当三色数值相同时为无色彩的灰度色,而三色都为255时为最亮的白色,都为0时为黑色。
l RGB格式
对一种颜色进行编码的方法统称为“颜色空间”或“色域”。用最简单的话说,世界上任何一种颜色的“颜色空间”都可定义成一个固定的数字或变量。RGB(红、绿、蓝)只是众多颜色空间的一种。采用这种编码方法,每种颜色都可用三个变量来表示-红色绿色以及蓝色的强度。记录及显示彩色图像时,RGB是最常见的一种方案。但是,它缺乏与早期黑白显示系统的良好兼容性。因此,许多电子电器厂商普遍采用的做法是,将RGB转换成YUV颜色空间,以维持兼容,再根据需要换回RGB格式,以便在电脑显示器上显示彩色图形。
二、RGB565与RGB888存储特点
RGB色彩模式是工业界的一种颜色标准,是通过对红、绿、蓝三个颜色通道的变化以及他们相互之间的叠加来得到各式各样的颜色的,RGB即使代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。
RGB565是采用两个字节存储一个色素,第二个字节前五位表示红色色素,第一个字节后五位表示蓝色色素,第一个字节前三位表示绿色色素的低三位和第二个字节后三位表示绿色色素的高三位。
即为:GGGBBBBBRRRRRGGG
第一个字节 |
第二个字节 |
||
前3位 |
后5位 |
前5位 |
后3位 |
GGG(绿色色素低三位) |
BBBBB |
RRRRR |
GGG(绿色色素高三位) |
RGB888是采用三个字节存储一个色素,第一个字节存储蓝色色素,第二个字节存储绿色色素,第三个字节存储红色色素。
即为:BBBBBBBBGGGGGGGGRRRRRRRR
第一个字节 |
第二个字节 |
第三个字节 |
BBBBBBBB |
GGGGGGGG |
RRRRRRRR |
三、获取RGB565分量的实现
B=( *image ) & 0x1F;==>000BBBBB
G=( *(image+1 ) << 3 ) & 0x38 + ( *image >> 5 ) & 0x07 ;==>00GGGGGG
R=( *(image+1) >> 3 ) & 0x1F; ==>000RRRRR
四、5bits映射到8bits
//第一个字节
*( image888+0 )=B * 255 / 63;
//第二个字节
*( image888+1 )=G * 255 / 127;
//的三个字节
*( image888+2 )=R * 255 / 63;
五、RGB565转RGB888的实现
void rgb565_to_rgb888(unsigned char *image,unsigned char *image888)
{
unsigned char R,G,B;
B=(*image) & 0x1F;//000BBBBB
G=( *(image+1) << 3 ) & 0x38 + ( *image >> 5 ) & 0x07 ;//00GGGGGG
R=( *(image+1) >> 3 ) & 0x1F; //000RRRRR
*(image888)=B<<3 | B>>2;
*(image888+1)=G<<2 | G>>4;
*(image888+2)=R<<3 | R>>2;
}
六、RGB888转RGB565的实现
unsigned short rgb_24_to_565(unsigned short r, unsigned short g, unsigned short b)
{
return ((r << 8) & 0xF800) | ((g << 3) & 0x07E0) | ((b >> 3) & 0x001f);
}
七、打印出转换后的部分颜色值
0 0 3c
75 0 0
75 0 0
75 0 3c
75 0 3c
0 0 3c
0 0 3c
75 0 0
75 0 0
75 0 3c
75 0 3c
0 0 3c
0 0 3c
75 0 0
75 0 0
75 0 3c
75 0 3c
0 0 3c
0 0 3c
0 0 3c
八、代码
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#pragma pack(2)
/*定义WORD为两个字节的类型*/
typedef unsigned short WORD;
/*定义DWORD为e四个字节的类型*/
typedef unsigned long DWORD;
/*位图文件头*/
typedef struct BMP_FILE_HEADER
{
WORD bType; /* 文件标识符 */
DWORD bSize; /* 文件的大小 */
WORD bReserved1; /* 保留值,必须设置为0 */
WORD bReserved2; /* 保留值,必须设置为0 */
DWORD bOffset; /* 文件头的最后到图像数据位开始的偏移量 */
} BMPFILEHEADER;
/*位图信息头*/
typedef struct BMP_INFO
{
DWORD bInfoSize; /* 信息头的大小 */
DWORD bWidth; /* 图像的宽度 */
DWORD bHeight; /* 图像的高度 */
WORD bPlanes; /* 图像的位面数 */
WORD bBitCount; /* 每个像素的位数 */
DWORD bCompression; /* 压缩类型 */
DWORD bmpImageSize; /* 图像的大小,以字节为单位 */
DWORD bXPelsPerMeter; /* 水平分辨率 */
DWORD bYPelsPerMeter; /* 垂直分辨率 */
DWORD bClrUsed; /* 使用的色彩数 */
DWORD bClrImportant; /* 重要的颜色数 */
} BMPINF;
/*彩色表*/
typedef struct RGB_QUAD
{
WORD rgbBlue; /* 蓝色强度 */
WORD rgbGreen; /* 绿色强度 */
WORD rgbRed; /* 红色强度 */
WORD rgbReversed; /* 保留值 */
} RGBQUAD;
void rgb565_to_rgb888(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;
printf("%x %x %x \n",*image888,*(image888+1),*(image888+2));
}
unsigned short rgb_24_to_565(unsigned short r, unsigned short g, unsigned short b)
{
short sh=((r << 8) & 0xF800) | ((g << 3) & 0x07E0) | ((b >> 3) & 0x001f);
unsigned char *ch=(char *)&sh;
unsigned char ch1=ch[0];
unsigned char ch2=ch[1];
printf("%x %x \n",ch1,ch2);
return sh;
}
void change(char filepath1[]){
FILE *fp;
BMPFILEHEADER fileHeader;
BMPINF infoHeader;
long offset, bmpImageSize, width, height, bytesPerPixel, size, bitCount;
WORD c;
//打开文件
if((fp = fopen(filepath1, "rb")) == NULL)
{
printf("Cann't open the file!\n");
exit(0);
}
fseek(fp, 0, 0);//文件指针偏移位置
fread(&fileHeader, sizeof(fileHeader), 1, fp);
fread(&infoHeader, sizeof(infoHeader), 1, fp);
if(infoHeader.bBitCount==16){
//如果源文件是565 的
printf("原文件是RGB565格式的\n");
unsigned char ch1[2],ch2[3];
do{
fread(ch1,2,1,fp);
//printf("%x %x \n",ch1[0],ch1[1]);
rgb565_to_rgb888(ch1,ch2);
//printf("%x %x %x\n",ch2[0],ch2[1],ch2[2]);
}while(!feof(fp));
}else{
printf("原文件是RGB888格式的\n");
unsigned char ch2[3];
do{
fread(ch2,3,1,fp);
//printf("%x %x %x\n",ch2[0],ch2[1],ch2[2]);
short sh=rgb_24_to_565(ch2[2],ch2[1],ch2[0]);
}while(!feof(fp));
}
fclose(fp);
}
int main()
{
change("xx.bmp");
return 0;
}
九、总结
量化压缩的方法:三个字取高位。虽然这样做到了压缩,但是会丢失精度。
量化补偿的方法:
1. 将原数据填充至高位
2. 对于低位,用原始数据的低位进行补偿
3. 如果仍然有未填充的位,继续使用原始数据的低位进行循环补偿