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

本文详细介绍了如何使用C语言读取8bit灰度图BMP文件,并实现3x3和自定义尺寸的中值滤波以及Prewitt算子进行图像锐化。程序通过模板滑动计算像素亮度值的中位数和灰度差,以达到平滑或锐化图像的效果。同时,提供了针对亮部、暗部及整体的局部图像处理方法。
摘要由CSDN通过智能技术生成

相关原理

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

平滑·中值滤波

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

锐化·Prewitt算子

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

C语言代码实现

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
 
 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色深彩色图
模板矩阵的边数为奇数。

运行结果

平滑(中值滤波):

在这里插入图片描述

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

在这里插入图片描述

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

锐化(Prewitt算子):

在这里插入图片描述
原图:在这里插入图片描述
效果图:
在这里插入图片描述

对图像局部操作的实现

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

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图片的中值滤波

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值