相信很多小伙伴都聽過“濾波器”這個詞,在通信領域,濾波器能夠去除噪聲信號等頻率成分,然而在我們OpenCV中,“濾波”並不是對頻率進行篩選去除,而是實現了圖像的平滑處理。接下來,這篇隨筆介紹使用OpenCV進行圖像處理的第六章 圖像平滑處理。
6 圖像平滑處理
未經處理的圖像含有噪聲的影響,所以我們希望盡可能保留原圖像的信息,過濾掉圖像內部的噪聲像素,得到平滑圖像,這個過程稱作圖像的平滑處理。
一幅圖像中,若某一像素點與周圍像素值差異過大,該像素點很可能是噪聲,則需要把值調整為周圍的像素點的近似值。如圖所示:
那么,如何對圖像進行平滑處理過濾噪聲呢?OpenCV提供了多種計算方法,有:
均值濾波
方框濾波
高斯濾波
中值濾波
雙邊濾波
2D卷積濾波(自定義濾波)
6.1 均值濾波
均值濾波是指使用當前N×N個像素值的均值來替代當前像素值,例如使用周圍3×3的像素點對第3行第3列像素值做均值濾波,如圖:
新值=(179+176+175+176+31+179+180+185+181)/ 9 = 162
也相當於,對上圖黃色區域矩陣乘以3×3的卷積核,該均值濾波3×3的卷積核如下(右側矩陣):
OpenCV提供了cv2.blur()函數進行均值濾波,舉例程序如下:
1 #針對噪聲圖像,使用不同大小的卷積核對其進行均值濾波,並顯示均值濾波的情況 2 import cv2 3 o=cv2.imread('E:\python_opencv\lena.jpg') 4 r5=cv2.blur(o,(5,5)) #5×5卷積核進行均值濾波 5 r30=cv2.blur(o,(30,30)) #30×30卷積核進行均值濾波 6 cv2.imshow('original',o) 7 cv2.imshow('result5',r5) 8 cv2.imshow('result30',r30) 9 cv2.waitKey() 10 cv2.destroyAllWindows()
運行結果如下圖,左為原圖像,中間及右側是為均值濾波處理結果,卷積核依次增大。
可以看出,卷積核越大,參與到均值運算的像素越多;卷積核越大,去噪效果越好,圖像失真會越嚴重,計算時間也會越長。所以我們要在圖像去噪和失真之間找到平衡,選擇大小合適的卷積核。
6.2 方框濾波
方框濾波可以選擇對周圍每個像素值求平均值,或周圍像素值之和而不求平均。
OpenCV提供了cv2.boxFilter()函數進行方框濾波,舉例程序如下:
1 #針對噪聲圖像,用方框濾波函數cv2.boxFilter()去噪 2 import cv2 3 o=cv2.imread('E:\python_opencv\lena.jpg') 4 #參數normalize的值設置為0,卷積核大小設置成2×2 5 r1=cv2.boxFilter(o,-1,(2,2),normalize=0) 6 #參數normalize的值設置為1,卷積核大小設置成2×2 7 r2=cv2.boxFilter(o,-1,(2,2),normalize=1) 8 cv2.imshow('original',o) 9 cv2.imshow('result1',r1) 10 cv2.imshow('result2',r2) 11 cv2.waitKey() 12 cv2.destroyAllWindows()
運行結果如下圖,左為原圖像,右面兩幅是方框濾波后圖像。
中間圖中白色像素較多,是因為cv2.boxFilter()函數中normalize參數等於0,沒有設置歸一化,將normalize設置為1進行歸一化后,可得右面正常圖像。
6.3 高斯濾波
前兩小節介紹的均值濾波和方框濾波中,每個像素點的權重是相等的,在高斯濾波中,中心點的權重值較大,邊緣點的權重值較小,每一種尺寸的卷積核都可以有多種不同形式的權重比例。
例如一個3×3的高斯濾波卷積核如下所示:
OpenCV提供了cv2.GaussianBlur()函數實現高斯濾波,舉例程序如下:
1 #對噪聲圖像進行高斯濾波,顯示濾波的結果 2 import cv2 3 o=cv2.imread('E:\python_opencv\lena.jpg') 4 r=cv2.GaussianBlur(o,(5,5),0,0) #5×5大小的卷積核,權重的標准差為默認值 5 cv2.imshow('original',o) 6 cv2.imshow('result',r) 7 cv2.waitKey() 8 cv2.destroyAllWindows()
運行結果如下圖,左為原圖像,右是高斯濾波后的圖像。
6.4 中值濾波
中值濾波不使用加權求和的形式計算,而是選取鄰域內所有像素點的中間值來替代當前的異常像素值。
舉例如下,異常值為31,則3×3鄰域內從小到大排列是 [31,175,176,176,179,179,180,181,185],中位數是179,則該像素點被處理為179。
OpenCV提供了cv2.medianBlur()函數實現中值濾波,舉例程序如下:
1 #對噪聲圖像進行中值濾波,顯示濾波的結果 2 import cv2 3 o=cv2.imread('E:\python_opencv\lena.jpg') 4 r=cv2.medianBlur(o,3) #濾波核大小設置為3,表示寬度和高度均為3 5 cv2.imshow('original',o) 6 cv2.imshow('result',r) 7 cv2.waitKey() 8 cv2.destroyAllWindows()
運行結果如下圖,左為原圖像,右為中值濾波后的圖像。
可以看到,由於中值濾波沒有進行均值處理,得到的圖像不存在細節變模糊的問題,有較好的濾波效果。但因為需要排序,中值濾波的計算量也較大。
6.5 雙邊濾波
在之前介紹的計算加權均值后濾波的方法中,濾波圖像不可避免的出現輪廓信息模糊的問題。而雙邊濾波綜合考慮了空間信息和色彩信息,能夠有效保護圖像內的邊緣信息。
雙邊濾波的原理是,處理異常像素值時,不僅考慮距離對權重的影響(距離越遠,權重越小),還考慮色差對權重的影響(色差越大,權重越小),既能去除噪聲,又能較好地保護邊緣信息。
OpenCV提供了cv2.bilateralFilter()函數實現雙邊濾波,舉例程序如下:
1 #針對噪聲圖像,分別對其進行高斯濾波和雙邊濾波,比較不同濾波方式對邊緣的處理結果是否相同 2 import cv2 3 o=cv2.imread('E:\python_opencv\lena.jpg') 4 g=cv2.GaussianBlur(o,(7,7),0,0) #高斯濾波 5 b=cv2.bilateralFilter(o,7,100,100) #雙邊濾波 6 cv2.imshow('original',o) 7 cv2.imshow('Gaussian',g) 8 cv2.imshow('bilateral',b) 9 cv2.waitKey() 10 cv2.destroyAllWindows()
運行結果如下圖,左為原圖像,中間是高斯濾波得到的圖像,右為雙邊濾波后的圖像。
可以看出,經過高斯濾波的圖像邊緣被模糊虛化了,而經過雙邊濾波的圖像得到了較好的保留。
6.6 2D卷積(自定義濾波)
上述濾波方法中,卷積核的設定是較為固定的,而在實際的圖像處理時,我們可能希望使用特定的卷積核進行處理,特定卷積核舉例如下:
OpenCV提供了cv2.filter2D()函數實現2D卷積濾波,舉例程序如下:
1 #自定義一個卷積核,使用雙邊濾波函數cv2.filter2D()對原始圖像進行濾波 2 import cv2 3 import numpy as np 4 o=cv2.imread('E:\python_opencv\lena.jpg') 5 kernel=np.ones((3,3),np.float32)/9 #設置3×3卷積核 6 kernel[2][2]=0.5 #將卷積核的第2行第2列元素置為0.5 7 r=cv2.filter2D(o,-1,kernel) #自定義濾波 8 cv2.imshow('original',o) 9 cv2.imshow('result',r) 10 cv2.waitKey() 11 cv2.destroyAllWindows()
代碼中,自定義將卷積核右下角的值設置為0.5,運行代碼后結果如下:
可以看到,本例中自定義卷積核后的濾波的效果,能夠對圖像的色彩亮度做出改變。
這次內容就分享到這里了,下次繼續更新第7章 圖像形態學操作,希望與各位老師和小伙伴們交流學習~