工作用到了这方面的知识,记录一下,用大白话说明一哈。
一、BMP图片
1、一个BMP格式的图片可以分为三块,文件头信息,位图信息,位图数据(有的带调色板,可选)。
BMP文件头: 存储了该文件的类型,大小和存放信息等。
位图信息: 放BMP图像的高,宽,bpp等信息。
位图数据: 就是每个像素的值。
BMP图片的其余详细信息在代码的
下图是BMP格式图片图像的存储方式:从左到右,从下到上,此处存放的应该是位图数据
2、具体操作
其他知识:什么是均值滤波?
由上图可知,BMP图片的像素存放方式很像一个二维平面坐标系,把下图P7想象成坐标原点(0,0),在这个3*3的区域内,将这九个数排序,假设从小到大排序是:P2,P4,P8,P3,P9,P1,P5,P6,P7。中值就是P9,把图中的P5换成P9。一个像素的“滤波”就完成了,其余像素的操作跟这个一致。
有的小伙伴会发现,这样搞,那边界的,如P7,P8,P9怎么替换?这就用到边界处理的,边界拓展——复制图像边界来处理?啥意思,即用次外圈的像素替换最外圈的像素,看不懂没关系,举个例子。下图,P1,P4分别用P2,P5替换,同理P8,P9分别用P5,P6替换,这里P1,P4,P7,P8,P9都是最外圈像素,P2,P5,P6都是次内圈像素。那四个角呢,跟它直接挨着的都可以替换它,如P7,可以用P4,P5,P8替换,因为刚处理过一次后P4,P5,P8都一样了嘿。
思路:文件嘛,在计算机看来都是二进制的0,1。如何读取呢?用fread读取BMP图片的数据,读取到的数据存放到数组data中,从data中取出9个数据,排序后取中值替换即可。
代码大部分都是直接参考别人的,只有边界处理是自己加的。
#include#include #include typedef unsigned char BYTE; typedef struct tagRGBQUAD{ BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved; } RGBQUAD; #pragma pack(1)//声明1字节对齐,因为BMP文件是1字节保存的文件,而系统默认4字节对齐。 typedef struct{ unsigned char id1;//位图文件的类型,必须为BM(占用0-1字节) unsigned char id2; unsigned int filesize;//位图文件的大小,以字节为单位(2-5字节) unsigned int reserved;// 位图文件保留字,必须为0(6-9字节) unsigned int bitmapdataoffset;//位图数据的起始位置,以相对于位图(10-13字节) unsigned int bitmapheadersize;//BMP头的大小,固定为40(14-17字节) unsigned int width;//图片宽度;以像素为单位(18-21字节) unsigned int height;//图片高度;以像素为单位(22-25字节) unsigned short planes;//图片位面数,必须为1(26-27字节) unsigned short bitperpixel;//每个像素所需的位数,每个像素所需的位数(28-29字节) //只能是以下几个数:1(双色),4(16色),8(256色)或24(真彩色) 灰度级 unsigned int compression;//是否压缩(30-33字节) //只能是以下几个数:0(不压缩),1(BI_RLE8压缩类型),2(BI_RLE4压缩类型) unsigned int bitmapdatasize;//位图的大小,以字节为单位(34-37字节) unsigned int hresolution;//位图水平分辨率,每米像素数(38-41字节) unsigned int vresolution;//位图垂直分辨率,每米像素数(42-45字节) unsigned int colors;//位图实际使用的颜色表中的颜色数(46-49字节) unsigned int importantcolors;//位图显示过程中重要的颜色数(50-53字节) //unsigned int bmiColors[1];//调色板;(54 - 57字节) unsigned char palette[256][4];//调色板 占256*4=1024字节 }BMPheader;//总大小40+14+1024=1078字节 typedef struct { BMPheader* bmpheader ; unsigned char* bitmapdata;//图片数据; }BMPheaderfile; long getfilesize(FILE *f) { long pos,len; pos=ftell(f);//ftell函数用于得到文件指针当前位置相对于文件首的偏移字节数 fseek(f,0,SEEK_END);//fseek函数用于移动文件指针相对于SEEK_END的偏移量为0,相当于移动到文件最后 len=ftell(f);//len就是文件的长度 fseek(f,pos,SEEK_SET);//将文件指针移动到原来的地方 return len; } int main() { BMPheaderfile *output=(BMPheaderfile*)malloc(sizeof(BMPheaderfile));//定义一个输出指针 unsigned char *data=NULL; FILE *fpr,*fpw; if((fpr=fopen("start.bmp","rb"))==NULL) { printf("cannot open this file"); exit(0); } if((fpw=fopen("end1.bmp","wb"))==NULL) { printf("cannot wirte this file"); exit(0); } long length=getfilesize(fpr); printf("文件的长度为%ldn",length); printf("文件的头长度为%ldn",sizeof(BMPheader)); data=(unsigned char*)malloc(length*sizeof(char));//分配空间 if(0==fread(data,1,length,fpr)) { printf("read failedn"); exit(0); } fclose(fpr);//释放指针 output->bmpheader=(BMPheader*)malloc(sizeof(BMPheader)); memcpy(output->bmpheader,data,sizeof(BMPheader)); int height=output->bmpheader->height; int width=output->bmpheader->width; printf("filesize is %dn",output->bmpheader->filesize); printf("该图像每个像素所需要的位数:%dn",output->bmpheader->bitperpixel); printf("height is %dn",output->bmpheader->height); printf("width is %dn",output->bmpheader->width); data=data+sizeof(BMPheader); output->bitmapdata=data; unsigned char pixel[9]={0};//滑动窗口的像素值,初始为0 unsigned char mid;//中值 unsigned char temp;//中间变量 unsigned char border; int flag; int m,i,j,x,h,w,y; for(j=1;j bitmapdata[width*j+i]=mid; } } for(int q = 2; q < width; q++) { output->bitmapdata[q]=output->bitmapdata[width+q]; } for(int w = width*(width-2)+2; w < width*(width-1)-1; w++) { output->bitmapdata[w+width]=output->bitmapdata[w]; } for(int e = 0; e < height; e++) { output->bitmapdata[e*height]=output->bitmapdata[e*height+1]; } for(int r = 0; r < height; r++) { output->bitmapdata[r*height-1]=output->bitmapdata[r*height-2]; } fseek(fpw,0,0); //fseek(fpw,0,SEEK_SET) fwrite(output->bmpheader,1,sizeof(BMPheader),fpw);//写入图像的头文件 fwrite(output->bitmapdata,1,length-sizeof(BMPheader),fpw);//写入图像的数据信息 fclose(fpw);//释放指针 return 0; }
原图:无边界处理:
有边界处理:
参考内容:数字图像处理(一)——BMP图像的介绍和读取_小贾的博客-CSDN博客_bmp图像
中值滤波算法_jsjliuyun的博客-CSDN博客_中值滤波算法



