Python3+OpenCV3影象處理(七)—— 濾波與模糊操作
過濾是訊號和影象處理中基本的任務。其目的是根據應用環境的不同,選擇性的提取影象中某些認為是重要的資訊。過濾可以移除影象中的噪音、提取感興趣的可視特徵、允許影象重取樣等等。頻域分析將影象分成從低頻到高頻的不同部分。低頻對應影象強度變化小的區域,而高頻是影象強度變化非常大的區域。在頻率分析領域的框架中,濾波器是一個用來增強影象中某個波段或頻率並阻塞(或降低)其他頻率波段的操作。低通濾波器是消除影象中高頻部分,但保留低頻部分。高通濾波器消除低頻部分。參考部落格:https://blog.csdn.net/sunny2038/article/details/9155893
個人認為模糊操作就是過濾掉影象中的一些特殊噪音。
一、均值模糊、中值模糊、使用者自定義模糊
程式碼如下:
#均值模糊、中值模糊、自定義模糊 模糊是卷積的一種表象 import cv2 as cv import numpy as np def blur_demo(image): #均值模糊 去隨機噪聲有很好的去燥效果 dst = cv.blur(image, (1, 15)) #(1, 15)是垂直方向模糊,(15, 1)還水平方向模糊 cv.namedWindow('blur_demo', cv.WINDOW_NORMAL) cv.imshow("blur_demo", dst) def median_blur_demo(image): # 中值模糊 對椒鹽噪聲有很好的去燥效果 dst = cv.medianBlur(image, 5) cv.namedWindow('median_blur_demo', cv.WINDOW_NORMAL) cv.imshow("median_blur_demo", dst) def custom_blur_demo(image): # 使用者自定義模糊 kernel = np.ones([5, 5], np.float32)/25 #除以25是防止數值溢位 dst = cv.filter2D(image, -1, kernel) cv.namedWindow('custom_blur_demo', cv.WINDOW_NORMAL) cv.imshow("custom_blur_demo", dst) src = cv.imread('E:\imageload\lenanoise.jpg') cv.namedWindow('input_image', cv.WINDOW_NORMAL) cv.imshow('input_image', src) blur_demo(src) median_blur_demo(src) custom_blur_demo(src) cv.waitKey(0) cv.destroyAllWindows()
執行結果:
注意:
1.均值濾波是典型的線性濾波演算法,它是指在影象上對目標畫素給一個模板,該模板包括了其周圍的臨近畫素(以目標畫素為中心的周圍8個畫素,構成一個濾波模板,即去掉目標畫素本身),再用模板中的全體畫素的平均值來代替原來畫素值。
低通濾波(均值模糊)函式原型:blur(src, ksize[, dst[, anchor[, borderType]]]) -> dst
src引數表示待處理的輸入影象。
ksize引數表示模糊核心大小。比如(1,15)表示生成的模糊核心是一個1*15的矩陣。
dst引數表示輸出與src相同大小和型別的影象。
anchor引數、borderType引數可忽略
中值濾波(中值模糊)函式原型:medianBlur(src, ksize[, dst]) -> dst
src引數表示待處理的輸入影象。
ksize引數表示濾波視窗尺寸,必須是奇數並且大於1。比如這裡是5,中值濾波器就會使用5×5的範圍來計算,即對畫素的中心值及其5×5鄰域組成了一個數值集,對其進行處理計算,當前畫素被其中值替換掉。
dst引數表示輸出與src相同大小和型別的影象。
3.使用者自定義模糊
所用函式:filter2D()
函式原型: filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]]) -> dst
src引數表示待處理的輸入影象。
ddepth引數表示目標影象深度,輸入值為-1時,目標影象和原影象深度保持一致
kernel: 卷積核(或者是相關核),一個單通道浮點型矩陣。修改kernel矩陣即可實現不同的模糊
二、高斯模糊
程式碼如下:
#高斯模糊 輪廓還在,保留影象的主要特徵 高斯模糊比均值模糊去噪效果好
import cv2 as cv
import numpy as np
def clamp(pv):
if pv > 255:
return 255
if pv < 0:
return 0
else:
return pv
def gaussian_noise(image): #加高斯噪聲
h, w, c = image.shape
for row in range(h):
for col in range(w):
s = np.random.normal(0, 20, 3)
b = image[row, col, 0] #blue
g = image[row, col, 1] #green
r = image[row, col, 2] #red
image[row, col, 0] = clamp(b + s[0])
image[row, col, 1] = clamp(g + s[1])
image[row, col, 2] = clamp(r + s[2])
cv.namedWindow("noise image", cv.WINDOW_NORMAL)
cv.imshow("noise image", image)
dst = cv.GaussianBlur(image, (15, 15), 0) # 高斯模糊
cv.namedWindow("Gaussian", cv.WINDOW_NORMAL)
cv.imshow("Gaussian", dst)
src = cv.imread('E:\imageload\lena.jpg')
cv.namedWindow("input_image", cv.WINDOW_NORMAL)
cv.imshow('input_image', src)
gaussian_noise(src)
dst = cv.GaussianBlur(src, (15,15), 0) #高斯模糊
cv.namedWindow("Gaussian Blur", cv.WINDOW_NORMAL)
cv.imshow("Gaussian Blur", dst)
cv.waitKey(0)
cv.destroyAllWindows()
執行結果:
注意:
1.高斯模糊實質上就是一種均值模糊,只是高斯模糊是按照加權平均的,距離越近的點權重越大,距離越遠的點權重越小。通俗的講,高斯濾波就是對整幅影象進行加權平均的過程,每一個畫素點的值,都由其本身和鄰域內的其他畫素值經過加權平均後得到。
2.高斯分佈的一維和二維原理如下:
補:高斯分佈的標準差σ。標準差代表著資料的離散程度,如果σ較小,那麼生成的模板的中心繫數較大,而周圍的係數較小,這樣對影象的平滑效果就不是很明顯;反之,σ較大,則生成的模板的各個係數相差就不是很大,比較類似均值模板,對影象的平滑效果比較明顯。高斯模糊具體原理見博文:https://blog.csdn.net/u012992171/article/details/51023768
3.高斯模糊GaussianBlur函式原型:GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]]) -> dst
src引數表示待處理的輸入影象。
ksize引數表示高斯濾波器模板大小。 ksize.width和ksize.height可以不同,但它們都必須是正數和奇數。或者,它們可以是零,即(0, 0),然後從σ計算出來。
sigmaX引數表示 X方向上的高斯核心標準差。
sigmaY引數表示 Y方向上的高斯核心標準差。 如果sigmaY為零,則設定為等於sigmaX,如果兩個sigma均為零,則分別從ksize.width和ksize.height計算得到。
補:若ksize不為(0, 0),則按照ksize計算,後面的sigmaX沒有意義。若ksize為(0, 0),則根據後面的sigmaX計算ksize
4.numpy包裡的random模組用於生成隨機數,random模組裡的normal函式表示的是生成高斯隨機數。
normal函式預設原型:normal(loc=0.0, scale=1.0, size=None)。
loc引數表示高斯分佈的中心點。
scale引數表示高斯分佈的標準差σ。
size引數表示產生隨機數的個數。size取值可以為(m,n,k),表示繪製m*n*k個樣本。
三、邊緣保留濾波EPF
進行邊緣保留濾波通常用到兩個方法:高斯雙邊濾波和均值遷移濾波。
程式碼如下:
#邊緣保留濾波(EPF) 高斯雙邊、均值遷移
import cv2 as cv
import numpy as np
def bi_demo(image): #雙邊濾波
dst = cv.bilateralFilter(image, 0, 100, 15)
cv.namedWindow("bi_demo", cv.WINDOW_NORMAL)
cv.imshow("bi_demo", dst)
def shift_demo(image): #均值遷移
dst = cv.pyrMeanShiftFiltering(image, 10, 50)
cv.namedWindow("shift_demo", cv.WINDOW_NORMAL)
cv.imshow("shift_demo", dst)
src = cv.imread('E:/imageload/example.png')
cv.namedWindow('input_image', cv.WINDOW_NORMAL)
cv.imshow('input_image', src)
bi_demo(src)
shift_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()
執行結果:
注意:
1.雙邊濾波(Bilateral filter)是一種非線性的濾波方法,是結合影象的空間鄰近度和畫素值相似度的一種折中處理,同時考慮空域資訊和灰度相似性,達到保邊去噪的目的。雙邊濾波器顧名思義比高斯濾波多了一個高斯方差sigma-d,它是基於空間分佈的高斯濾波函式,所以在邊緣附近,離的較遠的畫素不會太多影響到邊緣上的畫素值,這樣就保證了邊緣附近畫素值的儲存。但是由於儲存了過多的高頻資訊,對於彩色影象裡的高頻噪聲,雙邊濾波器不能夠乾淨的濾掉,只能夠對於低頻資訊進行較好的濾波
2.雙邊濾波函式原型:bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]]) -> dst
src引數表示待處理的輸入影象。
d引數表示在過濾期間使用的每個畫素鄰域的直徑。如果輸入d非0,則sigmaSpace由d計算得出,如果sigmaColor沒輸入,則sigmaColor由sigmaSpace計算得出。
sigmaColor引數表示色彩空間的標準方差,一般儘可能大。較大的引數值意味著畫素鄰域內較遠的顏色會混合在一起,從而產生更大面積的半相等顏色。
sigmaSpace引數表示座標空間的標準方差(畫素單位),一般儘可能小。引數值越大意味著只要它們的顏色足夠接近,越遠的畫素都會相互影響。當d > 0時,它指定鄰域大小而不考慮sigmaSpace。 否則,d與sigmaSpace成正比。
雙邊濾波原理:
3.均值漂移pyrMeanShiftFiltering函式原型:pyrMeanShiftFiltering(src, sp, sr[, dst[, maxLevel[, termcrit]]]) -> dst
src引數表示輸入影象,8位,三通道影象。
sp引數表示漂移物理空間半徑大小。
sr引數表示漂移色彩空間半徑大小。
dst引數表示和源圖象相同大小、相同格式的輸出圖象。
maxLevel引數表示金字塔的最大層數。
termcrit引數表示漂移迭代終止條件。
均值漂移原理: