bmp图像数据说明

                                           bmp图像数据说明

BMP说明
BMP是BitMap的缩写,即位图,是一种非压缩格式,图像文件一般比较大,Windows系统内部各图像绘制操作都是以BMP为基础的。

BMP图像组成
BMP文件由四部分:
文件头信息,固定大小,结构体见BitmapFileHeader图像信息头,固定大小,结构见BitmapInfoHeader调色板,可选的,大小根据不同位数不同。位图RGB数据,大小可以根据位数,高宽计算出来。


BMP数据结构

typedef unsigned short U16;
typedef unsigned long  U32;
typedef struct tagBitmapFileHeader
{

    U16 bfType;         /* windows下该值必需是0x4D42,即字符'BM'*/
    U32 bfSize;         /* bmp文件大小,包含bmp文件头,信息头,调色板大小,数据大小 */
    U16 bfReserved1;    /* 保留,必须设置为0 */
    U16 bfReserved2;    /* 保留,必须设置为0 */
    U32 bfOffBits;      /* rgb数据相对文件头偏移量 */
} BitmapFileHeader;



typedef struct
{

    U32 biSize;         /* 信息头大小sizeof(BitmapInfoHeader) */
    U32 biWidth;        /* 图象的宽度,以象素为单位 */
    U32 biHeight;       /* 图象的高度,以象素为单位,正值倒向位图,负值正向位图 */
    U16 biPlanes;       /* 位面数,设为1 */
    U16 biBitCount;     /* 位图位数,可以为32,24,16,8,4,1 */
    U32 biCompression;  /* 说明图象数据压缩的类型,BI_RGB(0) BI_BITFIELDS(3)等 */
    U32 biSizeImage;    /* 图像数据大小,包括位图信息大小和数据大小 */        
    U32 biXPelsPerMeter;/* 水平分辨率,一般可填0 */    
    U32 biYPelsPerMeter;/* 垂直分辨率,一般可填0*/
    U32 biClrUsed;      /* 颜色索引使用数,一般填0,表示都使用 */
    U32 biClrImportant; /* 重要颜色索引数,一般填0,表示都重要 */

} BitmapInfoHeader;

数据长度计算:
int iLineByteCnt = (((biWidth*biBitCount) + 31) >> 5) << 2;
iRGBDataSize = iLineByteCnt * biHeight;
这个公式主要做了数据行4字节对齐工作,先加31右移5位(除32)做对齐工作,左移2(乘4)转成字节。biBitCount与biCompression
24位色与32位色biBitCount分部为24及32,biCompression固定为BI_RGB,一个像素占用3个及4个字节.
16位色,biBitCount为16,每个像素占用2个字节,为表示2个字节RGB的位置,分为多种情况biCompression为BI_RGB时,表明为RGB555格式,最高位为0,RGB各占5位,这种16位色格式无调色板信息。biCompression为BI_BITFIELDS时,则表明使用掩码方式,BitmapInfoHeader后面12字节(3个int)分别为RGB的掩码,555格式下,掩码为0x7C00、0x03E0、0x001F,565格式下,它们则分别为:0xF800、0x07E0、0x001F,掩码方式挺灵活,甚至都可以自己定义16位色格式如RGB844,当然意义不大。
BMP数据结构比较简单,调色板信息是可变项,其他都是固定的,较易处理,有几个地方需要注意:BitmapFileHeader结构不是4字节对齐,需注意使用#pragma pack(2)或__attribute__((aligned(2)))方式进行2直接对齐。BMP图片存储时RGB数据时行一般是倒序的,填充的时候注意倒序填充。

  • BitmapFileHeader结构不是4字节对齐,需注意使用#pragma pack(2)或__attribute__((aligned(2)))方式进行2直接对齐。
  • BMP图片存储时RGB数据时行一般是倒序的,填充的时候注意倒序填充。
  • 8位灰度图像是有调色板信息的,而24bit BMP是没有调色板信息

BMP转YUV

YUV和BMP都是非压缩格式,不存在解码过程,只需要做像素点到像素点的转换,YUV转bmp公式较多,应用到不同场景,下面是ITU-R BT.601建议在数字视频领域使用的公式(带有伽马校正,图像增强效果): 

R' = 1.164*(Y’-16) + 1.596*(Cr'-128)
G' = 1.164*(Y’-16) - 0.813*(Cr'-128) - 0.392*(Cb'-128)
B' = 1.164*(Y’-16) + 2.017*(Cb'-128)

 效果肯定是最好的,但运算量也是最大的,如果在嵌入式设备上使用,可以使用下面的简化公式:

R = Y + 1.4075 *(V-128)
G = Y – 0.3455 *(U –128) – 0.7169 *(V –128)
B = Y + 1.779 *(U – 128)

 在代码中实现该公式时,为提高计算效率,浮点运算需转为整形运算,公式可以转化为如下形式(统一先左移20,再右移20):

R = (Y<<20 + 1475871 *(V-128)) >> 20
G = (Y<<20 – 362283 *(U –128) – 751724 *(V –128)) >> 20
B = (Y <<20 + 1865417 *(U – 128)) >> 20

 由于YUV每个分量都使用1个字节来存储(YUV420格式UV分量会重复使用),每个值的取值范围为(0~255),为减少乘法运算,可以把乘法部分用局部查表法实现,如下:

int V1475871[256] = {0};
int V751724[256] = {0};
int U362283[256] = {0};
int U1865417[256] = {0};

for (i = 0; i < 256; i++)
{
    V1475871[i] = (i - 128) * 1475871;
    V751724[i] = (i - 128) * 751724;
    U362283[i] = (i - 128) * 362283;
    U1865417[i] = (i - 128) * 1865417;

}

/* 使用局部查表法,公式转成如下形式: */
R = (Y<<20 + V1475871[V]) >> 20;
G = (Y<<20 – U362283[U] – V751724[V]) >> 20;
B = (Y <<20 + U1865417[U]) >> 20;

 24位色及32位色一般采用局部查表法优化效率,采用完全查表法内存使用代价太大,如果16位色,则可以采用完全查表法。
局部查表法优化了乘法操作,优化效果有限(多个平台测试结果都在10%左右)。

发布了49 篇原创文章 · 获赞 138 · 访问量 30万+

猜你喜欢

转载自blog.csdn.net/lz0499/article/details/101073436