OpenCV+python:模糊操作
模糊操作是圖像處理中最簡單和常用的操作之一,使用該操作的原因之一就為了給圖像預(yù)處理時減低噪聲。
模糊操作基于離散卷積計算:
g(i,j)=∑k,lf(i+k,j+l)?h(k,l)g(i,j) = \sum_{k,l}f(i+k,j+l)*h(k,l)g(i,j)=k,l∑?f(i+k,j+l)?h(k,l)
其中權(quán)重核h(k,l)為“濾波系數(shù)”。上面的式子可以簡記為:
g=f?hg = f\bigotimes hg=f?h
通常這些卷積算子可以是線性操作,所以又叫線性濾波。不同卷積核得到不同的卷積效果,模糊是卷積的一種表象。(關(guān)于邊界問題:有幾種填充方法:補零、邊界復(fù)制、塊復(fù)制、鏡像復(fù)制等方法)。必須是奇數(shù)卷積核,就是計算這些范圍內(nèi)的值來確定中心位置的大小
1,均值濾波(歸一化濾波)
均值濾波是典型的線性濾波算法,它是指在圖像上對目標像素給一個模板,該模板包括了其周圍的臨近像素(以目標像素為中心的周圍8個像素,構(gòu)成一個濾波模板,即去掉目標像素本身),再用模板中的全體像素的平均值來代替原來像素值。
用 3×3 大小模板進行均值濾波。
由于圖像邊框上的像素無法被模板覆蓋,所以不做處理,這當然造成了圖像邊緣的缺失
以(2,2)像素點為例,卷積核如下:
則濾波后的結(jié)果為:
g(2,2)=int[(1+2+1+1+10+2+5+2+6)/9=3
濾波后(2,2)像素點的值由 10 變?yōu)?3
最終結(jié)果:
2,中值濾波
仍以(2,2)像素點為例,對模板中的 9 個數(shù)進行從小到大排序:1,1,1,2,2,2,5,6,10。中間值為 2。所以,中值濾波后(2,2)位置的值10變?yōu)?2. 同理對其他像素點。處理結(jié)果:
均值模糊、中值模糊、自定義模糊(銳化)源代碼:
import cv2 as cv
import numpy as npdef blur_demo(image):dst = cv.blur(image, (5, 5))cv.imshow("blur_demo", dst)
"""
均值模糊函數(shù)blur():定義:blur(src,ksize,dst=None, anchor=None, borderType=None)定義是有5個參數(shù),但最后三個均為none,所以也就2個參數(shù)src:要處理的原圖像ksize: 必須是奇數(shù)卷積核,周圍關(guān)聯(lián)的像素的范圍:代碼中(5,5)就是5*5的大小,就是計算這些范圍內(nèi)的均值來確定中心位置的大小
"""def median_blur_demo(image):dst = cv.medianBlur(image, 5)cv.imshow("median_blur_demo", dst)"""
定義:medianBlur(src, ksize, dst=None)ksize與blur()函數(shù)不同,不是矩陣,而是一個數(shù)字,例如為5,就表示了5*5的方陣中值濾波對于白點噪聲/椒鹽噪聲的去除是非常的好的。
"""
def custom_blur_demo(image):#kernel = np.ones([5, 5], np.float32)/25 除以25防止溢出kernel = np.array([[0, -1, 0],[-1, 5, -1],[0, -1, 0]], np.float32) #銳化算子(奇數(shù),總和為1或者0)dst = cv.filter2D(image, -1, kernel=kernel)cv.imshow("custom_blur_demo", dst)
"""
filter2D(src,ddepth,kernel):
濾波函數(shù)的使用需要一個核模板,對圖像的濾波操作過程為:將和模板放在圖像的一個像素A上,求與之對應(yīng)的圖像上的每個像素點的和,
核不同,得到的結(jié)果不同,而濾波的使用核心也是對于這個核模板的使用,需要注意的是,該濾波函數(shù)是單通道運算的,
也就是說對于彩色圖像的濾波,需要將彩色圖像的各個通道提取出來,對各個通道分別濾波才行。ddepth:深度,輸入值為-1時,目標圖像和原圖像深度保持一致kernel: 卷積核(或者是相關(guān)核),一個單通道浮點型矩陣
"""src = cv.imread("F:/images/lenanoise.png")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
blur_demo(src)
median_blur_demo(src)
custom_blur_demo(src)cv.waitKey(0)cv.destroyAllWindows()
運行結(jié)果:
3,高斯濾波
高斯濾波是一種線性平滑濾波,適用于消除高斯噪聲,廣泛應(yīng)用于圖像處理的減噪過程。通俗的講,高斯濾波就是對整幅圖像進行加權(quán)平均的過程,每一個像素點的值,都由其本身和鄰域內(nèi)的其他像素值經(jīng)過加權(quán)平均后得到。高斯濾波的具體操作是:用一個模板(或稱卷積、掩模)掃描圖像中的每一個像素,用模板確定的鄰域內(nèi)像素的加權(quán)平均灰度值去替代模板中心像素點的值。
高斯分布的概率密度函數(shù):
如果選取3*3卷積模板,分布值為0.2,0.4,0.2;由于浮點數(shù)不易計算,所以按比例轉(zhuǎn)換為1:2: 1進行計算。
源代碼:
import cv2 as cv
import numpy as npdef clamp(pv): #防止溢出if pv > 255:return 255if pv < 0:return 0else:return pvdef gaussian_noise(image): # 獲取有高斯噪聲的圖片h, w, c = image.shapefor row in range(h): for col in range(w):s = np.random.normal(0, 20, 3) #產(chǎn)生隨機數(shù)b = image[row, col, 0] # blueg = image[row, col, 1] # greenr = image[row, col, 2] # redimage[row, col, 0] = clamp(b + s[0]) #產(chǎn)生有高斯噪聲的圖片image[row, col, 1] = clamp(g + s[1])image[row, col, 2] = clamp(r + s[2])cv.imshow("noise image", image)src = cv.imread("F:/images/lena.png")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)t1 = cv.getTickCount()
gaussian_noise(src)
t2 = cv.getTickCount()
time = (t2 - t1)/cv.getTickFrequency()
print("time consume : %s"%(time*1000))
dst = cv.GaussianBlur(src, (0, 0), 15) #(0,0),然后根據(jù)sigmaX=15自動計算ksize,高斯模糊對高斯噪聲有抑制作用
"""
GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None)src,輸入圖像,即源圖像,填Mat類的對象即可。圖片深度應(yīng)該為CV_8U,CV_16U, CV_16S, CV_32F 以及 CV_64F之一。
dst,即目標圖像,需要和源圖片有一樣的尺寸和類型。比如可以用Mat::Clone,以源圖片為模板,來初始化得到如假包換的目標圖。
ksize,高斯內(nèi)核的大小。其中ksize.width和ksize.height可以不同,但他們都必須為正數(shù)和奇數(shù)(并不能理解)。或者,它們可以是零的,它們都是由sigma計算而來。
sigmaX,表示高斯核函數(shù)在X方向的的標準偏差?! 「鶕?jù)這個可以獲取sigmaY,若是sigmaX和sigmaY都沒有則根據(jù)ksize獲取
sigmaY,表示高斯核函數(shù)在Y方向的的標準偏差。若sigmaY為零,就將它設(shè)為sigmaX,如果sigmaX和sigmaY都是0,那么就由ksize.width和ksize.height計算出來。
為了結(jié)果的正確性著想,最好是把第三個參數(shù)Size,第四個參數(shù)sigmaX和第五個參數(shù)sigmaY全部指定到。
borderType,用于推斷圖像外部像素的某種邊界模式。注意它有默認值BORDER_DEFAULT。
"""
cv.imshow("Gaussian Blur", dst)cv.waitKey(0)cv.destroyAllWindows()
運行結(jié)果:
4,雙邊濾波
OpenCV經(jīng)典的兩種實現(xiàn)EPF方法:高斯雙邊和均值遷移
高斯模糊只考慮了權(quán)重,只考慮了像素空間的分布,沒有考慮像素值和另一個像素值之間差異的問題,如果像素間差異較大的情況下(比如圖像的邊緣),高斯模糊會進行處理,但是我們不需要處理邊緣,要進行的操作就叫做邊緣保留濾波(EPF)。
(1) 均值模糊無法克服邊緣像素信息丟失缺陷。原因是均值模糊是基于平均權(quán)重。
(2) 高斯模糊部分克服了該缺陷,但是無法完全避免,因為沒考慮到像素值的不同。
(3) 雙邊濾波是保留邊緣的濾波方法,避免了邊緣信息的丟失,保留了圖像輪廓不變。
只模糊上半部分,下半部分差異太大,沒有模糊差異越大,越會完整保留。
源代碼(雙邊模糊、均值遷移)
import cv2 as cv
import numpy as npdef bi_demo(image):dst = cv.bilateralFilter(image, 0, 100, 15)cv.imshow("bi_demo", dst)
"""
定義:bilateralFilter(src, d, sigmaColor, sigmaSpace, dst=None, borderType=None)值域和空域的兩個方差sigma可以簡單的設(shè)置為相等,小于10,無太大效果,大于150效果太強,像卡通片似的。濾波器尺寸d:大于5將較慢(5 forreal-time),d=9,for off-lineapplications,d 是像素鄰域“直徑”。計算的半徑,半徑之內(nèi)的像數(shù)都會被納入計算,如果提供-1或者0,會從后面的參數(shù)sigmaSpace中自動計算。Sigma_color(顏色標準差):顏色空間過濾器的sigma值,這個參數(shù)的值越大,表明該像素鄰域內(nèi)有越寬廣的顏色會被混合到一起,產(chǎn)生較大的半相等顏色區(qū)域。Sigma_space(空間標準差):坐標空間中濾波器的sigma值,如果該值較大,則意味著顏色相近的較遠的像素將相互影響,從而使更大的區(qū)域中足夠相似的顏色獲取相同的顏色。當d>0時,d指定了鄰域大小且與sigmaSpace五官,否則d正比于sigmaSpace.雙邊濾波的內(nèi)在想法是:在圖像的值域(range)上做傳統(tǒng)濾波器在空域(domain)上做的工作??沼驗V波對空間上鄰近的點進行加權(quán)平均,加權(quán)系數(shù)隨著距離的增加而減少;值域濾波則是對像素值相近的點進行加權(quán)平均,加權(quán)系數(shù)隨著值差的增大而減少
"""def shift_demo(image):dst = cv.pyrMeanShiftFiltering(image, 10, 50)cv.imshow("shift_demo", dst)
"""
meanShfit均值漂移算法是一種通用的聚類算法,它的基本原理是:對于給定的一定數(shù)量樣本,任選其中一個樣本,以該樣本為中心點劃定一個圓形區(qū)域,求取該圓形區(qū)域內(nèi)樣本的質(zhì)心,即密度最大處的點,再以該點為中心繼續(xù)執(zhí)行上述迭代過程,直至最終收斂??梢岳镁灯扑惴ǖ倪@個特性,實現(xiàn)彩色圖像分割,Opencv中對應(yīng)的函數(shù)是pyrMeanShiftFiltering。這個函數(shù)嚴格來說并不是圖像的分割,而是圖像在色彩層面的平滑濾波,它可以中和色彩分布相近的顏色,平滑色彩細節(jié),侵蝕掉面積較小的顏色區(qū)域,所以在Opencv中它的后綴是濾波“Filter”,而不是分割“segment”。先列一下這個函數(shù),再說一下它“分割”彩色圖像的實現(xiàn)過程。pyrMeanShiftFiltering(src, sp, sr, dst=None, maxLevel=None, termcrit=None): 第一個參數(shù)src,輸入圖像,8位,三通道的彩色圖像,并不要求必須是RGB格式,HSV、YUV等Opencv中的彩色圖像格式均可;第二個參數(shù)sp,定義的漂移物理空間半徑大小; #越大,細節(jié)丟失越多第三個參數(shù)sr,定義的漂移色彩空間半徑大小;第四個參數(shù)dst,輸出圖像,跟輸入src有同樣的大小和數(shù)據(jù)格式;第五個參數(shù)maxLevel,定義金字塔的最大層數(shù);第六個參數(shù)termcrit,定義的漂移迭代終止條件,可以設(shè)置為迭代次數(shù)滿足終止,迭代目標與中心點偏差滿足終止,或者兩者的結(jié)合
"""src = cv.imread("F:/images/example.png")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
bi_demo(src)
shift_demo(src)
cv.waitKey(0)cv.destroyAllWindows()
運行結(jié)果:
總結(jié)
以上是生活随笔為你收集整理的OpenCV+python:模糊操作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。