天天看點

Python中圖像平滑方法的兩種非線性濾波:中值濾波、雙邊濾波

作者:華為雲開發者聯盟

本文分享自華為雲社群《[Python從零到壹] 五十六.圖像增強及運算篇之圖像平滑(中值濾波、雙邊濾波)-雲社群-華為雲》,作者:eastmount。

常用于消除噪聲的圖像平滑方法包括三種線性濾波(均值濾波、方框濾波、高斯濾波)和兩種非線性濾波(中值濾波、雙邊濾波),本文将詳細講解兩種非線性濾波方法。

一.中值濾波

前面講述的都是線性平滑濾波,它們的中間像素值都是由鄰域像素值線性權重得到的,接下來将講解一種非線性平滑濾波——中值濾波。中值濾波通過計算每一個像素點某鄰域範圍内所有像素點灰階值的中值,來替換該像素點的灰階值,進而讓周圍的像素值更接近真實情況,消除孤立的噪聲。

中值濾波對脈沖噪聲有良好的濾除作用,特别是在濾除噪聲的同時,能夠保護圖像的邊緣和細節,使之不被模糊處理,這些優良特性是線性濾波方法所不具有的,進而使其常常被應用于消除圖像中的椒鹽噪聲[1-2]。

中值濾波算法的計算過程如圖1所示。選擇含有五個點的視窗,依次掃描該視窗中的像素,每個像素點所對應的灰階值按照升序或降序排列,然後擷取最中間的值來替換該點的灰階值。

Python中圖像平滑方法的兩種非線性濾波:中值濾波、雙邊濾波

上圖展示的是矩形視窗,常用的視窗還包括正方形、十字形、環形和圓形等,不同形狀的視窗會帶來不同的過濾效果,其中正方形和圓形視窗适合于外輪廓邊緣較長的圖像,十字形視窗适合于帶尖角形狀的圖像。

OpenCV将中值濾波封裝在medianBlur()函數中,其函數原型如下所示:

  • dst = medianBlur(src, ksize[, dst])

    – src表示待處理的輸入圖像

    – dst表示輸出圖像,其大小和類型與輸入圖像相同

    – ksize表示核心大小,其值必須是大于1的奇數,如3、5、7等

下面是調用medianBlur()函數實作中值濾波的代碼。

# -*- coding: utf-8 -*-
# By:Eastmount
import cv2  
import numpy as np  
import matplotlib.pyplot as plt

#讀取圖檔
img = cv2.imread('lena-zs.png')
source = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)

#中值濾波
result = cv2.medianBlur(source, 3)

#用來正常顯示中文标簽
plt.rcParams['font.sans-serif']=['SimHei']

#顯示圖形
titles = ['原始圖像', '中值濾波']
images = [source, result]
for i in range(2):
   plt.subplot(1,2,i+1), plt.imshow(images[i], 'gray')
   plt.title(titles[i])
   plt.xticks([]),plt.yticks([])
plt.show()
           

其運作結果如圖2所示,它有效地過濾掉了“lena”圖中的噪聲,并且很好地保護了圖像的邊緣資訊,使之不被模糊處理。

Python中圖像平滑方法的兩種非線性濾波:中值濾波、雙邊濾波

二.雙邊濾波

雙邊濾波(Bilateral filter)是由Tomasi和Manduchi在1998年發明的一種各向異性濾波,它一種非線性的圖像平滑方法,結合了圖像的空間鄰近度和像素值相似度(即空間域和值域)的一種折中處理,進而達到保邊去噪的目的。雙邊濾波的優勢是能夠做到邊緣的保護,其他的均值濾波、方框濾波和高斯濾波在去除噪聲的同時,都會有較明顯的邊緣模糊,對于圖像高頻細節的保護效果并不好[3]。

雙邊濾波比高斯濾波多了一個高斯方差sigma-d,它是基于空間分布的高斯濾波函數。是以在圖像邊緣附近,離的較遠的像素點不會過于影響到圖像邊緣上的像素點,進而保證了圖像邊緣附近的像素值得以儲存。但是雙邊濾波也存在一定的缺陷,由于它儲存了過多的高頻資訊,雙邊濾波不能有效地過濾掉彩色圖像中的高頻噪聲,隻能夠對低頻資訊進行較好地去噪[4]。

