【图像处理作业】用C语言对bmp图像使用中值滤波、Prewitt算子进行平滑、锐化操作

相关原理

使用C语言打开8bit灰度图bmp文件并读出相应的每个像素亮度值,因为任何一个图像都可看成单个像素的组合。程序实现了1×1的图像和一个3×3的图像做卷积,并将结果输出成为新的bmp文件

平滑·中值滤波

对每个像素使用一个的方阵(大小为N=3, 5, 7,
…)在图象上滑动并把模板中像素的灰度值按升(或降)次序排列。取排列在正中间,即矩阵中像素亮度灰度值的中位数作为窗口中心所在象素的灰度值。

锐化·Prewitt算子

Prewitt算子是一种一阶微分算子的边缘检测,利用像素点上下、左右邻点的灰度差,在边缘处达到极值检测边缘,去掉部分伪边缘,对噪声具有平滑作用
。其原理是在图像空间利用两个方向模板与图像进行邻域卷积来完成的,这两个方向模板一个检测水平边缘,一个检测垂直边缘。

C语言代码实现

#include
#include
#include
 
 int compare1(const void* e1, const void *e2)
{
    //后续qsort使用预备函数
	return  *((int*)e1) - *((int *)e2);
	
}
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("1.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("文件的长度为%ld\n",length);
printf("文件的头长度为%ld\n",sizeof(BMPheader));
data=(unsigned char*)malloc(length*sizeof(char));//分配空间
 
/* 读文件,从fpr指向的文件中读出1个length长度(即图片的大小)的数据到data所指的内存空间去 */
if(0==fread(data,1,length,fpr))
{
	printf("read failed\n");
	exit(0);
}
fclose(fpr);//释放指针
output->bmpheader=(BMPheader*)malloc(sizeof(BMPheader));
 
/* 从data中拷贝sizeof(BMPheader)大小到output->bmpheader */
memcpy(output->bmpheader,data,sizeof(BMPheader));
 /*
 打印出图像中头文件的信息
 */
int height=output->bmpheader->height;
int width=output->bmpheader->width;
printf("filesize is %d\n",output->bmpheader->filesize);
printf("该图像每个像素所需要的位数:%d\n",output->bmpheader->bitperpixel);
printf("height is %d\n",output->bmpheader->height);
printf("width is %d\n",output->bmpheader->width);
data=data+sizeof(BMPheader);
output->bitmapdata=data;


unsigned char mid;//中值
unsigned char temp;//中间变量

int flag;
int m,i,j,x,h,w,y;
int n ;
printf("请输入模板的边数:");
scanf("%d",&n);
int N = n * n;
int sum;

int format[N] = {0};
int cho;
printf("中值滤波:1\n自定义模板:2\n");
scanf("%d",&cho);

if(cho==1){
    for(j=(n/2);j<height-(n/2);j++)
    {
		for(i=(n/2);i<width-(n/2);i++)
			{
				
				m=0;
				for(y=j-(n/2);y<=j+(n/2);y++)
					{
						for(x=i-(n/2);x<=i+(n/2);x++)
							{	
								format[m]=(int)data[y*width+x];
								m=m+1;
							}
					}
		
				qsort(format, N, sizeof(format[0]), compare1);
				mid=format[N/2];
				output->bitmapdata[width*j+i]=mid;
			}
	}
/* 边界问题:模板大小为3时的边界处理 */
 	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];	
		}
			}

if(cho==2){
    printf("按行输入模板:\n");
	for(int q = 0 ; q < N ; q ++){
		scanf("%d",&format[q]);
	}

	
	for(j=(n/2);j<height-(n/2);j++)
    {
		for(i=(n/2);i<width-(n/2);i++)
			{
                int test = (int)data[j*width+i] ;
				
					m=0;
				    sum = 0;
				    int cont = 0;
				    for(y=j-(n/2);y<=j+(n/2);y++)
				    	{
				    		for(x=i-(n/2);x<=i+(n/2);x++)
				    			{	
				    				if(format[m]!=0){
				    					cont ++;
				    				}
				    				temp = (int)data[y*width+x] * format[m];
				    				m=m+1;
				    				sum = sum + temp;
				    			}
				    	

				    sum = sum / cont ;
				    output->bitmapdata[width*j+i]=sum;
                }
			}
	}

	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;

}

运行时注意:
需要在文件打开操作中修改成代码所在文件夹下需要进行操作的图片名称。
图片为8bit灰度图而非8bit色深彩色图
模板矩阵的边数为奇数。

运行结果

平滑(中值滤波):

【图像处理作业】用C语言对bmp图像使用中值滤波、Prewitt算子进行平滑、锐化操作_第1张图片

原图:
【图像处理作业】用C语言对bmp图像使用中值滤波、Prewitt算子进行平滑、锐化操作_第2张图片
使用3*3矩阵进行中值滤波:
【图像处理作业】用C语言对bmp图像使用中值滤波、Prewitt算子进行平滑、锐化操作_第3张图片

【图像处理作业】用C语言对bmp图像使用中值滤波、Prewitt算子进行平滑、锐化操作_第4张图片

原图:
使用15*15矩阵进行中值滤波:

锐化(Prewitt算子):

【图像处理作业】用C语言对bmp图像使用中值滤波、Prewitt算子进行平滑、锐化操作_第5张图片
原图:
效果图:

对图像局部操作的实现

通过对每一个像素的亮度筛选并进行后续操作,可以实现对图片的局部锐化/平滑,修改局部代码(添加判断)如下:

for(j=(n/2);j<height-(n/2);j++)
    {
		for(i=(n/2);i<width-(n/2);i++)
			{
                int test = (int)data[j*width+i] ;
				if(test > 200){
					m=0;
				    sum = 0;
				    int cont = 0;
				    for(y=j-(n/2);y<=j+(n/2);y++)
				    	{
				    		for(x=i-(n/2);x<=i+(n/2);x++)
				    			{	
				    				if(format[m]!=0){
				    					cont ++;
				    				}
				    				temp = (int)data[y*width+x] * format[m];
				    				m=m+1;
				    				sum = sum + temp;
				    			}
				    	

				    sum = sum / cont ;
				    output->bitmapdata[width*j+i]=sum;
                }

				}else{
					output->bitmapdata[width*j+i]=test;
				}
			}
	}

其中修改部分为:

 int test = (int)data[j*width+i] ;
				if(test > 200){
				//具体操作
				}

实现了对像素亮度超过200部分的局部图像处理。

实现效果:

原图:
对整体锐化:

对暗部锐化:

对亮部锐化:

代码参考:

C语言 BMP图片的中值滤波

你可能感兴趣的:(研究生作业,图像处理,c语言,计算机视觉)