关键字:直方图统计、C语言、lena256色灰度图
本文内容主要给大家介绍数字图像处理领域中直方图的相关内容以及在C语言下的实现,重点介绍了BMP图像文件格式,对于进一步的直方图均衡、直方图匹配、局部直方图处理等内容之后会陆续推出。
目录
1.直方图
直方图是多种空间域处理技术的基础,从统计学角度出发,提供关于一幅图像质量、对比度的相关信息,在暗图像中,直方图的分量集中在灰度级的低端,类似的,亮图像直方图的分量倾向于灰度级的高端;低对比度图像具有较窄的直方图,而高对比度图像倾向于占据整个可能的灰度级并且分布均匀。
2.图像的格式
图像有多种存储格式,像我们熟悉的jpg、png、bmp等等,其中bmp(bitmap的缩写)作为Windows操作系统的图像标准格式,使用广泛,加上bmp格式通常是不压缩的,初学数字图像处理时更易上手些,本文使用BMP格式的lena图像,该图适度的混合了细节、平滑区域、阴影和纹理,能够很好的测试各种图像处理算法,是数字图像处理的标准图之一。
BMP文件格式主要由位图文件头、位图信息头、调色板、位图数据四部分组成,下面我们依次介绍:
2.1位图文件头
位图文件头(bitmap file header)这部分主要介绍图像类型、图像大小以及图像存放地址和两个保留未使用的字段,该部分共14个字节。打开WINGDI.h文件,定位到tagBITMAPFILEHEADER部分:
字段 | 大小(字节) | 描述 |
bfType | 2 | 位图类别,Windows下为BM |
bfSize | 4 | 该BMP图像文件的大小 |
bfReserved1 | 2 | 保留字段,总为0 |
bfReserved2 | 2 | 保留字段,总为0 |
bfOffBits | 4 | BMP位图数据的地址 |
我们结合lena.bmp图像具体来看一下
十六进制值 | 描述 |
42 4D | BM的ASCII值,表明该文件为BMP格式 |
36 04 04 00 | 40436H=263222字节,约257KB |
00 00 00 00 | 保留字段,总为0 |
36 04 00 00 | 436H=1078,位图数据开始的地方,即文件头、信息头、调色板的总长 |
2.2位图信息头
位图信息头(bitmap information header)主要介绍图像宽高、图像的色深、图像压缩等相关参数,该部分共40个字节。与上文类似,在WINGDI.h文件,定位到tagBITMAPFILEHEADER部分:
字段名 | 大小(字节) | 描述 |
biSize | 4 | 本结构的大小,在Windows中总为28H=40字节 |
biWidth | 4 | 该位图的宽度,以像素为单位 |
biHeight | 4 | 该位图的高度,以像素为单位 |
biPlanes | 2 | 目标设备的位平面数,必须为1 |
biBitCount | 2 | 位深度,常用1、4、8、24分布对应单色、16色、256色、真彩色 |
biCompression | 4 | 位图的压缩类型,0、1、2分别对应不压缩、BI-RLE8压缩、BI-RLE4压缩 |
biSizeImage | 4 | 位图的大小,以字节为单位 |
biXPelsPerMeter | 4 | 位图的目标设备水平分辨率,以每米像素数为单位 |
biYpelsPerMeter | 4 | 位图的目标设备垂直分辨率,以每米像素数为单位 |
biClrUsed | 4 | 该位图使用的颜色数 |
biClrImportant | 4 | 位图显示时被认为重要的颜色数 |
结合lena.bmp图像具体看一下
十六进制值 | 描述 |
28 00 00 00 | 该部分共28H=40字节 |
00 02 00 00 | 该位图宽200H=512个像素 |
00 02 00 00 | 该位图高200H=512个像素 |
01 00 | 目标设备平面数,必须为1 |
08 00 | 位深度为8,256色 |
00 00 00 00 | 位图不压缩 |
00 00 04 00 | 位图大小不超过40000H=262144个字节 |
00 00 00 00 | 目标设备参数 |
00 00 00 00 | 目标设备参数 |
00 01 00 00 | 使用颜色100H=256色 |
00 01 00 00 | 其中重要的颜色100H=256色 |
2.3调色板
调色板(color table)是单色、16色和256色图像所特有的,分别对应于上文中的biBitCount为1、4、8,调色板每四个字节存放一个颜色值,所以256色图像调色板占256 * 4=1024个字节,假设某点的像素值为n,则该像素的颜色为bmiColor[n]所定义的颜色。在WINGDI.h文件中,定位到" tagRGBQUAD"部分:
字段 | 大小(字节) | 描述 |
rgbBlue | 1 | 蓝色亮度值 |
rgbGreen | 1 | 绿色亮度值 |
rgbRed | 1 | 红色亮度值 |
rgbReserved | 1 | 保留,总为0 |
2.4位图数据
接下来便是真正的位图数据了,14 + 40 + 256 * 4 = 1078,即位图文件头中的bfOffBits字段。另外要注意,我们这里用的是256色的图像,24位的真彩色图像时没有调色板的,位图信息头后直接就是位图数据。
3.C语言实现
由于篇幅原因,这里给出统计直方图相关代码,灰度最大值、最小值、数学期望、方差、图像熵等源码在下方GitHub地址中一并给出:https://github.com/fuyuanhao/HDIL-DIP :)欢迎大家给我点点小星星
//需要引入头文件window.h
//声明相关变量
BITMAPFILEHEADER bmpFileHeader;
BITMAPINFOHEADER bmpInfoHeader;
RGBQUAD bmpColorTable[256];
BYTE bmpValue[512 * 512];
FILE *fp;
//打开lena.bmp图像文件
fp = fopen("lena.bmp", "rb");
if (!fp){
printf("Cann't open the file!\n");
return 0;
}
//读取图像信息
fread(&bmpFileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
fread(&bmpInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);
fread(bmpColorTable, sizeof(RGBQUAD), 256, fp);
fread(bmpValue, 1, 512 * 512, fp);
//将图像灰度值存入一位数组中
int grayValue[512 * 512] = { 0 };
for (int i = 0; i < 512 * 512; i++)
{
grayValue[i] = bmpColorTable[bmpValue[i]].rgbBlue;
}
//统计直方图
int grayCount[256] = { 0 };
double grayFrequency[256] = { 0.0 };
for (int i = 0; i < 512 * 512; i++)
{
grayCount[grayValue[i]]++;
}
for (int i = 0; i < 256; i++){
if (grayCount[i]){
grayFrequency[i] = grayCount[i] / (512.0*512.0);
printf("灰度值%3d 频数为%6d 频率为%f\n", i, grayCount[i], grayFrequency[i]);
}
}
//关闭图像文件
fclose(fp);
参考
[1]冈萨雷斯.数字图像处理[M].电子工业出版社:北京,2011:72-87.
[2]贾永红.数字图像处理[M].武汉大学出版社:武汉,2015:34-38.
此外,本文撰写时参考了网上多篇博客,在此感谢大家的帮助。
如果觉得本文有帮助,可以关注公众号【妙手】,获取更多数字图像处理相关内容: