天天看點

Python+OpenCV基礎教程2:平滑圖像

Python+OpenCV基礎教程2:平滑圖像

學習模糊/平滑圖像,消除噪點。圖檔等可到源碼處下載下傳。

1、目标

Python+OpenCV基礎教程2:平滑圖像

2、教程

濾波與模糊

推薦大家先閱讀:番外篇:卷積基礎(圖檔邊框),有助于了解卷積和濾波的概念。

關于濾波和模糊,很多人分不清,我來給大家理理(雖說如此,我後面也會混着用,,ԾㅂԾ,,):

它們都屬于卷積,不同濾波方法之間隻是卷積核不同(對線性濾波而言)

低通濾波器是模糊,高通濾波器是銳化

低通濾波器就是允許低頻信号通過,在圖像中邊緣和噪點都相當于高頻部分,是以低通濾波器用于去除噪點、平滑和模糊圖像。高通濾波器則反之,用來增強圖像邊緣,進行銳化處理。

常見噪聲有椒鹽噪聲和高斯噪聲,椒鹽噪聲可以了解為斑點,随機出現在圖像中的黑點或白點;高斯噪聲可以了解為拍攝圖檔時由于光照等原因造成的噪聲。

均值濾波

均值濾波是一種最簡單的濾波處理,它取的是卷積核區域内元素的均值,用cv2.blur()實作,如3×3的卷積核:

Python+OpenCV基礎教程2:平滑圖像
img = cv2.imread('lena.jpg')
blur = cv2.blur(img, (3, 3))  # 均值模糊           

所有的濾波函數都有一個可選參數borderType,這個參數就是番外篇:卷積基礎(圖檔邊框)中所說的邊框填充方式。

方框濾波

方框濾波跟均值濾波很像,如3×3的濾波核如下:

Python+OpenCV基礎教程2:平滑圖像

用cv2.boxFilter()函數實作,當可選參數normalize為True的時候,方框濾波就是均值濾波,上式中的a就等于1/9;normalize為False的時候,a=1,相當于求區域内的像素和。

# 前面的均值濾波也可以用方框濾波實作:normalize=True
blur = cv2.boxFilter(img, -1, (3, 3), normalize=True)           
高斯濾波

前面兩種濾波方式,卷積核内的每個值都一樣,也就是說圖像區域中每個像素的權重也就一樣。高斯濾波的卷積核權重并不相同:中間像素點權重最高,越遠離中心的像素權重越小,來,數學時間( ╯□╰ ),還記得标準正态分布的曲線嗎?

Python+OpenCV基礎教程2:平滑圖像

顯然這種處理元素間權值的方式更加合理一些。圖像是2維的,是以我們需要使用2維的高斯函數,比如OpenCV中預設的3×3的高斯卷積核(具體原理和卷積核生成方式請參考文末的番外小篇):

OpenCV中對應函數為cv2.GaussianBlur(src,ksize,sigmaX):

img = cv2.imread('gaussian_noise.bmp')

# 均值濾波vs高斯濾波
blur = cv2.blur(img, (5, 5))  # 均值濾波
gaussian = cv2.GaussianBlur(img, (5, 5), 1)  # 高斯濾波           

參數3 σx值越大,模糊效果越明顯。高斯濾波相比均值濾波效率要慢,但可以有效消除高斯噪聲,能保留更多的圖像細節,是以經常被稱為最有用的濾波器。均值濾波與高斯濾波的對比結果如下(均值濾波丢失的細節更多):

Python+OpenCV基礎教程2:平滑圖像
中值濾波

中值又叫中位數,是所有數排序後取中間的值。中值濾波就是用區域内的中值來代替本像素值,是以那種孤立的斑點,如0或255很容易消除掉,适用于去除椒鹽噪聲和斑點噪聲。中值是一種非線性操作,效率相比前面幾種線性濾波要慢。

比如下面這張斑點噪聲圖,用中值濾波顯然更好:

Python+OpenCV基礎教程2:平滑圖像
雙邊濾波

模糊操作基本都會損失掉圖像細節資訊,尤其前面介紹的線性濾波器,圖像的邊緣資訊很難保留下來。然而,邊緣(edge)資訊是圖像中很重要的一個特征,是以這才有了雙邊濾波。用cv2.bilateralFilter()函數實作:

img = cv2.imread('lena.jpg')

# 雙邊濾波vs高斯濾波
gau = cv2.GaussianBlur(img, (5, 5), 0)  # 高斯濾波
blur = cv2.bilateralFilter(img, 9, 75, 75)  # 雙邊濾波           
Python+OpenCV基礎教程2:平滑圖像

可以看到,雙邊濾波明顯保留了更多邊緣資訊。

3、番外小篇:高斯濾波卷積核

要解釋高斯濾波卷積核是如何生成的,需要先複習下機率論的知識(What??又是數學( ╯□╰ ))

一維的高斯函數/正态分布X∼N(μ,σ2)X∼N(μ,σ2):

Python+OpenCV基礎教程2:平滑圖像

當μ=0,σ2=1μ=0,σ2=1時,稱為标準正态分布X∼N(0,1)X∼N(0,1):

Python+OpenCV基礎教程2:平滑圖像

二維X/Y互相獨立的高斯函數:

Python+OpenCV基礎教程2:平滑圖像

由上可知,二維高斯函數具有可分離性,是以OpenCV分兩步計算二維高斯卷積,先水準再垂直,每個方向上都是一維的卷積。OpenCV中這個一維卷積的計算公式類似于上面的一維高斯函數:

Python+OpenCV基礎教程2:平滑圖像
Python+OpenCV基礎教程2:平滑圖像
print(cv2.getGaussianKernel(3, 0))
# 結果:[[0.25][0.5][0.25]]           

生成之後,先進行三次的水準卷積:

Python+OpenCV基礎教程2:平滑圖像

然後再進行垂直的三次卷積:

Python+OpenCV基礎教程2:平滑圖像

這就是OpenCV中高斯卷積核的生成方式。其實,OpenCV源碼中對小于7×7的核是直接計算好放在數組裡面的,這樣計算速度會快一點,感興趣的可以看下源碼:getGaussianKernel()

上面矩陣也可以寫成:

Python+OpenCV基礎教程2:平滑圖像

4、小結

在不知道用什麼濾波器好的時候,優先高斯濾波cv2.GaussianBlur(),然後均值濾波cv2.blur()。

斑點和椒鹽噪聲優先使用中值濾波cv2.medianBlur()。

要去除噪點的同時盡可能保留更多的邊緣資訊,使用雙邊濾波cv2.bilateralFilter()。

線性濾波方式:均值濾波、方框濾波、高斯濾波(速度相對快)。

非線性濾波方式:中值濾波、雙邊濾波(速度相對慢)。

文章轉載自 EX2TRON'S BLOG

http://ex2tron.wang/opencv-python-smoothing-images/

繼續閱讀