1. 程式人生 > >高斯模糊的實現方法

高斯模糊的實現方法

轉載;http://blog.csdn.net/markl22222/article/details/10313565  

一、高斯模糊是什麼

模糊演算法,不論是使用哪種演算法,目的都是為了讓圖片看起來不如原來那麼清晰。

清晰的圖片,畫素間的過渡會較為乾脆利落,簡而言之,就是畫素之間的差距比較大。
而模糊的本質,其實就是使用某種演算法把影象畫素和畫素之間的差距縮小,讓中間點和周圍點變得差不多;即,讓中間點取一個範圍內的平均值。
模糊到了極致,比如用於計算模糊的取值區域為整張圖片,就會得到一張全圖所有畫素顏色都差不多的圖片:


左邊是原圖,右邊是徹底模糊之後的對比圖

計算模糊的取值區域就是濾鏡區域,那麼關鍵就是,我們採用什麼曲線函式來生成平均值了。

假設濾鏡區域為正方形,且半徑為r,我們可以用如下曲線函式來計算圖片上某一個點的值:


這是一個非常簡單的直線函式,求得的點值即為算術平均值,圖片上某個點的值僅和模糊半徑r有關,與座標的位置無關。

由此我們可以得到用於模糊影象的濾鏡演算法:

每個畫素通道的最大值不能超過255,若賦予的值超出了通道最大值,則將通道值限制在最大值上。

使用上面的演算法,設定濾鏡半徑為5,處理出來的圖片效果如下:


左邊是原圖,右邊是對比圖

模糊成功了,但效果有些不盡人意,圖片的一些邊緣細節模糊得並不柔和,感覺像沒戴眼鏡的近視眼看起來的效果。

從上面的演算法裡我們可以看出,濾鏡中填充的每一個值,可以看做是一個權重。在處理影象的時候,通過它計算出濾鏡範圍內每個畫素的權重值,最後將它們相加,得到的就是濾鏡中心點的畫素值。
使用上面的模糊演算法,在處理圖片的時候,對所有的畫素點是一視同仁的。但實際上,離中心點越遠的點,重要性應該越低才更合理。
也就是說,越靠近濾鏡邊緣的畫素,權重更小才會更符合實際。

高斯分佈,即正態分佈曲線,形狀大概如下圖:

它就是一個可以計算出符合上面要求的權重分佈的函式,對應的二維形式如下:

使用高斯分佈曲線作為濾鏡演算法的模糊演算法,稱之為高斯模糊

二、高斯模糊演算法實現

設定濾鏡半徑為5,通過與前文一樣的遍歷演算法,我們可以得到下面的模糊效果:


左邊是原圖,右邊是對比圖

這個效果不夠明顯,我們可以設更大一點的濾鏡,比如10,處理出來的效果如下:


左邊是原圖,右邊是對比圖

好了,模糊成功了。效率怎麼樣呢?
在我的電腦上(i3M330,2.13G),使用 半徑10 的濾鏡處理 400 × 649 的圖片,Debug版本需要大約 8s 左右,Release版本則為916ms。
這個速度就算在Release下也偏慢了。

研究一下我們的演算法:
當濾鏡半徑為r時,演算法的時間複雜度是O(x × y × (2r)²)。
能否降低一點呢?

三、高斯模糊演算法優化

引用維基百科裡的原文:

“除了圓形對稱之外,高斯模糊也可以在二維影象上對兩個獨立的一維空間分別進行計算,這叫作線性可分。這也就是說,使用二維矩陣變換得到的效果也可以通過在水平方向進行一維高斯矩陣變換加上豎直方向的一維高斯矩陣變換得到。”

這個特徵讓我們可以使用一維的高斯函式,在橫縱兩個方向上分別處理一次影象,得到和二維高斯函式一樣的效果。
使用一維高斯函式,演算法的時間複雜度就變為O(2 × x × y × 2r),兩相比較,演算法效率高出r倍。

一維形式的高斯函式如下:

四、其它模糊演算法

從上面的文字裡,我們已經知道了高斯模糊演算法其實就是利用高斯函式或者說曲線,生成模糊濾鏡,然後對影象畫素做處理的演算法。
那麼我們可以考慮使用其它曲線來作為我們的模糊曲線麼?

當然是可以的。
文章的最開始就使用了最簡單的算術平均值曲線作為模糊曲線,只是實際的效果較為一般。

我們可以再嘗試其他的曲線函式,比如直線函式:


求絕對值是為了讓函式曲線保持“中間高兩邊低”

使用其他函式得到的濾鏡演算法和處理的圖片效果本文就不再一一贅述了。感興趣的朋友可以下載文後所附的程式碼。

附件裡的模糊演算法實現在filter.h中,VC和gcc編譯器下均編譯通過。測試平臺基於win32下的Qt 5.0.1,編譯器為MinGW 4.7。