本篇文章介紹如何用OpenCV-Python來實現初級濾波功能。
本文來自https://blog.csdn.net/sunny2038/article/details/9155893
簡介
過濾是信號和圖像處理中基本的任務。其目的是根據應用環境的不同,選擇性的提取圖像中某些認爲是重要的信息。過濾可以移除圖像中的噪音、提取感興趣的可視特徵、允許圖像重採樣,等等。其源自於一般的信號和系統理論,這裏將不介紹該理論的細節。但本章會介紹關於過濾的基本概念,以及如何在圖像處理程序中使用濾波器。首先,簡要介紹下頻率域分析的概念。
當我們觀察一張圖片時,我們觀察的是圖像中有多少灰度級(或顏色)及其分佈。根據灰度分佈的不同來區分不同的圖像。但還有其他方面可以對圖像進行分析。我們可以觀察圖像中灰度的變化。某些圖像中包含大量的強度不變的區域(如藍天),而在其他圖像中的灰度變化可能會非常快(如包含許多小物體的擁擠的圖像)。因此,觀察圖像中這些變化的頻率就構成了另一條分類圖像的方法。這個觀點稱爲頻域。而通過觀察圖像灰度分佈來分類圖像稱爲空間域。
頻域分析將圖像分成從低頻到高頻的不同部分。低頻對應圖像強度變化小的區域,而高頻是圖像強度變化非常大的區域。目前已存在若干轉換方法,如傅立葉變換或餘弦變換,可以用來清晰的顯示圖像的頻率內容。注意,由於圖像是一個二維實體,所以其由水平頻率(水平方向的變化)和豎直頻率(豎直方向的變化)共同組成。
在頻率分析領域的框架中,濾波器是一個用來增強圖像中某個波段或頻率並阻塞(或降低)其他頻率波段的操作。低通濾波器是消除圖像中高頻部分,但保留低頻部分。高通濾波器消除低頻部分
本篇文章介紹在OpenCV-Python中實現的初級的濾波操作,下一篇文章介紹更加複雜的濾波原理及其實現。
本篇文章使用傳統的lena作爲實驗圖像。
用低通濾波來平滑圖像
低通濾波器的目標是降低圖像的變化率。如將每個像素替換爲該像素周圍像素的均值。這樣就可以平滑並替代那些強度變化明顯的區域。在OpenCV中,可以通過blur函數做到這一點:
dst = cv2.blur(image,(5,5));
其中dst是blur處理後返回的圖像,參數一是輸入的待處理圖像,參數2是低通濾波器的大小。其後含有幾個可選參數,用來設置濾波器的細節,具體可查閱參考資料2。不過這裏,這樣就夠了。下面是一個簡單的示例代碼:
import cv2
img = cv2.imread(r'C:\contentpic\2018\09\17\20180917150947_5310158069_580328.jpg',0)
result = cv2.blur(img,(5,5))
print(result)
cv2.imshow("Origin", img)
cv2.imshow("Blur", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
結果如下,左邊是平滑過的圖像,右邊是原圖像:
這種濾波器又稱爲boxfilter(注,這與化學上的箱式過濾器是兩碼事,所以這裏就不翻譯了)。所以也可通過OpenCV的cv2.bofxfilter(...)函數來完成相同的工作。如下:
result = cv2.boxFilter(img, -1, (5, 5))
這行代碼與上面使用blur函數的效果完全相同。其中第二個參數的-1表示輸出圖像使用的深度與輸入圖像相同。後面還有幾個可選參數,具體可查閱OpenCV文檔。
高斯模糊
在某些情況下,需要對一個像素的周圍的像素給予更多的重視。因此,可通過分配權重來重新計算這些周圍點的值。這可通過高斯函數(鐘形函數,即喇叭形數)的權重方案來解決。cv::GaussianBlur函數可作爲濾波器用下面的方法調用:
gaussianResult = cv2.GaussianBlur(img,(5,5),1.5)
數返回處理結果,第一個參數是待處理圖像,第二個參數是孔徑的尺寸,一個大於1的奇數。比如這裏是5,中值濾波器就會使用5×5的範圍來計算。即對像素的中心值及其5×5鄰域組成了一個數值集,對其進行處理計算,當前像素被其中值替換掉。
區別
低通濾波與高斯濾波的不同之處在於:低通濾波中,濾波器中每個像素的權重是相同的,即濾波器是線性的。而高斯濾波器中像素的權重與其距中心像素的距離成比例。關於高斯模糊的詳細內容,抽空將寫一篇獨立的文章介紹。
使用中值濾波消除噪點
前面介紹的是線性過濾器,這裏介紹非線性過濾器——中值濾波器。由於中值濾波器對消除椒鹽現象特別有用。所以我們使用第二篇教程中椒鹽函數先對圖像進行處理,將處理結果作爲示例圖片。
調用中值濾波器的方法與調用其他濾波器的方法類似,如下:
result = cv2.medianBlur(image,5)
函數返回處理結果,第一個參數是待處理圖像,第二個參數是孔徑的尺寸,一個大於1的奇數。比如這裏是5,中值濾波器就會使用5×5的範圍來計算。即對像素的中心值及其5×5鄰域組成了一個數值集,對其進行處理計算,當前像素被其中值替換掉。
如果在某個像素周圍有白色或黑色的像素,這些白色或黑色的像素不會選擇作爲中值(最大或最小值不用),而是被替換爲鄰域值。代碼如下:
import cv2
import numpy as np
def salt(img, n):
for k in range(n):
i = int(np.random.random() * img.shape[1]);
j = int(np.random.random() * img.shape[0]);
if img.ndim == 2:
img[j, i] = 255
elif img.ndim == 3:
img[j, i, 0] = 255
img[j, i, 1] = 255
img[j, i, 2] = 255
return img
img = cv2.imread(r"C:\contentpic\2018\09\17\20180917150947_5310158069_580328.jpg", 0)
result = salt(img, 500)
median = cv2.medianBlur(result, 5)
cv2.imshow("Salt", result)
cv2.imshow("Median", median)
cv2.waitKey(0)
結果如下圖所示
由於中值濾波不會處理最大和最小值,所以就不會受到噪聲的影響。相反,如果直接採用blur進行均值濾波,則不會區分這些噪聲點,濾波後的圖像會受到噪聲的影響。
中值濾波器在處理邊緣也有優勢。但中值濾波器會清除掉某些區域的紋理(如背景中的樹)。
其他
由於方向濾波器與這裏的原理有較大的出入,所以將用獨立的一篇文章中介紹其原理以及實現。