圖片處理前,往往進行雜訊去除的預處理,OpenCV提供了許多去除雜訊的函式,如果我們想要知道哪個函式較為適用,分析雜訊的生成方式會是首要任務。

從加入椒鹽雜訊開始

在使用OpenCV進行圖片處理前,特別是在二值化或尋找圖像邊緣之類的操作前,我們經常會看到當中已經先進行了模糊處理,這麼做是為了去除圖片的雜訊,最常使用的是GaussianBlur函式,然而OpenCV實際上提供了許多模糊函式,什麼時候該選擇這些函式呢?

事實上,你必須先釐清圖片中的雜訊是哪種類型,而想認識雜訊的類型,最好的方式,會是知道如何為圖片加入雜訊。

為什麼會想為圖片加上雜訊?理由還不少,例如,增加圖片的粗糙感、製造懷舊風格,或者是後製出噴砂的感覺,市面上,有不少影像處理軟體,都提供了增加雜訊之類的濾鏡。在程式設計上,若我們想知道怎麼加入雜訊,灰階圖片會是個簡單的開始,因為,此時我們只要需要面對每個像素的灰階值。

要在灰階圖片增加雜訊的方式之一,是在圖片中隨機地選擇像素位置,將灰階值設為0或255,這會形成黑或白的雜訊,黑點就好比胡椒,白點就像是鹽,於是,這種加上雜訊的方式,就稱為椒鹽雜訊(Salt & Pepper Noise)。

椒鹽雜訊是認識雜訊處理時一個很好的起點。如果我們針對撒下的雜訊做統計,以雜訊值為橫軸,各雜訊值出現的次數為縱軸畫出直方圖,估且稱這種圖為雜訊譜(Noise spectrum)的話,會只有兩條直條,分別出現在0與255的位置。

由於是單純地撒下黑或白,這種雜訊在圖中會很突兀。從雜訊譜來看,兩側的直線就像訊號中的突波,例如,在正常的音樂中突然發生爆音,環境中的燈光突然開始閃爍之類的,因而又稱為脈衝雜訊(Impluse noise)。就圖像而言,人眼很容易會察覺到雜訊的存在。

白雜訊與高斯雜訊

如果不是單純地撒下黑或白,而是在每個像素處生成隨機數,與既有的灰階值做運算呢?例如,透過numpy的random.randint,隨機生成數值,與既有像素灰階值相加後設為灰階值,若低於0就設為0,高於255設為255,由於隨機數的生成沒有任何規律,這就構成了白雜訊(White noise)。

若將隨機生成的雜訊,以方才提及的雜訊譜畫出來,我們可以發現這種雜訊,每個雜訊值各自的總數,大致是差不多數量,但為什麼這叫白雜訊呢?

我們知道,自然界中的白光,其實是環境中各種顏色,也就是各種頻率的光混合而成,「白」比喻的就是雜訊的分布,具有類似特性,你也可能聽過所謂的白噪音,也是借用了這類比喻,指的是具有各種頻率聲音的噪音,若頻率範圍在人類可接受的範圍內,而且各頻率的功率一致,據說很適合用來助眠。

白雜訊是由各種值組合而成(只是程式計算時還是得給個界線),每個雜訊間的值並不相關(不過程式中多半是偽隨機),視給定的隨機值範圍而定,若範圍小,鄰近像素間的變化小,稱之為低頻雜訊,若範圍大,鄰近像素間的變化大,稱為高頻雜訊。

白雜訊比較像是在打光均勻的環境中,將ISO開很大的照像時得到的雜訊;實際環境中光線明暗可能不均,亮的地方,整體雜訊值可能高些,暗的地方整體會有較低的雜訊值,然而,無論整體雜訊值是高或低,雜訊值的範圍內,落在中間值的可能性會比較高。

想生成這類雜訊的話,我們可以試試高斯雜訊(Gaussian noise),它產生的雜訊值依舊是隨機的,沒辦法預測會生成什麼值,然而將雜訊值加以統計,會呈現高斯分布,也就是常態分布。

例如,透過numpy的random.normal生成的亂數,是隨機不可預測的,然而,如果我們觀察雜訊譜,會發現當中會呈高斯分布。相對來說,高斯雜訊與原圖會比較融合,這類雜訊還可以透過調整平均值、標準差之類的參數,來生成不同的雜訊效果。

椒鹽雜訊、白雜訊、高斯雜訊是理解雜訊生成的入門,還有其他的雜訊生成方式,像是過去專欄我也曾談過的Perlin雜訊、Worley雜訊,還有其他如粉紅雜訊(Pink noise)、Poisson雜訊等,重要的是理解雜訊的原理,找出應用的方式,看看能否達到想要的效果。

雜訊的去除

若圖片本身有雜訊,代表像素資料失真,此時,我們只能想辦法從圖像的其他像素中取得資訊,儘可能去模擬出接近人眼,或者人眼所無法察覺的像素值。

如果是選擇鄰近NxN像素加總後平均(N通常為奇數),這種方式稱為均值濾波(Mean filter),OpenCV的blur函式就是實作之一,優點是實作簡單、運算速度快,既然是取平均,表示鄰近像素的差異不能太大,因而適用於去除低頻雜訊,然而,面對椒鹽雜訊時,均值濾波就沒什麼效果,而且取平均值的結果就是,圖像邊緣也會跟著模糊,N越大就越模糊。

如果取鄰近像素值排序後取中間數,稱為中值濾波(Median filter),OpenCV的medianBlur函式是其實作,若鄰近像素數量選擇適當,中值濾波可以有效地處理椒鹽雜訊(或者圖片中隨機散落的雜點),也能夠保留較多邊緣的細節,不過,鄰近像素取得越多,細節保留的效果會越差。

方才談到均值濾波的原理,是單純取鄰近像素的平均值,高斯濾波的原理也是取鄰近像素平均值,然而,計算平均值時會考慮鄰近像素的權重,權重是透過二維的高斯函式來計算,也就是考量了一定範圍內的雜訊會具有高斯分布。而實際環境中,不少雜訊分布就具有此特性,因此高斯濾波常用來去除照片中的雜訊,缺點就是計算上比較耗時,OpenCV中的GaussianBlur函式提供了實現。

若我們想試著實作雜訊的生成與去除,〈Image Noise & Spatial Domain Filtering〉有三篇不錯的文件,可以參考看看。

均值濾波、中值濾波、高斯濾波等,是認識雜訊去除(也是模糊處理)很好的一個起點,因為,它們都利用像素的局部資訊,來達到去除雜訊之目的;然而,關於雜訊去除的處理,還有許多其他方式,例如,透過分析整個圖片的資訊,來達到去除雜訊的目的,而在OpenCV的官方文件〈Image Denoising〉中,就談到這類雜訊去除的相關函式。

分析雜訊是第一步

關於圖片呈現的平滑處理上,OpenCV官方稱GaussianBlur或許是最好的方式,而對於照片之類的對象,GaussianBlur函式大多能派上用場,但是,也不是想去除雜訊就是GaussianBlur函式,我們大致瞭解原理後應該也能發覺:它對於椒鹽雜訊、或者圖片中隨機散落的雜點就顯得無力。

因此想要去除雜訊,分析雜訊是首要任務,接著認識相關函式去除雜訊的原理,雖然有些可能充斥著數學之類的理論,然而試著理解的過程中,往往對於雜訊的分析也會產生助益,也就更能知道選擇哪個適當的方式以去除雜訊了。

專欄作者

熱門新聞

Advertisement