我们在写滤波程序时一般会用矩阵模板与原图像做卷积,这时候在做图像边界的处理是一般都选择忽略边缘,不过要是模板比较大,那么处理的效果就不好了,图像四周就会是原图像,中间才是滤波后的结果,虽然用Matlab的imfilter就能解决,不过还是自己通过滤波的原理实践一下比较好。
模板和图像一共有如下16种关系,我粗略的画了一下,前三张小矩形的是模板、大的矩形是图像,最后一张大的是模板,小的是图像。这就是图像和模板卷积时的所有关系。
看似好像要写16个if判断,其实是不用的,我们只要判断卷积时模板的四个边界和图像的四个边界的关系就行了。这里有两对相对坐标,一个是表示图像的卷积范围,一个表示模板的卷积范围。先说怎么表示图像的卷积范围吧,如果当前处理的点是(i,j),模板大小都是2*r+1(我这里都用了对称的奇数模板,模板边界像素要是偶数会很难处理,这里我干脆把奇数也化成了偶数,原理差不多的)。八个边界可以这样表示,图像就是1表示图像上边缘,m表示图像下边缘,1表示图像左边缘,n表示图像右边缘,i-r表示模板上边缘,i+r表示模板下边缘,j-r表示模板左边缘,j+r表示模板右边缘。通过这四对的组合就能16个关系,具体还是见下面的代码吧,看注释结合代码比较清楚。
main.m
1 clear all;
2 close all;
3 clc;
4 r=20;
5 w=fspecial(\'average\',[2*r+1 2*r+1]);
6
7 img=imread(\'lena.jpg\');
8 img=mat2gray(img);
9 [m n]=size(img);
10 imshow(img);
11
12
13 imgn=filterim(img,w);
14 figure;
15 imshow(mat2gray(imgn));
16
17 imgn=img;
18
19 for i=r+1:m-r
20 for j=r+1:n-r
21
22 imgn(i,j)=sum(sum(img(i-r:i+r,j-r:j+r).*w));
23
24 end
25 end
26 figure;
27 imshow(mat2gray(imgn));
28
29
30 figure;
31 img=imfilter(img,w);
32 imshow(mat2gray(img))
filterim.m(实现主要功能):
1 function imgn=filterim(img,w)
2
3 [r r]=size(w);
4 [m n]=size(img);
5 if mod(r,2)==0
6 r=r+1;
7 w=imresize(w,[r r]);
8 end
9 imgn=zeros(m,n);
10 r=floor(r/2);
11
12 for i=1:m
13 for j=1:n
14 %图像需要获得四个边界的卷积范围,模板只需要获得最上面和最左面就可以了,因为图像和模板两个卷积范围是一样的。
15 if i-r<1 %判断模板上边缘和图像上边缘的关系
16 img_up=1; %如果当前像素的高小于模板的一半,那么选择图像的上边缘作为卷积图像的上边缘
17 mark_up=r-i+1; %模板的上边缘使用和图像相交的上边缘
18 else
19 img_up=i-r; %使用当前像素的高减去模板的一半作为卷积图像的上边缘
20 mark_up=1; %使用模板的最上边缘作为卷积模板的上边缘
21 end
22
23 if i+r>m %判断模板下边缘和图像下边缘的关系
24 img_down=m; %如果当前像素的高加上模板的一半超过整个图像的高,那么卷积图像的下边缘使用整个图像的下边缘
25 else
26 img_down=i+r; %否则卷积图像的下边缘使用当前像素的高加上模板的一半
27 end
28
29 if j-r<1 %判断模板左边缘和图像左边缘的关系
30 img_left=1; %如果当前像素的宽小于模板的一半,那么选择图像的左边缘作为卷积图像的左边缘
31 mark_left=r-j+1; %模板的左边缘使用和图像相交的左边缘
32 else
33 img_left=j-r; %使用当前像素的宽减去模板的一半作为卷积图像的左边缘
34 mark_left=1; %使用模板的最左边缘作为卷积模板的左边缘
35 end
36
37 if j+r>n %判断模板右边缘和图像右边缘的关系
38 img_right=n; %如果当前像素的宽加上模板的一般超过整个图像的宽,那么卷积图像的右边缘使用整个图像的右边缘
39 else
40 img_right=j+r; %否则卷积图像的右边缘使用当前像素的宽加上模板的一半
41 end
42
43 imgn(i,j)=sum(sum(img(img_up:img_down,img_left:img_right).*w(mark_up:mark_up+(img_down-img_up),mark_left:mark_left+(img_right-img_left))));%/((img_down-img_up+1)*(img_right-img_left+1));
44 %卷积图像上边缘:下边缘,左边缘:右边缘 %卷积模板上边缘:上边缘+(竖直卷积范围),卷积模板左边缘:左边缘+(水平卷积范围)
45 end
46 end
47 end
说实话,这个注释写的我很纠结,注释我已经尽力写清楚了,虽然我感觉还是没解释清楚。我果然需要锻炼一下写作与表达能力。
下面是效果图:
原图
自己写的滤波时边界处理的效果
通常的不做边界处理的效果
Matlab函数处理的结果
我这个效果基本和matlab自带的效果很接近了,不过速度好像慢很多,matlab自带的函数也许使用汇编处理的,总之,算法就是这样啦。