前面讲了一帧YUV图像是由Y(亮度)U(色度)V(色度)来表示的,而RGB图像是由R(红色)G(绿色)B(蓝色)三个分量来表示的。
RGB格式的图片,比较常见的有如下三种:
顾名思义,RGB16是以16位(2个字节)为一个存储单元,来存储一个RGB像素。RGB16又有以下两种比较常见的存储形式
这里每个像素点用16位(2个字节)来表示,R、G、B分量分别占用了5位、6位、5位,内部排列如下所示
高字节 低字节
R R R R R G G G G G G B B B B B
这里每个像素点依旧用16位(2个字节)来表示,最高位不使用,R、G、B分量分别占用了5位,5位,5位。内部排列如下所示
高字节 低字节
空 R R R R R G G G G G B B B B B
RGB24是将24位的数据,分成3份,分别去存储R、G、B分量。所以每个分量占的大小应是8位(1个字节)。这里需要注意的是:R、G、B分量存储的顺序,从高字节到低字节,必须是以B G R的顺序来存储。为什么这里要强调从高字节到低字节,因为后续如果进行图片格式转换,遇到字节序不一致,需要对应地进行转换。内部排列如下所示
高字节 低字节
B B B B B B B B G G G G G G G G R R R R R R R R
RGB32中,每个像素点用32位(4个字节)来表示。这里存储的顺序和RGB24一样,这里不再过多赘述。唯一不同的是,在低字节处保留了8位。内部排列如下所示
高字节
B B B B B B B B G G G G G G G G
低字节
R R R R R R R R N N N N N N N N(N就是空的意思,hhh)
下面我们来编程分离一张RGB24格式图片中的R,G,B分量
#include
#include
/*
para: fileName 输入文件名
width 宽
height 高
*/
int rgb24Split(char *fileName, int width, int height)
{
FILE *fp = fopen(fileName, "rb+");
FILE *fp1 = fopen("output_r.y", "wb+");
FILE *fp2 = fopen("output_g.y", "wb+");
FILE *fp3 = fopen("output_b.y", "wb+");
unsigned char *buffer = (unsigned char *)malloc(width * height * 3);
fread(buffer, 1, width * height * 3, fp);
for (int i = 0; i < width * height * 3; i = i + 3)
{
//R
fwrite(buffer + i, 1, 1, fp1);
//G
fwrite(buffer + i + 1, 1, 1, fp2);
//B
fwrite(buffer + i + 2, 1, 1, fp3);
}
free(buffer);
fclose(fp);
fclose(fp1);
fclose(fp2);
fclose(fp3);
return 0;
}
/* a test file to split r g b */
int main()
{
rgb24Split("cie1931_500x500.rgb", 500, 500);
return 0;
}
首先我们打开原图片
我们这里分离了R,G,B三原色,可能看到这里有的同学要问,为什么不是以B,G,R的顺序写入,因为先前说过字节序的问题,所以这里应该是以R,G,B的顺序写入。
我们把每个数据都单独存储到文件中,所以不能算是一帧RGB图像了,所以我们以“Y(只看亮度)”的格式去打开这些文件,查看某种颜色的强度。
由观察得知,这张图片左上角绿色的强度偏大,右边的红色强度偏大,左下角则是蓝色的强度偏大。
下面看一下我们分离出的图片
分离出的R数据图像