在雙邊濾波器中,輸出的像素值依賴于鄰域像素值的權重值組合,對輸入圖像進行局部權重平均得到輸出圖像 的像素值,其公式如下所示:

Python中圖像平滑方法的兩種非線性濾波:中值濾波、雙邊濾波

式中表示中心點(x,y)的(2N+1)×(2N+1)的領域像素,值依賴于領域像素值的權重平均。權重系數取決于空間域核(domain)和值域核(range)的乘積。空間域核的定義如公式(2)所示。

Python中圖像平滑方法的兩種非線性濾波:中值濾波、雙邊濾波

值域核的定義如公式(3)所示。

Python中圖像平滑方法的兩種非線性濾波:中值濾波、雙邊濾波

兩者相乘之後,就會産生依賴于資料的雙邊濾波權重函數,如下所示:

Python中圖像平滑方法的兩種非線性濾波:中值濾波、雙邊濾波

從式子(4)可以看出,雙邊濾波器的權重系數是空間鄰近度因子和像素亮度相似因子的非線性組合。前者随着像素點與中心點之間歐幾裡德距離的增加而減小,後者随着像素亮度之差的增大而減小[5-6]。

在圖像變化平緩的區域,鄰域内亮度值相差不大,雙邊濾波器轉化為高斯低通濾波器;在圖像變化劇烈的區域,鄰域内像素亮度值相差較大,濾波器利用邊緣點附近亮度值相近的像素點的亮度平均值替代原亮度值。是以,雙邊濾波器既平滑了圖像,又保持了圖像邊緣,其原理圖如圖3所示。

Python中圖像平滑方法的兩種非線性濾波:中值濾波、雙邊濾波

OpenCV将中值濾波封裝在bilateralFilter()函數中,其函數原型如下所示:

  • dst = bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]])

    – src表示待處理的輸入圖像

    – dst表示輸出圖像,其大小和類型與輸入圖像相同

    – d表示在過濾期間使用的每個像素鄰域的直徑。如果這個值我們設其為非正數,則它會由sigmaSpace計算得出

    – sigmaColor表示顔色空間的标準方差。該值越大,表明像素鄰域内較遠的顔色會混合在一起,進而産生更大面積的半相等顔色區域

    – sigmaSpace表示坐标空間的标準方差。該值越大,表明像素的顔色足夠接近,進而使得越遠的像素會互相影響,更大的區域中相似的顔色擷取相同的顔色,當d>0,d指定了鄰域大小且與sigmaSpace無關。否則,d正比于sigmaSpace

    – borderType表示邊框模式,用于推斷圖像外部像素的某種邊界模式,預設值為BORDER_DEFAULT,可省略

下面是調用bilateralFilter()函數實作雙邊濾波的代碼,其中d為15,sigmaColor設定為150,sigmaSpace設定為150。

# -*- coding: utf-8 -*-
# By:Eastmount
import cv2  
import numpy as np  
import matplotlib.pyplot as plt
 
#讀取圖檔
img = cv2.imread('lena-zs.png')
source = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
 
#雙邊濾波
result = cv2.bilateralFilter(source, 15, 150, 150)

#用來正常顯示中文标簽
plt.rcParams['font.sans-serif']=['SimHei']

#顯示圖形
titles = ['原始圖像', '雙邊濾波']  
images = [source, result]
for i in range(2):
   plt.subplot(1,2,i+1), plt.imshow(images[i], 'gray')
   plt.title(titles[i])
   plt.xticks([]),plt.yticks([])
plt.show()
           

其運作結果如圖4所示:

Python中圖像平滑方法的兩種非線性濾波:中值濾波、雙邊濾波

三.總結

本文主要講解了常用于消除噪聲的圖像平滑方法,常見方法包括三種線性濾波(均值濾波、方框濾波、高斯濾波)和兩種非線性濾波(中值濾波、雙邊濾波)。這篇文章介紹了中值濾波和雙邊濾波,通過原理和代碼進行對比,分别講述了各種濾波方法的優缺點,有效地消除了圖像的噪聲,并保留圖像的邊緣輪廓。

點選下方,第一時間了解華為雲新鮮技術~

華為雲部落格_大資料部落格_AI部落格_雲計算部落格_開發者中心-華為雲