在圖像處理中,會用到對圖像的平滑處理。平滑常常被用來消除圖像的噪聲,下面介紹幾個常用於圖像平滑處理的函數。
(1)blur
平滑處理常常用到的是線性濾波器。線性濾波器的數學基礎建立在卷積的概念之上。對於一個線性濾波器,變換之后圖像的輸出值其實就是該點的某個鄰域內各點輸入像素值的加權求和。假如我們現在有一幅M*N的圖像要進行線性濾波,我們采用的卷積核(kernel)的大小為m*n,那么處理之后的圖像每一點的輸出像素值由下面這個式子確定:
上面這個式子的分子其實就是源圖像f(x,y)與我們所用的卷積核w做卷積運算,而分母是w中各個元素的求和結果,這樣就為鄰域內不同位置分配了不同的權重。需要注意的是,一旦w被確定,那么分母其實是一個常數,所以我們應該提前算出分母的值,避免直接代入上式造成的重復計算和不必要的時間浪費。
而OpenCV中的blur函數就是上面所提到的線性濾波中的一種。它和其他線性濾波算法的共性點自然在於它也是一個線性濾波器,滿足疊加原理。
個性的地方在於這種線性濾波所用的卷積核的各個元素都是相等的,都是1,也就是它對該點鄰域內的各個其他點“一視同仁”,“不分彼此”。所以這時候,分母的大小是m*n,分子呢?自然就是鄰域內各點像素值求和。而這種“大鍋飯”的壞處,便是消除噪聲的同時也使得源圖像的某些細節變得模糊不清。具體模糊的程度要看我們所選用的卷積核的大小(也就是m,n的大小)和圖像細節處的像素范圍。請看下面的例子(取自岡薩雷斯數字圖像處理一書),這個例子分別展示了原圖和經過blur函數處理后的圖像,所用的卷積核的大小依次為3*3,5*5,9*9,15*15,35*35,從字母a和噪聲區域以及幾個圓形點的變化可以比較容易地看出圖像模糊是如何受到卷積核大小和細節本身所影響的:
string name="image.tif"; Mat src=imread (name,CV_LOAD_IMAGE_GRAYSCALE); imshow ("Original",src); imwrite ("Original Image.tif",src); Mat dst; blur (src,dst,Size(3,3)); imshow ("size=3",dst); imwrite ("size=3.tif",dst);
(2)高斯濾波器
由於blur的“大鍋飯”政策使得圖像的模糊比較嚴重,所以人們又提出了其他的分配權重的方法,其中之一便是高斯濾波。高斯濾波的思想便是根據鄰域內的點到中心點的距離來按照高斯函數分配權重。還記得那個鍾形函數的曲線嗎??
“假設圖像是1維的,那么觀察上圖,不難發現中間像素的加權系數是最大的, 周邊像素的加權系數隨着它們遠離中間像素的距離增大而逐漸減小。”
二維的Guass函數可以寫成如下的形式:
值得一提的是,高斯函數作為一種很典型的函數,被廣泛地應用於權重分配等一些場合,比如局部加權回歸(locally wighted regression)。
同時要注意到,雖然高斯函數並不是一個線性函數,但是由於它的思想仍然是給不同區域的像素點分配不同的權重。本質上和blur並沒有什么區別,它仍然是一種線性濾波。它的非線性體現在了權重的分配過程中,而這個分配過程是距離的函數,並不是像素值的函數!
同時標准差的不同,也會對濾波結果產生比較大的影響。實際過程中如何選擇標准差,也是應該考慮的問題之一。可以知道,標准差越大,高斯函數的圖像會越扁平,也就是說權重的下降速度會變慢,高斯濾波也就越接近於blur;標准差越小,高斯函數的圖像會越高瘦,也就是認為數據集中程度較好,權重會隨着距離的增大迅速衰減,這樣模糊化程度會減弱,但是消除噪聲的能力會下降。所以說,標准差的大小實際是對權重分配的再調整。
string name="image.tif"; Mat src=imread (name,CV_LOAD_IMAGE_GRAYSCALE); imshow ("Original",src); Mat dst; GaussianBlur (src,dst,Size(3,3),1); //x方向的標准差選為1 imshow ("高斯濾波",dst); imwrite ("高斯濾波結果.tif",dst);

(3)中值濾波
中值濾波是一種非線性濾波方法。顧名思義,這種濾波方法會將鄰域內的像素值排序,選出中值賦給輸出像素點。這種濾波方法模糊化較輕,尤其適用於被椒鹽噪聲污染的圖像。
對比一下就可以發現中值濾波很好地去除了噪聲。
string name="CircuitBoard.tif"; Mat src=imread (name,CV_LOAD_IMAGE_GRAYSCALE); //線性濾波 Mat blurFilter; blur(src,blurFilter,Size(3,3)); //中值濾波 Mat medianFilter; medianBlur (src,medianFilter,3); imshow("椒鹽噪聲污染的圖像",src); imshow("線性濾波結果",blurFilter); imshow("中值濾波結果",medianFilter); imwrite ("線性濾波結果.tif",blurFilter); imwrite ("中值濾波結果.tif",medianFilter);
(4)雙邊濾波
雙邊濾波也是一種非線性濾波方法。出於減輕圖象去噪后模糊的問題,雙邊濾波不僅考慮權重隨着距離衰減,同樣也認為像素值相差越多,所占的權重應該越小。“雙邊濾波器也給每一個鄰域像素分配一個加權系數。 這些加權系數包含兩個部分, 第一部分加權方式與高斯濾波一樣,第二部分的權重則取決於該鄰域像素與當前像素的灰度差值。”
由於權重的分配過程中不但涉及到距離信息,更涉及到了像素值,所以容易想到這是一種非線性濾波方法。
對於這種濾波方法,這個網址給出了一份比較詳細的數學論證:雙邊濾波的數學原理。要注意一點,雙邊濾波不一定要靠高斯函數來實現,但是高斯函數是一種很常用的分配權重的方法。而且我個人認為,由於“中心極限定理”,高斯函數應該是一種比較好的分配方法。
這種方法的好處便是能夠在去噪和抗模糊化中取得一種比較好的折中效果。
這個函數的調用格式為(這里參考了鄰域濾波:方框、高斯、中值、雙邊濾波這篇博客和圖像平滑處理這個教程的內容):
bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT );
d 表示濾波時像素鄰域直徑,d為負時由 sigaColor計算得到;d>5時不能實時處理。