BMP格式图像知识点总结并转灰度图

练习目的

BMP格式图片灰度化

位图知识点

刚拿到任务时觉得图像处理不算难,以前在学校用matlab做过简单的数字图像处理作业,如果用c++写的话调用OpenCV的库函数应该也不难,但后来发现要用纯c++开发,就有点懵逼了。matlab和OpenCV里的封装函数确实用起来很方便很快,但函数的算法是如何实现的,到底是对图片的什么信息做了什么更改,一无所知。所以需要好好补一下这部分知识,这样有利于从根本上理解图像处理的本质方法。
上网搜了很多资料,发现对图片进行处理大家都提到了BMP格式,后来再查发现bmp格式的文件里存储了图片的很多信息,包括:信息头,文件头,调色板,位图数据(实际的像素值)。刚开始的想法就是我能拿到图片的像素值就好办了,后来发现原来BMP格式就存储着像素信息,那就继续了解下BMP格式的存储结构,还要知道怎么拿到这些数据。

BMP图像存储结构

块名称 Windows结构体定义 大小(BYTE)
文件信息头 BITMAPFILEHEADER 14
位图信息头 BITMAPINFOHEADER 40
调色板 RGBQUAD 单色、16色、256色图像文件特有,相对应的调色板大小是2,16,256。
RGB像素值阵列 BYTE* 由图像长宽尺寸决定,每一行字节数必须是4的整数倍

位图文件头

提供文件的格式,大小等信息

typedef struct tagBITMAPFILEHEADER
{
   
	UINT16	bfType;        	//2BYTES,必须为BM,即0x424D,文件格式,windows位图文件
	DWORD	bfSize;			//4BYTES,整个BMP文件的大小
	UINT16	bfReverved1;	//2BYTES,保留,值为0
	UINT16	bfReverved2;	//2BYTES,保留,值为0
	DWORD	bfOffBits;		//4BYTES,文件起始位置到图像像素数据的字节偏移量
}BITMAPFILEHEADER;

位图信息头

定义如下:

typedef struct _tagBMP_INFOHEADER
{
   
	DWORD biSize;			//4BYTES,INFOHEADER结构体大小
	LONG biWidth;			//4BYTES,图像宽度(以像素为单位)
	LONG biHeight;			//4BYTES,图像高度。值为正,图像存储顺序从下到上,从左到右;值为负,正好相反。
	WORD biPlanes;			//2BYTES,图像数据平面,BMP存储RGB数据,因此总为1
	WORD biBitCount;		//2BYTES,图像像素位数
	DWORD biCompression;	//4BYTES,0:不压缩;1:RLE8;2:RLE4
	DWORD  biSizeImage;		//4BYTES,4字节对齐的图像数据大小
	LONG biXPelsPerMeter;	//4BYTES,用像素/米表示的水平分辨率
	LONG biYPelsPerMeter;	//4BYTES,用像素/米表示的垂直分	
	DWORD biClrUsed;		//4BYTES,实际使用的调色板索引数,0:使用所有的调色板索引
	DWORD biClrImportant;	//4BYTES,重要的调色板索引数,0:所有的索引都重要
}BMP_INFOHEADER;

调色板

结构体定义如下:

typedef struct _tagRGBQUAD
{
   
	BYTE rgbBlue;		//指定蓝色强度
	BYTE rgbGreen;		//指定绿色强度
	BYTE rgbRed;		//指定红色强度
	BYTE rgbReserved;	//保留,设0
}RGBQUAD;

1,4,8位图像才会使用调色板数据,16,24,32位图像不需要调色板数据,即调色板最多只需256项(索引0-255)。
颜色表的大小根据所使用的颜色模式而定:2色图像为8字节;16色图像位64字节;256色图像为1024字节。其中,每4字节表示一种颜色,并以B(蓝色)、G(绿色)、R(红色)、alpha(32位位图的透明度值,一般不需要)。即首先4字节表示颜色号1的颜色,接下来表示颜色号2的颜色,依此类推。

颜色表中RGBQUAD结构数据的个数有biBitCount来确定,当biBitCount=1,4,8时,分别有2,16,256个表项。

当biBitCount=1时,为2色图像,BMP位图中有2个数据结构RGBQUAD,一个调色板占用4字节数据,所以2色图像的调色板长度为2*4为8字节。

当biBitCount=4时,为16色图像,BMP位图中有16个数据结构RGBQUAD,一个调色板占用4字节数据,所以16像的调色板长度为16*4为64字节。

当biBitCount=8时,为256色图像,BMP位图中有256个数据结构RGBQUAD,一个调色板占用4字节数据,所以256色图像的调色板长度为256*4为1024字节。

当biBitCount=16,24或32时,没有颜色表。

位图数据

位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:

当biBitCount=1时,8个像素占1个字节;

当biBitCount=4时,2个像素占1个字节;

当biBitCount=8时,1个像素占1个字节;

当biBitCount=24时,1个像素占3个字节;

Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充,

一个扫描行所占的字节数计算方法:

DataSizePerLine= (biWidth* biBitCount+31)/8;

// 一个扫描行所占的字节数

DataSizePerLine= DataSizePerLine/4*4; // 字节数必须是4的倍数

位图数据的大小(不压缩情况下):

DataSize= DataSizePerLine* biHeight;

转灰度图重点

这里参考了文章:http://blog.sina.com.cn/s/blog_677a04530101244t.html

把24位真彩BMP图像转变成256阶灰度图的具体步骤如下:
(1) 修改信息头
信息头共有11部分,灰度化时需要修改两部分
bi2.biBitCount=8;
bi2.biSizeImage=( (bi.biWidth+3)/4 ) * 4bi.biHeight;
(2)修改文件头
文件头共有5部分,灰度化时需要修改两部分
bf2.bfOffBits = sizeof(bf2)+sizeof(BITMAPINFOHEADER)+256
sizeof(RGBQUAD);
bf2.bfSize = bf2.bfOffBits + bi2.biSizeImage;
(3)创建调色板
RGBQUAD ipRGB2 = (RGBQUAD )malloc(256sizeof(RGBQUAD));
for ( i = 0; i < 256; i++ )
ipRGB2[i].rgbRed = ipRGB2[i].rgbGreen = ipRGB2[i].rgbBlue = i;
(4)修改位图数据部分
这部分主要是由原真彩图的rgbRed、rgbGreen、rgbBlue分量值得到灰度图像的灰度值Y,可以用下面公式得到:
Y=0.299
rgbRed+0.587* rgbGreen+0.114*rgbBlue;

代码例程

代码参考了CSDN小伙伴 keep_moving_cqu的代码,对代码做了注释,并在最后释放了内存。试了下可用
https://blog.csdn.net/mydreamremindme/article/details/9909141

#include <iostream>
  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值