我們在寫濾波程式時一般會用矩陣模板與原映像做卷積,這時候在做映像邊界的處理是一般都選擇忽略邊緣,不過要是模板比較大,那麼處理的效果就不好了,映像四周就會是原映像,中間才是濾波後的結果,雖然用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
clear all;close all;clc;r=20;w=fspecial('average',[2*r+1 2*r+1]);img=imread('lena.jpg');img=mat2gray(img);[m n]=size(img);imshow(img);imgn=filterim(img,w);figure;imshow(mat2gray(imgn));imgn=img;for i=r+1:m-r for j=r+1:n-r imgn(i,j)=sum(sum(img(i-r:i+r,j-r:j+r).*w)); endendfigure;imshow(mat2gray(imgn));figure;img=imfilter(img,w);imshow(mat2gray(img))
filterim.m(實現主要功能):
function imgn=filterim(img,w) [r r]=size(w); [m n]=size(img); if mod(r,2)==0 r=r+1; w=imresize(w,[r r]); end imgn=zeros(m,n); r=floor(r/2); for i=1:m for j=1:n %映像需要獲得四個邊界的卷積範圍,模板只需要獲得最上面和最左面就可以了,因為映像和模板兩個卷積範圍是一樣的。 if i-r<1 %判斷模板上邊緣和映像上邊緣的關係 img_up=1; %如果當前像素的高小於模板的一半,那麼選擇映像的上邊緣作為卷積映像的上邊緣 mark_up=r-i+1; %模板的上邊緣使用和映像相交的上邊緣 else img_up=i-r; %使用當前像素的高減去模板的一半作為卷積映像的上邊緣 mark_up=1; %使用模板的最上邊緣作為卷積模板的上邊緣 end if i+r>m %判斷模板下邊緣和映像下邊緣的關係 img_down=m; %如果當前像素的高加上模板的一半超過整個映像的高,那麼卷積映像的下邊緣使用整個映像的下邊緣 else img_down=i+r; %否則卷積映像的下邊緣使用當前像素的高加上模板的一半 end if j-r<1 %判斷模板左邊緣和映像左邊緣的關係 img_left=1; %如果當前像素的寬小於模板的一半,那麼選擇映像的左邊緣作為卷積映像的左邊緣 mark_left=r-j+1; %模板的左邊緣使用和映像相交的左邊緣 else img_left=j-r; %使用當前像素的寬減去模板的一半作為卷積映像的左邊緣 mark_left=1; %使用模板的最左邊緣作為卷積模板的左邊緣 end if j+r>n %判斷模板右邊緣和映像右邊緣的關係 img_right=n; %如果當前像素的寬加上模板的一般超過整個映像的寬,那麼卷積映像的右邊緣使用整個映像的右邊緣 else img_right=j+r; %否則卷積映像的右邊緣使用當前像素的寬加上模板的一半 end 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)); %卷積映像上邊緣:下邊緣,左邊緣:右邊緣 %卷積模板上邊緣:上邊緣+(豎直卷積範圍),卷積模板左邊緣:左邊緣+(水平卷積範圍) end endend
說實話,這個注釋寫的我很糾結,注釋我已經儘力寫清楚了,雖然我感覺還是沒解釋清楚。我果然需要鍛煉一下寫作與表達能力。
下面是:
原圖
自己寫的濾波時邊界處理的效果
通常的不做邊界處理的效果
Matlab函數處理的結果
我這個效果基本和matlab內建的效果很接近了,不過速度好像慢很多,matlab內建的函數也許使用彙編處理的,總之,演算法就是這樣啦。