位图文件结构简单,是数字图像处理时常用的输入和输出数据格式。
位图文件是逐像素保存图像的,一般不压缩。
位图文件由多种色彩模式,现在最常用的是24位真彩色。即用RGB方式来保存像素颜色,每个像素三个字节,每个字节的值表示一种颜色值,范围是0-255,共能表示16777216种颜色。
位图文件分为四部分:
1.位图文件头 占14字节
2.位图信息头 占40字节
3.颜色表 24位真彩色图像没有这部分内容
4.位图数据 存放像素信息
各部分的具体结构:
1.位图文件头:0----13字节
起始字节 | 所占字节数 | 具体内容 | 标志 |
1 | 2 | 文件类型(Windows位图为“BM”) | bfType |
3 | 4 | 文件大小 | bfSize |
7 | 4 | 保留 | bfReserved |
11 | 4 | 第一个位图数据的偏移量(一般为54) | bfOffBits |
2.位图信息头:14----53字节
起始字节 | 所占字节数 | 具体内容 | 标志 |
15 | 4 | 位图信息的长度(一般为40) | biSize |
19 | 4 | 位图的宽度 | biWidth |
23 | 4 | 位图的高度 | biHeight |
27 | 2 | 位图的位面数(=1) | biPlanes |
29 | 2 | 每个像素所占位数(=24 真彩图) | biBitCount |
31 | 4 | 位图压缩类型(=0 未压缩) | biCompression |
35 | 4 | 图像的大小(以字节为单位,必须是4的倍数) | biSizeImage |
39 | 4 | 位图水平分辨率(像素/米) | biXPelsPerMeter |
43 | 4 | 位图垂直分辨率(像素/米) | biYPelsPerMeter |
47 | 4 | 位图实际使用的颜色数(=0 使用所有颜色) | biClrUsed |
51 | 4 | 指定重要的颜色数(=0 都重要) | biClrImportant |
3.颜色表:24位真彩色图像没有这部分内容
4.位图数据:
对于24位真彩色图,位图数据存储图像中每个像素的RGB颜色值。一个像素占三个字节,每个字节分别表示RGB三个分量的值。但顺序与通常的恰好相反,为B、G、R。
像素的存放顺序是从图像的最后一行到第一行。每行从左至右。并且,BMP文件采用一种“对齐”机制。即,每行像素所占字节数必须是4的整数倍,如果实际像素所占字数不是4的倍数,则补充空字节,使每行所占的字节数为4的整数倍。下一行像素从空字节后开始存放。例如,图片每行有两个像素,占6字节,则补充2字节的空字节,下一行数据从这2字节后开始存放。实际每行像素占用8字节空间。
了解了这些,就可以将位图读取到程序中。程序中通常用矩阵的形式来保存图像。下面是示例代码:
/*
*变量定义
*/
int flag; //标志变量
char pic[1000][1000][3]; //存放图像中每个像素的RGB值
char bfType[2]; //存放图像类型标志
struct bf_head //定义文件信息头结构体
{
long int bfSize; //文件大小
long bfReserved;
long bfOffBits; //第一个位图数据的开始字节位置
}bf_h;
struct bi_head //定义图像信息头结构体
{
long biSize; //图像大小
long biWidth; //图像宽度
long biHeight; //图像高度
short int biPlanes; //位图的位面数
short int biBitCount; //每个像素所占位数
long biCompression; //位图压缩类型
long biSizeImage; //图像的大小
long biXPelsPerMeter; //位图水平分辨率
long biYpelsPerMeter; //位图垂直分辨率
long biClrUsed; //位图实际使用的颜色数
long biClrImportant; //指定重要的颜色数
}bi_h;
/*
*读取文件
*/
string lpszPathName="name.bmp";//要打开的bmp文件文件名
int x,y,k; //循环控制变量
FILE *fp=fopen(lpszPathName,"rb"); //以二进制的方式打开文件对话框中的图像
fread(bfType,2,1,fp); //读取从第1个字节开始的2个字符读一次存入bfType中
if (bfType[0]=='B'&&bfType[1]=='M') //如果文件类型为“BM”,则该文件时BMP文件
{
fread(&bf_h,12,1,fp); //读文件信息头
fread(&bi_h,40,1,fp); //读图像信息头
//在读取像素之前总共读取了54个字节 第55个字节开始为像素字节
//fread会移动读取文件的指针
if (bi_h.biBitCount==24)//像素位数等于24,时24位真彩色,可以进行处理
{
flag=1;//24位真彩色,标志量赋值
//图像从最后一行开始存储,因此先读的存在数组后面
for (y=bi_h.biHeight-1;y>=0;y--)
{//这层循环次数等于像素行数,也就是图像高度
for (x=0;x<bi_h.biWidth;x++)
{
//行中的像素是从左往右的,x由小到大,与实际的相同
//这层循环次数等于像素列数,也就是图像宽度
//分别读(x,y)处像素的RGB三个颜色分量分别存入
//pic[x][y][0],pic[x][y][1],pic[x][y][2]中
//文件中颜色值的存放顺序是BGR,所以用倒序来读,保存到数组中就是RGB
for (k=2;k>=0;k--)
fread(&pic[y][x][k],1,1,fp);//这里y表示行的下标
}
//由于BMP文件的“对齐”机制,每一行像素数据的长度若不是4的倍数,
//则填充一些数据使它是4的倍数。
if (((bi_h.biWidth*3)%4)!=0)
fseek(fp,4-(bi_h.biWidth*3)%4,1);//跳过无图像数据的字节
}
}
}
fclose(fp);