一、实验目的

  1. RGB格式储存特点。
  2. RGB格式转换的实现过程。

二、实验内容

  1. RGB888 RGB565 两种格式存储特点
  2. RGB565获取每一个分量的数据值的实现写出来。
  3. RGB888转565的实现函数
  4. 565转888的实现函数(中间的颜色值是有精度损失、最终的颜色值经过量化补偿的操作)
  5. 实现一个完整的测试程序
    linux平台下面通过打开bmp图片的方式,利用之前实现的函数对其格式进行转换,把最终转换的图片颜色数据输出出来

三.实验结果分析

  1. RGB888/RGB565 两种格式存储特点
    RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。 在电脑中,RGB的所谓“多少”就是指亮度,并使用整数来表示。通常情况下RGB各有256级亮度,用数字表示为从0、1、2…直到255。在0时灯最弱是关掉的,而在255时灯最高。当三色数值相同时为无色彩的灰色度,而三色都为255时为最亮的白色,都为0时为黑色;
    RGB565使用16位表示一个像素,这16位中的5位用于R,6位用于G,5位用于B。共有两个字节。
    RGB888使用24位表示一个像素,这24位中的8位用于R,8位用于G,8位用于B。共有三个字节。
  2. RGB565获取每一个分量的数据值的实现写出来。
    可以组合使用屏蔽字和移位操作来得到RGB各分量的值:
    具体实现过程如图3-1所示
#define RGB555_MASK_RED 0x7C00
#define RGB555_MASK_GREEN 0x03E0
#define RGB555_MASK_BLUE 0x001F
R = (wPixel & RGB555_MASK_RED) >> 10; 
G = (wPixel & RGB555_MASK_GREEN) >> 5; 
B = wPixel & RGB555_MASK_BLUE;


3: RGB888转565的实现函数
RGB888->RGB565而言:其转换的具体思路如下:

1.取RGB888中第一个字节的高5位作为转换后的RGB565的第一个字节的低5位
2.取RGB888中第二个字节的高3位作为转换后的RGB565第二个字节的低3位
3.取RGB888中第二个字节的第4–6位,作为转换后的RGB565第一个字节的高3位
4.取RGB888中第三个字节的高5位作为转换后的RGB565第二个字节的高5位

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);
}

代码中的具体实现如下图3-2所示


4: 565转888的实现函数(中间的颜色值有精度损失、最终的颜色值经过量化补偿的操作)
RGB565->RGB888

1.取RGB565第一个字节中低5位作为RGB888第一个字节的高5位
2.取RGB565第二个字节中的低3位,将其左移5位,作为RGB888第二个字节的高3位
3.取RGB565第一个字节的高3位将其右移5位,作为RGB888第二个字节的4–6位
4.取RGB565第二个字节中的高5位作为RGB888第三个字节

void rgb565_to_rgb24(BYTE *rgb24, unsigned short rgb565)  
{   
 //extract RGB  
rgb24[2] = (rgb565 & RGB565_MASK_RED) >> 11;     
    rgb24[1] = (rgb565 & RGB565_MASK_GREEN) >> 5;  
    rgb24[0] = (rgb565 &  RGB565_MASK_BLUE);  
//amplify the image  
    rgb24[2] <<= 3;  
    rgb24[1] <<= 2;  
    rgb24[0] <<= 3; 
    rgb24[2] = rgb24[2] | ((rgb24[2] & 0x38) >> 3);
    rgb24[1] = rgb24[1] | ((rgb24[1] & 0x0c) >> 2)
    rgb24[0] = rgb24[0] | ((rgb24[0] & 0x38) >> 3);
}

具体过程实现如图3-3所示

Android RGB888 转成 RGB565 rgb 转换_数据

5:量化补偿
量化补偿的方法:

  1. 将原数据填充至高位
  2. 对于低位,用原始数据的低位进行补偿
  3. 如果仍然有未填充的位,继续使用原始数据的低位进行循环补偿

16bit RGB565 -> 24bit RGB888 的转换
16bit RGB656: R4 R3 R2 R1 R0 G5 G4 G3 G2 G1 G0 B4 B3 B2 B1 B0

1: 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
2: 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 数据为经过量化补偿的数据,对低位做了量化补偿

四:实现完整的测试程序

#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 tagBITMAPFILEHEADER{
           WORD bType; /* 文件标识符 位图类别*/
           DWORD bSize; /* BMP图像文件的大小 */
           WORD bReserved1; /* 保留值,总为0 */
           WORD bReserved2; /* 保留值,总为0 */
           DWORD  bfOffBits;/* BMP图像数据的地址*/
} BMPFILEHEADER;
 /*位图信息头*/
typedef struct tagBITMAPINFOHEADER{
           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 tagRGBQUAD
{
          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("1%x 1%x 1%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;
            unsigned char red32, green32, blue32, x32, red565, green565, blue565;
            unsigned short rgb565;

//打开文件
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){
printf("原文件是RGB565格式的\n");
unsigned char ch1[2],ch2[3];
do{
fread(ch1,2,1,fp);
rgb565_to_rgb888(ch1,ch2);
            printf("565blue32=0x%x,green32=0x%x,red32=0x%x.\n",blue32\,green32,red32);         
            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);
            fread(&blue32,sizeof(unsigned char),1,fp);
            fread(&green32,sizeof(unsigned char),1,fp);
            fread(&red32,sizeof(unsigned char),1,fp);    
            short sh=rgb_24_to_565(ch2[2],ch2[1],ch2[0]);
            printf("888blue32=0x%x,green32=0x%x,red32=0x%x.\n",blue32,green32,red32);
}while(!feof(fp));
}fclose(fp);
}

int main(){
                 change("background_1.bmp");
                 return 0;
}