可以保留影像邊緣的超強平滑濾波

Fammy 蔡豐名
Taiwan AI Academy
Published in
6 min readJan 7, 2020

# CVPR 2019 Oral paper: Side Window Filtering

幾乎消除所有雜訊點!並保留了邊界資訊!

這是一篇極少數沒有使用 deep learning 並入選 CVPR 的 paper

他提出的概念非常簡單而有效,先來看看我用 python 實作重現的結果

下圖左是我們 AIA 的執行長、圖右是加了椒鹽雜訊的影像

下圖左是未經平滑濾波處理的原始雜訊影像

圖中是使用 cv2.blur 傳統的 3 x 3 均值濾波器

圖右是使用這篇 paper 的方法簡稱 SWF 套用在傳統的 3 x 3 均值濾波器上

經過 5 次的 mean filter 之後,已經可以明顯看出 SWF 在保留影像邊界上有極好的效果,反觀傳統的濾波器模糊了影像,再繼續套更多次的 iterations 看看結果

明顯可以看到傳統的濾波器就是越來越模糊,反觀 SWF 方法似乎收斂了,並且保持了非常多的影像邊界

這就是這篇論文 Side Window Filtering 提出的神奇方法,接下來會很簡單的介紹是怎麼做的,如果對詳細的內容有興趣,可以參考原論文或是 google 這個關鍵字也有許多網路上的解析文章

以及最後附有 Python 實作程式碼

(網路上好像都找不到 python 的 code,只好自己刻了)

開始簡單介紹 SWF 原理吧!

# Side Window Filtering

首先,我們先回顧一下 3 x 3 的均值濾波器

如果套用到以下的這個矩陣結果會是

這個計算結果應該相當直觀,3 x 3 大小的 kernel 會把交界處平均

可以發現所有濾波器所使用的 kernel 都是以正中央作為重心的

上圖中黃底 0 的位置變成 3.33了,因為均值濾波器會以自己為中心看周圍的其他人,如果自己身在邊界處,勢必就會把邊界給模糊掉了

相對的,10 的邊界處也被模糊成 6.67 了

所以作者提出 Side Window 的想法,如果今天 kernel 長成下面這樣呢

一樣以 kernel 正中央為中心,但我只看我左手邊的人

套用到一樣的矩陣的話,可以得到下面的結果

原本 0 的位置不會被平均了!很好的保持了這個邊界的資訊

你可能發現了,那 0 右邊的這個 10 呢!?這個邊界資訊還是會被模糊掉啊

為了保持這個 10 的邊界資訊,很直觀的,下面這個 kernel 可以做到

套進矩陣結果如下

10 經過濾波器還是維持 10,但左邊的 0 又被平均成 5 了

但你可能想到了,如果把這兩個 kernel 結合起來呢!?

通過兩種 kernel 之後就會得到右邊的兩個結果

以黃底的 10 來說,上方的 kernel 可以很好保持這個邊界,而下方的 kernel 則會平滑掉

那選擇也非常直覺了,我們針對矩陣每個位置的數值,選擇與原數值差距最小的就可以了!

黃底的數字是經過 filter 之後沒有改變的

這就是 Side Window Filtering 的核心概念!

通過各種角度的 Filter 之後選擇變化最小的!

Paper 中提出了三種最常見的邊界

剛剛上面的例子其實就是 (a) 這種高台型的邊界,在傳統的 CV filtering 中因為都以自我為中心看周圍全部,所以勢必這些邊界都會被模糊化

那當然上面的例子只要用兩種方向的 kernel 就能夠克服,但現實的影像邊界會有各式各樣的角度

所以!那我們就也用各式各樣的角度出發去做 Side Window Filtering!

原論文實作中用了下列八種角度

套用在 3 x 3 的均值濾波器的話,就是下面八種方向 kernel

如此一來就能考慮更多種的邊界,每一次做濾波的時候,每一個 pixel 點都套上這 8 個方向的均值 kernel,再從中選擇與自己差距最小的那個作為輸出

那是不是能夠 cover 更多種的邊界角度呢?應該是可以的,我在我的實作中提供了下面 4 種更多角度的 kernel,相對的運算時間就需要更長

以上就是簡單的理解 Side Window Filtering 方法的概念

也可以發現這個方法可以套用在任何一種 filter 的 kernel 上實現

底下的程式碼實作出了 Mean Blur 均值平滑、Gaussian Blur 高斯平滑以及 Median Blur中位數平滑三種 kernel,未來可以再加入更多種 kernel,支援 (3 x 3), (5 x 5), (7 x 7), (9 x 9), … 等等大小的 kernel size

大家可以帶入自己的應用領域試試看喔!

最後附上 Python 實作的程式碼

實作中會使用大量的 for loop 以及矩陣的位置存取,以 Python 實作將會非常非常慢,我想也是網路上找不到 Python 實作程式碼的原因之一

這份實作中用了 numba just-in-time 的 compile 將 Python 的迴圈以及矩陣操作運算達到很大幅度的加速

謝謝你的閱讀,希望有帶給你幫助 >_<’’

--

--

Fammy 蔡豐名
Taiwan AI Academy

曾擔任 AIA 台灣人工智慧學校新竹分校助教,對技術與教學充滿熱忱,現為一線 IC 設計廠 AI 顧問