第七章: 圖像平滑處理
-
1、什么是圖像平滑處理
圖像平滑處理就是,將圖像中與 周圍像素點的像素值差異較大的像素點 調(diào)整成 和周圍像素點像素值 相近的值。
例如: -
2、為什么要進行平滑處理?
因為圖像在采集(生成)、傳輸、處理的過程中常常會存在一定的噪聲干擾,比如,在圖像拍攝的時候,也就是圖像生成的時候,實際中往往會出現(xiàn)比如鏡頭污染、光線較強、較弱、大氣折射、鏡頭角度等問題,導致拍攝出來的圖片某些像素亮度變化過大,比如過亮或者過暗,導致人眼看到的圖像畫面不清晰,也就是圖像有噪聲,影響畫質(zhì)。為了抑制這種噪聲,改善圖像質(zhì)量,我們就要對圖像進行平滑處理。
說明:圖像經(jīng)過平滑處理smoothing后,雖然可以抑制一些噪音,但同時也會把圖像中的邊緣線條弄模糊blurring了。 -
3、如何進行平滑處理?
用濾波器(filtering)過濾掉某些波,保留另一些波。
濾波器是物理學中的概念,是物理學中對波的處理方式,有非常深入的研究和多種處理波的方法。
我們拿物理學中的這個方法用到圖像處理上,就叫圖像濾波。在圖像領(lǐng)域,實現(xiàn)圖像濾波的濾波器我們叫濾波核filter,也叫卷積核。 圖像濾波是圖像處理和計算機視覺中最常用、最基本的操作。
我們首先要明白,計算機視覺不是讓人眼去看圖片的,是讓計算機去看圖片的,讓它去識別圖像中特定物體、去檢測圖像中的特定目標、去分割圖像中特定的目標,而計算機看圖片和人眼看圖片完全不是一回事,人眼看到的是圖像,計算機看到的是一個數(shù)字矩陣。而讓計算機去"圖像識別",就是讓它從一大堆數(shù)字中找出規(guī)律。而我們對圖像進行的一些處理是便于計算機找出這個規(guī)律。
圖像濾波可以實現(xiàn)對圖像的各種處理,比如實現(xiàn)圖像的平移、旋轉(zhuǎn)、鏡面、分割、檢測等等幾乎所有的處理方式。本章中對圖像進行平滑處理更是可以通過圖像濾波去實現(xiàn)。
所以,如果我們想對一張圖像進行濾波處理,
一是要確定你的濾波核也就是卷積核,包括卷積核的尺寸和卷積核內(nèi)的數(shù)值,其中,尺寸是必須考慮的,而數(shù)值有些情況下是不需要考慮的,因為有時我們只需要一個沒有數(shù)據(jù)只有尺寸的核即可);
二是要確定卷積的方式,比如是進行均值運算還是加權(quán)運算還是中值運算等等方法;
三是要確定是否要padding以及如果padding,padding就是對圖像邊緣進行填充,圖像邊緣的像素點是沒法卷積運算的,此時就要特別處理,就是填充,而填充也有多種填充方式比如0填充、常量填充、鏡像填充等。
一、均值濾波
用一個只有尺寸沒有數(shù)值的卷積核去卷積原圖像,得到對應位置上的每個像素點的值是被卷積核套住的像素的均值。
API: cv2.blur(img, ksize)
#例7.1 觀察均值濾波對圖像的處理效果
import cv2
import matplotlib.pyplot as plt
img = cv2.imread(r'C:\Users\25584\Desktop\lenaNoise.png')
img_blur1 = cv2.blur(img, (5,5)) #使用5x5的卷積核
img_blur2 = cv2.blur(img, (30,30)) #使用30x30的卷積核
fig, axes = plt.subplots(1,3, figsize=(10,5), dpi=100)
axes[0].imshow(img[:,:,::-1])
axes[1].imshow(img_blur1[:,:,::-1])
axes[2].imshow(img_blur2[:,:,::-1])
plt.show()
說明:均值濾波的卷積核越大,參與到均值運算中的像素就會越多,也就是當前像素點的值是更多像素點的值的均值,
所以,卷積核越大去噪效果越好,但圖像實真也越嚴重。所以,我們要選擇合適尺寸的卷積核,在失真和去噪之間取得平衡。
二、方框濾波
用一個有尺寸有數(shù)值的卷積核去卷積原圖像。
API:?cv2.boxFilter(img, ddepth, ksize [, anchor, normalize, borderType])
img:要卷積的圖像
ddepth:默認值是-1,表示與原始圖像的深度一樣。
ksize: 卷積核的尺寸
anchor: 錨點,默認值是(-1,-1),表示卷積運算完后的點位于核的中心點位置。該參數(shù)通常使用默認即可。
normalize: 表示卷積后要不要歸一化處理。默認值是1。
當normalize=1時,要進行平均歸一化處理。此時計算結(jié)果就是均值濾波。
當normalize=0時,表示不進行均值歸一化處理,直接使用卷積結(jié)果值。當卷積結(jié)果超過255時,就截斷為最大值255。
borderType:邊界處理方式
#例7.2 觀察方框濾波對圖像的處理效果
import cv2
import matplotlib.pyplot as plt
img = cv2.imread(r'C:\Users\25584\Desktop\lenaNoise.png')
img_boxfilter1 = cv2.boxFilter(img, -1, (5,5)) #使用5x5的卷積核,normalize=1,默認使用均值歸一化。
img_boxfilter2 = cv2.boxFilter(img, -1, (2,2), normalize=0) #不使用均值歸一化
fig, axes = plt.subplots(1,3, figsize=(10,5), dpi=100)
axes[0].imshow(img[:,:,::-1])
axes[1].imshow(img_boxfilter1[:,:,::-1])
axes[2].imshow(img_boxfilter2[:,:,::-1])
plt.show()
三、高斯濾波
用一個有尺寸有數(shù)值的卷積核去卷積原圖像。高斯濾波和均值濾波和方框濾波不同的是,在均值濾波和方框濾波中,被卷積核套住的區(qū)域中,每個像素點的權(quán)重是相同的,但是在高斯濾波處理中,被高斯卷積核套住的區(qū)域中,中心點的權(quán)重值最大,越遠離中心點的權(quán)重值就越小。
或者另外一種說法:高斯濾波和均值濾波、方框濾波的卷積核是不一樣的。就是因為有不同的卷積核才實現(xiàn)不同的處理效果,才會有不同的濾波處理方式。
-
高斯濾波核的特點:
尺寸:尺寸必須是奇數(shù),就是核的高和寬可以不相等,但都必須是奇數(shù)。
數(shù)值:高斯核是必須有數(shù)值的,核里面的數(shù)值符合高斯分布。另外,卷積核里面的數(shù)值是要經(jīng)過歸一化處理的,沒有歸一化處理計算結(jié)果是錯誤的?。?!
- 幫助理解文檔:高斯模糊的算法(高斯卷積 高斯核)_Farmwang的博客-CSDN博客_高斯卷積
API:?cv2.GaussianBlur(img, ksize, sigmaX, sigmaY [, borderType])
img:要卷積的圖像
ksize: 卷積核的尺寸,記住必須是奇數(shù)!
sigmaX: 卷積核在x軸方向(水平方向)上的標準差
sigmaY: 卷積核在y軸方向(垂直方向)上的標準差
sigmX和sigmY默認值都是0
如果sigmaX不設(shè)為0,sigmaY設(shè)為0,則sigmay采用sigmaX的值;
如果二者都默認為0,則sigmaX=0.3[(ksize.width-1)*0.5-1]+0.8, sigmaY=0.3[(ksize.height-1)*0.5-1]+0.8
borderType:邊界處理方式,一般使用默認值即可。
#例7.3 觀察高斯濾波對圖像的處理效果
import cv2
import matplotlib.pyplot as plt
img = cv2.imread(r'C:\Users\25584\Desktop\lenaNoise.png')
?
img_gaussianBlur1 = cv2.GaussianBlur(img, (5,5), 0, 0)
img_gaussianBlur2 = cv2.GaussianBlur(img, (5,5), 3,3)
?
fig, axes = plt.subplots(1,3, figsize=(10,5), dpi=100)
axes[0].imshow(img[:,:,::-1])
axes[1].imshow(img_gaussianBlur1[:,:,::-1])
axes[2].imshow(img_gaussianBlur2[:,:,::-1])
plt.show()
四、中值濾波
用一個有尺寸沒有數(shù)值的卷積核去卷積原圖像。卷積的方式是選取被卷積核套住的區(qū)域中的中間值作為當前像素點的像素值。
API:?cv2.medianBlur(img, ksize)
img:要卷積的圖像
ksize: 卷積核的尺寸,這個尺寸必須是大于1的奇數(shù),因為這樣卷積操作的時候才有中間值!
#例7.4 觀察中值濾波對圖像的處理效果
import cv2
import matplotlib.pyplot as plt
img = cv2.imread(r'C:\Users\25584\Desktop\lenaNoise.png')
img_medianBlur1 = cv2.medianBlur(img, 5)
img_medianBlur2 = cv2.medianBlur(img, 3)
fig, axes = plt.subplots(1,3, figsize=(10,5), dpi=100)
axes[0].imshow(img[:,:,::-1])
axes[1].imshow(img_medianBlur1[:,:,::-1])
axes[2].imshow(img_medianBlur2[:,:,::-1])
plt.show()
五、雙邊濾波
前面講的均值濾波、方框濾波、高斯濾波、中值濾波都是只單純的考慮了像素點之間的空間信息而進行濾波的方式,這些方式都或多或少都會模糊圖像的邊緣信息,就是把圖像里面的邊緣線條弄模糊了,就是在去除圖像噪音的同時把圖像也弄模糊了,造成圖像邊界信息的部分丟失,這是這些方法的一個共同的缺點。
雙邊濾波就可以很好的規(guī)避這個缺點。因為雙邊濾波不僅考慮了像素的空間信息(距離越遠權(quán)重越小)同時還考慮了像素的色彩信息(色彩差別越大,權(quán)重越小),這樣就可以很好的去除噪聲還可以較好的保護邊緣信息,所以雙邊濾波器也是一個保邊去噪的濾波器。如下圖所示,左圖是原圖,中間是均值濾波的結(jié)果,右圖是雙邊濾波的計算結(jié)果。
也就是說,當遠離邊界時,即顏色十分相近,顏色權(quán)基本一樣時,類似于高斯濾波,這樣變可平滑處理圖像。當處在邊界時(所謂邊界,就是顏色反差極大的地方),邊界上的點互相顏色相近,會取極大的權(quán)值,而邊界外的的點,顏色距離很遠,權(quán)值取的很小(甚重可以忽略不計),這樣就保護了邊緣。
-
如何實現(xiàn)既考慮空間信息又考慮色彩信息?
簡單!空間信息的考慮還是上面的高斯核思路,空間距離遠的像素的權(quán)值調(diào)小,空間距離近的像素權(quán)值調(diào)大。 而色彩信息直接簡單粗暴用if then判斷語句實現(xiàn)唄。我們先設(shè)定一個色差范圍,比如100,當被雙邊濾波核套住的原圖區(qū)域中,某個像素點的值大于或者小于要計算的那個像素點值的100范圍外,直接將那個像素點的權(quán)值置為0即可。也就是說,當差值的絕對值大于100的像素點就不參與平滑運算,這樣就保留住了邊緣線條了。
一句話就是:雙邊濾波的濾波核還是一個高斯核,但是加了一個判斷條件,就是:逐個遍歷高斯核的每個元素,如果這個元素的像素值和中間元素的像素值差值大于100,那這個元素的權(quán)重就置為0,就是這個像素點就不參與濾波計算,這樣就保住了和周圍像素差值較大的邊緣像素點。 -
API:?cv2.bilateralFilter(img, d, sigmaColor, sigmaSpace)
img:要卷積的圖像
d: 類似前面的ksize,該參數(shù)是正整數(shù),如果該參數(shù)設(shè)置為非正數(shù),則會自動從參數(shù)sigmaSpace中計算得到。
sigmaColor: 濾波處理時選取的顏色差值范圍,該值決定被卷積核套住的原圖區(qū)域中,有哪些點能夠參與到濾波中來。 如果sigmaColor=0,就表示其他所有的點都權(quán)值為0,都沒法參與運算,所以該參數(shù)設(shè)置為0是毫無意義的。如果sigmaColor=255,就表示所有的點都可以參與濾波運算。
sigmaSpace: 當參數(shù)d設(shè)置為正整數(shù),這個參數(shù)就無意義,可以隨便設(shè)置。當參數(shù)d設(shè)置為非正數(shù),這個參數(shù)才有意義,就是相當于ksize,就是卷積核的尺寸。#例7.5 觀察雙邊濾波對圖像的處理效果 import cv2 import matplotlib.pyplot as plt img = cv2.imread(r'C:\Users\25584\Desktop\lenaNoise.png') img_bilateralFilter1 = cv2.bilateralFilter(img, 15, 150, 1000) img_bilateralFilter2 = cv2.bilateralFilter(img, 3, 255, 1000) fig, axes = plt.subplots(1,3, figsize=(10,5), dpi=100) axes[0].imshow(img[:,:,::-1]) axes[1].imshow(img_bilateralFilter1[:,:,::-1]) axes[2].imshow(img_bilateralFilter2[:,:,::-1]) plt.show()
?說明:如果sigmaColor較小,比如10,濾波效果不太明顯,如果較大比如150,濾波效果就非常明顯,會產(chǎn)生卡通的效果。
#例7.6 觀察雙邊濾波對邊緣信息的處理效果 import cv2 import matplotlib.pyplot as plt img = cv2.imread(r'C:\Users\25584\Desktop\bilTest.bmp') img_GaussianBlur = cv2.GaussianBlur(img, (55, 55), 0, 0) #高斯濾波 img_bilateralFilter = cv2.bilateralFilter(img, 55, 100, 1000) #雙邊濾波 fig, axes = plt.subplots(1,3, figsize=(10,5), dpi=100) axes[0].imshow(img[:,:,::-1]) axes[1].imshow(img_GaussianBlur[:,:,::-1]) axes[2].imshow(img_bilateralFilter[:,:,::-1]) plt.show()
說明:可見高斯核把邊緣信息模糊虛化了,而雙邊濾波核較好的保存了邊緣信息。
六、自定義卷積核實現(xiàn)卷積操作---2D卷積
如果上面的均值濾波卷積核、方框濾波卷積核、高斯濾波卷積核、中值濾波卷積核、雙邊濾波卷積核都不能滿足我們對圖像的處理要求,此時我們就需要一個更加靈活的核——即我們自定義一個我們想要的核。如何實現(xiàn)呢?opencv中的cv2.filter2D()函數(shù)可以幫助我們實現(xiàn):
cv2.filter2D(img, ddepth, kernel, anchor, delta, borderType)
img:要處理的原圖
ddepth: 默認-1,表示與原圖圖像相同的深度
kernel: 卷積核,是一個單通道的數(shù)組。如果想處理彩圖時,讓每個通道使用不同的核,就必須先將彩圖分解后再使用不同的核去卷積操作。
anchor: 默認值是(-1,-1),默認計算的結(jié)果位于核的中心位置。
delta:這個參數(shù)可寫可不寫。如果寫,表示在卷積操作時,對應位置相乘相加后再加一個偏置,這個偏置就是delta。
borderType: 邊界處理方式,一般用默認值即可。文章來源:http://www.zghlxwxcb.cn/news/detail-768417.html#例7.7 自定義卷積核,練習cv2.filter2D()函數(shù) import cv2 import matplotlib.pyplot as plt import numpy as np img = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp') kernel = np.ones((9,9), np.float32)/81 #在實際中我們可以定義更復雜的卷積核,以實現(xiàn)自定義濾波操作 img_filter = cv2.filter2D(img, -1, kernel) #這個濾波器就相當于均值濾波 img_blur = cv2.blur(img, (9,9)) #均值濾波 fig, axes = plt.subplots(1,3, figsize=(10,5), dpi=100) axes[0].imshow(img[:,:,::-1]) axes[1].imshow(img_filter[:,:,::-1]) axes[2].imshow(img_blur[:,:,::-1]) plt.show()
文章來源地址http://www.zghlxwxcb.cn/news/detail-768417.html
到了這里,關(guān)于【OpenCV】第七章: 圖像平滑處理的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!