OpenCV-Python實現圖像平滑處理操作
什麼是圖像平滑處理
在盡量保留圖像原有信息的情況下,過濾掉圖像內部的噪聲,這一過程我們稱之為圖像的平滑處理,所得到的圖像稱為平滑圖像。
那麼什麼是圖像的噪聲呢?
圖像的噪聲就是圖像中與周圍像素點差異較大的像素點。噪聲的處理就是將其更改為臨近像素點的近似值,使圖像更平滑。
圖像平滑處理的噪聲取值的方式有以下6種:
(1)均值濾波
(2)方框濾波
(3)高斯濾波
(4)中值濾波
(5)雙邊濾波
(6)2D卷積(自定義濾波)
均值濾波
均值濾波是指用當前像素點周圍N*N個像素點的均值來代替當前像素值。使用該方法遍歷處理圖像內的每一個像素點,即可完成整幅圖像的均值濾波。
在進行均值濾波處理時,我們需要考慮對周圍多少個像素點取平均值。通常情況下,我們會以當前像素點為中心,對行數和列數相等的一塊區域內的所有像素點取平均值。
但是邊緣像素點可能不能這樣做,畢竟比如左上角的像素點是沒有左上像素點的,這個時候我們常常會取圖像內存在的周圍鄰域點的平均值。
在OpenCV中,它給我們提供的均值濾波函數為cv2.blur(),其完整定義如下:
def blur(src, ksize, dst=None, anchor=None, borderType=None):
src:原始圖像
kszie:濾波中心的大小,也就是取平均值的周圍像素點的高度與寬度,比如(5,5),就是取5*5鄰域像素點均值作為結果。
anchor:錨點,其默認值為(-1,1),表示當前計算均值的點位於核的中心點位置。一般使用默認值即可。
borderType:邊界樣式,該值決定瞭以何種方式處理邊界,一般情況下不需要更改。
瞭解瞭該函數的定義,下面我們簡單的來完成一個去噪圖像,具體代碼如下所示:
import cv2 img = cv2.imread("5.jpg") result_5img = cv2.blur(img, (5, 5)) result_30img= cv2.blur(img, (30, 30)) cv2.imshow("img", img) cv2.imshow("result_5img", result_5img) cv2.imshow("result_30img", result_30img) cv2.waitKey() cv2.destroyAllWindows()
運行之後,效果如下所示:
從上圖可以看出來,使用(5,5)卷積進行均值濾波處理後圖像雖然模糊,但還可以辨認。而使用(30,30)卷積進行均值濾波,圖像失真非常嚴重。
所以,我們可以得出來,卷積核越大,去噪效果越好,花費的時間越長,同時圖像失真也越嚴重。而實際的處理中,我們需要在失真與去噪之間取得平衡,選取合適的卷積大小。
方框濾波
方框濾波與均值濾波的不同之處在於,方框濾波不會計算像素均值,它可以自由選擇是否對均值濾波的結果進行歸一化,即可以自由選擇濾波結果是鄰域像素值之和的平均值,還是鄰域像素值之和。
在OpenCV中,它提供cv2.boxFilter()函數來實現方框濾波,其完整定義如下:
def boxFilter(src, ddepth, ksize, dst=None, anchor=None, normalize=None, borderType=None):
src:原始圖像
ddepth:處理結果圖像的圖像深度,一般使用-1表示與原圖像使用相同的圖像深度
ksize:濾波核心的大小
normalize:是否在濾波時進行歸一化處理。當它為1時,表示要進行歸一化處理,也就是鄰域像素值的和除以面積,比如(3,3),公式如下:
當它為0時,表示不需要進行歸一化處理,直接使用鄰域像素值的和。
下面,我們來用程序分別實現歸一化與不歸一化的效果,代碼如下:
import cv2 img = cv2.imread("5.jpg") result1 = cv2.boxFilter(img, -1, (5, 5)) result2 = cv2.boxFilter(img, -1, (30, 30)) result3 = cv2.boxFilter(img, -1, (2, 2),normalize=0) cv2.imshow("img", img) cv2.imshow("result1", result1) cv2.imshow("result2", result2) cv2.imshow("result3", result3) cv2.waitKey() cv2.destroyAllWindows()
運行之後,顯示的效果如下所示:
可以看到,左下角不需要歸一化處理,這裡隻取(2,2),如果你取大瞭,可以試試。因為范圍大瞭,和一般都會大於255,那麼就會造成圖像全是白色。
高斯濾波
在進行均值濾波與方框濾波時,其鄰域內每個像素的權重是相等的。而高斯濾波會將中心點的權重加大,遠離中心點的權重減小,以此來計算鄰域內各個像素值不同權重的和。
在OpenCV中,它給我們提供cv2.GaussianBlur()函數進行高斯濾波,其完整定義如下:
def GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None):
src:原始圖像
ksize:濾波核的大小
sigmaX:卷積和在水平方向上(X軸方向)的標準差,其控制的是權重比例
sigmaY:卷積和在垂直方向上(Y軸方向)的標準差,也是控制的是權重比例。如果它為0,隻采用sigmaX的值,如果sigmaX與sigmaY都是0,則通過ksize.width和ksize.height計算得到(可選參數)
下面,我們來使用高斯濾波看看效果,代碼如下所示:
import cv2 img = cv2.imread("5.jpg") result = cv2.GaussianBlur(img, (3, 3), 0, 0) cv2.imshow("img", img) cv2.imshow("result", result) cv2.waitKey() cv2.destroyAllWindows()
運行之後,效果如下所示:
中值濾波
中值濾波與前面的三種濾波都不同,它不在采用加權求均值的方式計算濾波結果,而是用鄰域內所有像素值的中間值來代替當前像素點的像素值。
簡單點說,就是取當前像素點及其周圍臨近像素點的像素值,將這些值進行排序後,取中間位置的像素值作為當前位置的像素值。
在OpenCV中,它提供給我們cv2.medianBlur()函數來進行中值濾波,其完整定義如下:
def medianBlur(src, ksize, dst=None):
src:原始圖像
kszie:濾波核的大小
參數就兩個,下面我們來用代碼測試一下:
import cv2 img = cv2.imread("5.jpg") result = cv2.medianBlur(img, 3) cv2.imshow("img", img) cv2.imshow("result", result) cv2.waitKey() cv2.destroyAllWindows()
運行之後,顯示效果如下:
可以看到,這裡我們將臉上的紅點去掉瞭。需要特別註意的是,濾波核的大小必須是奇數,矩陣中心點向外衍生必然是奇數,不信可以隨便矩陣取一點試試。
雙邊濾波
雙邊濾波是綜合考慮空間信息和色彩信息的濾波方式,在濾波的過程中能夠有效地保護圖像內的邊緣信息。
前面濾波方式基本隻考慮瞭空間的權重信息,這種情況計算起來比較方便,但是邊緣信息的處理上存在較大問題。而雙邊濾波在處理邊緣時,與當前點色彩相近的像素點給與較大的權重值,而與當前像素點色彩差別大的會給較小的權重,這樣就保護瞭邊緣信息。
簡單點概括,雙邊濾波在計算某一個像素點的新值時,不僅考慮距離信息,還考慮色彩信息。雙邊濾波即能有效地去除噪聲,又能很好地保護邊緣信息。
在OpenCV中,它給我們提供cv2.bilateralFilter()函數來實現,其完整定義如下:
def bilateralFilter(src, d, sigmaColor, sigmaSpace, dst=None, borderType=None):
src:原始圖像
d:在濾波時選取的空間距離參數,這裡表示以當前像素點為中心點的直徑。如果該值為非正數,則會從參數sigmaSpace計算得到。如果濾波空間較大,比如d>5,則速度較慢。因此,在實際的應用中,推薦d=5。對於噪聲較大的離線濾波,可以選擇d=9。
sigmaColor:在濾波處理時,選擇的顏色范圍,該值決定瞭周圍哪些像素點能夠參與到濾波中來。與當前像素點的像素值差值小於sigmaColor的像素點,能夠參與到當前的濾波中。該值越大,就說明周圍有越多的像素點可以參與到運算中。該值為0時,濾波失去意義;該值為255,指定直徑內的所有點都能夠參與運算。
sigmaSpace:坐標空間中的sigma值。它的值越大,說明有越多的點能夠參與到濾波計算中來。當d>0時,無論sigmaSpace的值如何,d都指定鄰域大小;否則,d域sigmaSpace的值成比例。
為瞭簡單起見,博主這裡將兩個sigmaColor與sigmaSpace值設置為相同的。如果它們的值比較小,比如小於10,濾波的效果不太明顯;如果它們的值較大,比如大於150,則濾波效果會比較明顯。
代碼如下所示:
import cv2 img = cv2.imread("5.jpg") result = cv2.bilateralFilter(img,25,50,50) cv2.imshow("img", img) cv2.imshow("result", result) cv2.waitKey() cv2.destroyAllWindows()
運行之後,顯示效果如下所示:
2D卷積
在OpenCV中,除瞭提供上面這些常用的濾波方式之外,還允許用戶自定義卷積核實現卷積操作。這個函數是cv2.Filter2D(),其完整定義如下:
def filter2D(src, ddepth, kernel, dst=None, anchor=None, delta=None, borderType=None):
src:原始圖像
ddepth:處理結果圖像的深度,-1與原圖像一致。
kernel:卷積核,是一個單通道數組。如果想在處理彩色圖像時,讓每個通道使用不同的核,則必須將彩色圖像分解後使用不同的核完成。
delta:修正值,可選參數。如果該值存在,會在基礎濾波的結果上加上該值作為最終的濾波結果。
下面,我們來使用這個函數看看效果,具體代碼如下所示:
import cv2 import numpy as np img = cv2.imread("5.jpg") kernel = np.ones((9,9), np.float32) / 81 result = cv2.filter2D(img, -1, kernel) cv2.imshow("img", img) cv2.imshow("result", result) cv2.waitKey() cv2.destroyAllWindows()
運行之後,效果如下所示:
到此這篇關於OpenCV-Python實現圖像平滑處理操作的文章就介紹到這瞭,更多相關OpenCV 圖像平滑處理內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Python OpenCV圖像模糊處理介紹
- Python OpenCV對圖像進行模糊處理詳解流程
- C++ opencv圖像平滑濾波器使用示例
- 深入學習Python+Opencv常用四種圖像處理操作
- OpenCV-Python實現通用形態學函數