数字图像处理_领域平均滤波_中值滤波
东华大学实验报告
课程 数字图像处理 名称 数字图像变换
实验名称: 邻域平均法(box模板)和中值滤波处理 一、 实验目的
图像变换是数字图像处理中的一种综合变换,如直方图变换、几何变换等。通过本实验,使得学生掌握两种变换的程序实现方法。
二、 实验任务
请设计程序,分别用邻域平均法,其模板为:
111 111*1 9111
和中值滤波法对testnoise图像进行去噪处理(中值滤波的模板的大小也设为3×
3)。
三、实验环境
本实验在Windows平台上进行,对内存及cpu主频无特别要求,使用VC或者MINGW(gcc)编译器均可。
四、设计思路 介绍代码的框架结构、所用的数据结构、各个类的介绍(类的功能、类中方法的功能、类的成员变量的作用)、各方法间的关系 试验要求中以给出大致的编程思路和源代码以及代码注释,只有黑框部分需要自己填
写。在此不进行赘述。
五、具体实现 实现设计思路中定义的所有的数据类型,对每个操作给出实际算法。对主程序和其他模块也都需要写出实际算法。
注意:源代码中要加上注释。
代码:(红色为重点代码)
(3*3)
/*------利用第一次实验课提供的 dhc.h 和 dhc.c文件以获取位图的高 宽 以及从文件头到实际的位图数据的偏移字节数,从而实现对位图实际数据的操作。------*/ #include
#include
#include
#include
/*------定义结构指针------*/
struct bmphdr *hdr;
//定义用于直方图变量
unsigned char *bitmap,*count,*new_color;
/*------main()函数编写------*/
int main()
{
//定义整数 i, j 用于函数循环时的,nr_pixels为图像中像素的个数
int i, j ,nr_pixels,nr_w,nr_h;
//定义两个文件指针分别用于提取原图像的数据和生成直方图均衡化后的图像 FILE *fp, *fpnew;
//定义主函数的参数包括:输入的位图文件名和输出的位图文件名,此处内容可以不要,在DOS下执行命令的时候再临时输入也可,为了方便演示,我这里直接把函数的参数确定了。 // argc=3;
// argv[1]=
// argv[2]=
//参数输入出错显示
/* if (argc != 3) {
printf(
}*/
// 获取位图文件相关信息
// hdr = get_header(argv[1]);
hdr = get_header(
if (!hdr) exit(1);
//以二进制可读方式打开输入位图文件
fp = fopen(
if (!fp) {
printf(
exit(1);
}
// 文件指针指向数据区域
fseek(fp, hdr->offset, SEEK_SET);
//计算位图像素的个数
nr_pixels = hdr->width * hdr->height;
nr_w = hdr->width;
nr_h = hdr->height;
bitmap = malloc(nr_pixels);
new_color = malloc(nr_pixels);
count = malloc((nr_w+2)*(+nr_h+2));
//读取位图数据到bitmap中
fread(bitmap, nr_pixels, 1, fp);
fclose(fp);
//因为图像边缘无法使用邻域平均,所以根据邻近颜色填补图像的周围一圈,存入count[]数组中
//中心图像存入count[]
for(i=nr_w+3;i
{
j=i/(nr_w+2);
if(i%(nr_w+2)!=0&&(i+1)%(nr_w+2)!=0) count[i]=bitmap[i-nr_w-1-2*j]; }
//填补第一排
for(i=1;i
{
count[i]=bitmap[i-1];
}
//填补最后一排
for(i=1;i
{
count[(nr_w+2)*(nr_h+1)+i]=bitmap[nr_w*(nr_h-1)+i-1];
}
//填补左边一排
for(i=0;i
{
count[i*(nr_w+2)]=count[i*(nr_w+2)+1];
}
//填补右边一排
for(i=0;i
{
count[(i+1)*(nr_w+2)-1]=count[(i+1)*(nr_w+2)-2];
}
//邻域平均3*3
for(j=nr_w+3,i=0;j
{
if(j%(nr_w+2)!=0&&(j+1)%(nr_w+2)!=0)
new_color[i]=(count[j]+count[j-1]+count[j+1]+count[j-nr_w-2]+count[j-1-nr_w-2]+count[j+1-nr_w-2]+count[j+nr_w+2]+count[j-1+nr_w+2]+
count[j+1+nr_w+2])/9,i++;
}
//结果存入bitmap[]中
for (i = 0; i
bitmap[i]=new_color[i];
// 打开一个以输出文件名命名的文件,设为可写的二进制形式
fpnew = fopen(
//由于位图文件的头部信息并没有因直方图均衡化而改变,因此输出图像的头部信息从原位图文件中拷贝即可:
fwrite(hdr->signature, 2, 1, fpnew);
fwrite(&hdr->size, 4, 1, fpnew);
fwrite(hdr->reserved, 4, 1, fpnew);
fwrite(&hdr->offset, 4, 1, fpnew);
fwrite(&hdr->hdr_size, 4, 1, fpnew);
fwrite(&hdr->width, 4, 1, fpnew);
fwrite(&hdr->height, 4, 1, fpnew);
fwrite(&hdr->nr_planes, 2, 1, fpnew);
fwrite(&hdr->bits_per_pixel, 2, 1, fpnew);
fwrite(&hdr->compress_type, 4, 1, fpnew);
fwrite(&hdr->data_size, 4, 1, fpnew);
fwrite(&hdr->resol_hori, 4, 1, fpnew);
fwrite(&hdr->resol_vert, 4, 1, fpnew);
fwrite(&hdr->nr_colors, 4, 1, fpnew);
fwrite(&hdr->important_color, 4, 1, fpnew);
if (hdr->offset > 54)
fwrite(hdr->info, (hdr->offset - 54), 1, fpnew);
//直方图均衡化的数据(bitmap)赋值
fwrite(bitmap, nr_pixels, 1, fpnew);
//关闭
fclose(fpnew);
//释放内存(优化程序必需)
free(hdr);
free(bitmap);
free(new_color);
free(count);
return 0;
}
/*------利用第一次实验课提供的 dhc.h 和 dhc.c文件以获取位图的高 宽 以及从文件头到实际的位图数据的偏移字节数,从而实现对位图实际数据的操作。------*/ #include
#include
#include
#include
/*------定义结构指针------*/
struct bmphdr *hdr;
//定义用于直方图变量
unsigned char *bitmap,*count,*new_color;
/*------main()函数编写------*/
int main()
{
//定义整数 i, j 用于函数循环时的,nr_pixels为图像中像素的个数
int i, j, m, n, nr_pixels,nr_w,nr_h,temp,t[9];
//定义两个文件指针分别用于提取原图像的数据和生成直方图均衡化后的图像 FILE *fp, *fpnew;
//定义主函数的参数包括:输入的位图文件名和输出的位图文件名,此处内容可以不要,在DOS下执行命令的时候再临时输入也可,为了方便演示,我这里直接把函数的参数确定了。 // argc=3;
// argv[1]=
// argv[2]=
//参数输入出错显示
/* if (argc != 3) {
printf(
}*/
// 获取位图文件相关信息
// hdr = get_header(argv[1]);
hdr = get_header(
if (!hdr) exit(1);
//以二进制可读方式打开输入位图文件
fp = fopen(
if (!fp) {
printf(
exit(1);
}
// 文件指针指向数据区域
fseek(fp, hdr->offset, SEEK_SET);
//计算位图像素的个数
nr_pixels = hdr->width * hdr->height;
nr_w = hdr->width;
nr_h = hdr->height;
bitmap = malloc(nr_pixels);
new_color = malloc(nr_pixels);
count = malloc((nr_w+2)*(+nr_h+2));
//读取位图数据到bitmap中
fread(bitmap, nr_pixels, 1, fp);
fclose(fp);
//因为图像边缘无法使用邻域平均,所以根据邻近颜色填补图像的周围一圈,存入count[]数组中
//中心图像存入count[]
for(i=nr_w+3;i
{
j=i/(nr_w+2);
if(i%(nr_w+2)!=0&&(i+1)%(nr_w+2)!=0) count[i]=bitmap[i-nr_w-1-2*j]; }
//填补第一排
for(i=1;i
{
count[i]=bitmap[i-1];
}
//填补最后一排
for(i=1;i
{
count[(nr_w+2)*(nr_h+1)+i]=bitmap[nr_w*(nr_h-1)+i-1];
}
//填补左边一排
for(i=0;i
{
count[i*(nr_w+2)]=count[i*(nr_w+2)+1];
}
//填补右边一排
for(i=0;i
{
count[(i+1)*(nr_w+2)-1]=count[(i+1)*(nr_w+2)-2];
}
//中值平均3*3
for(j=nr_w+3,i=0;j
{
if(j%(nr_w+2)!=0&&(j+1)%(nr_w+2)!=0)
{
t[0]=count[j];
t[1]=count[j-1];
t[2]=count[j+1];
t[3]=count[j-nr_w-2];
t[4]=count[j-1-nr_w-2];
t[5]=count[j+1-nr_w-2];
t[6]=count[j+nr_w+2];
t[7]=count[j-1+nr_w+2];
t[8]=count[j+1+nr_w+2];
for(m=0;m
for(n=0;n
if(t[n]>t[n+1])
{
temp=t[n];
t[n]=t[n+1];
t[n+1]=temp;
}
new_color[i]=t[4];
i++;
}
}
//结果存入bitmap[]中
for (i = 0; i
bitmap[i]=new_color[i];
// 打开一个以输出文件名命名的文件,设为可写的二进制形式
fpnew = fopen(
//由于位图文件的头部信息并没有因直方图均衡化而改变,因此输出图像的头部信息从原位图文件中拷贝即可:
fwrite(hdr->signature, 2, 1, fpnew);
fwrite(&hdr->size, 4, 1, fpnew);
fwrite(hdr->reserved, 4, 1, fpnew);
fwrite(&hdr->offset, 4, 1, fpnew);
fwrite(&hdr->hdr_size, 4, 1, fpnew);
fwrite(&hdr->width, 4, 1, fpnew);
fwrite(&hdr->height, 4, 1, fpnew);
fwrite(&hdr->nr_planes, 2, 1, fpnew);
fwrite(&hdr->bits_per_pixel, 2, 1, fpnew);
fwrite(&hdr->compress_type, 4, 1, fpnew);
fwrite(&hdr->data_size, 4, 1, fpnew);
} fwrite(&hdr->resol_hori, 4, 1, fpnew); fwrite(&hdr->resol_vert, 4, 1, fpnew); fwrite(&hdr->nr_colors, 4, 1, fpnew); fwrite(&hdr->important_color, 4, 1, fpnew); if (hdr->offset > 54) fwrite(hdr->info, (hdr->offset - 54), 1, fpnew); //直方图均衡化的数据(bitmap)赋值 fwrite(bitmap, nr_pixels, 1, fpnew); //关闭 fclose(fpnew); //释放内存(优化程序必需) free(hdr); free(bitmap); free(new_color); free(count); return 0;
得出实验结果图像后,比较这两种方法去噪的效果好坏,并分析具体原因。
通过比较,邻域平均法在降低噪声的同时,会使图像产生模糊;中值滤波在降低噪声的同时,能够较好的保持图像边缘,不过我感觉有点水粉画的效果,让图像有点失真。
完成上述工作后,使用程序进行验证分析:使用邻域平均法时,3×3和5×5模板大小对图像进行处理的效果有何差别?并分析原因。
程序及源代码都放在文件夹中,不放进报告了。上面是对比图,显然5×5模板比3×3模版模糊,因为使用邻域平均法时,模版尺寸越大,则图像模糊程度越大。
六、心得体会
这次实验是对两种去噪方法的比较。而在书本中,我们已经看过两种去噪方法的效果了,通过上机验证,果然如此。
在编写代码中,我把算法设计的比较繁琐,因为图像每一个像素的信息是由一维数组bitmap记录的,所以在算均值与中值时花了很大的力气。主要是添补周围一圈的图像比较繁琐,还有就是在一维数组中找模版中心和模版中的其他点。虽然我觉得用二维数组会使算法比较简单,但是我忘了二维数组如何动态分配空间,所以只能硬着头皮用一维数组做。