【图像处理】【计算机视觉】线性邻域滤波专场:方框滤波、均值滤波与高斯滤波...
首先注意點:關于OpenCV中的函數,有老的數據結構,還有新的opencv2的數據結構,一般地區別就是IplImage*與Mat的區別,兩者大致分別對應著C和C++內的兩個功能一樣,但是函數名稱有別。所以,在使用中最好的辦法就是盡量查看OpenCV的手冊,因為它對應的C++,C和Python版本等都寫了出來,非常好的工具不能忘了。
下面是使一些比較熱門的圖像濾波操作,對應的是基于C++的Mat數據類型(參考:http://blog.csdn.net/pi9nc/article/details/22977297):
本篇文章中,我們一起仔細探討了OpenCV圖像處理技術中比較熱門的圖像濾波操作。圖像濾波系列文章淺墨準備花兩次更新的時間來講,此為上篇,為大家剖析了“方框濾波“,”均值濾波“和”高斯濾波“三種常見線性鄰域濾波操作。而作為非線性濾波的“中值濾波”和“雙邊濾波”,留待我們下次剖析。
先上一張精彩截圖:
淺墨其實很希望把這篇文章寫得精簡和簡明扼要,發現越深入寫進去,需要講的周邊內容越多,于是文章越寫越長,最后在word中字數統計突破了一萬。。。。。。。
因為文章很長,如果詳細啃的話,或許會消化不良。在這里給大家一個指引,如果是單單想要掌握這篇文章中講解的OpenCV線性濾波相關的三個函數:boxFilter,blur和GaussianBlur的使用方法的話,直接看第三部分“淺出”和第四部分“實例”就行。
?
在以后寫的OpenCV系列文章中,淺墨暫且準備將每篇博文中知識點都分成原理、深入、淺出和實例四大部分來講解,
第一部分為和圖像處理中線性濾波相關的理論,第二部分“深入”部分主要深入OpenCV內部,帶領大家領略OpenCV的開源魅力,進行OpenCV相關源碼的剖析,做到對OpenCV理解深刻,做一個高端大氣的OpenCV使用者。 第三部分“淺出”主要教會大家如何快速上手當前文章中介紹的相關OpenCV API函數。而在第四部分,淺墨會為大家準備一個和本篇文章相關的詳細注釋的綜合實例程序。
這樣的話呢,文章既不失深度,也不失快速入門的良方。希望淺墨按這樣的新思路寫出來的文章,無論是新手還是高手,看了都能有所收獲。
給出本篇萬字文章的結構脈絡:
?
一、理論——相關圖像處理概念介紹
二、深入——OpenCV源碼講解
三、淺出——API函數講解
四、實例——詳細注釋的博文配套程序
?
OK,我們開始吧。
一、理論與概念講解
<1>關于平滑處理
“平滑處理“(smoothing)也稱“模糊處理”(bluring),是一項簡單且使用頻率很高的圖像處理方法。平滑處理的用途有很多,最常見的是用來減少圖像上的噪點或者失真。在涉及到降低圖像分辨率時,平滑處理是非常好用的方法。
<2>圖像濾波與濾波器
首先我們看一下圖像濾波的概念。圖像濾波,即在盡量保留圖像細節特征的條件下對目標圖像的噪聲進行抑制,是圖像預處理中不可缺少的操作,其處理效果的好壞將直接影響到后續圖像處理和分析的有效性和可靠性。
消除圖像中的噪聲成分叫作圖像的平滑化或濾波操作。信號或圖像的能量大部分集中在幅度譜的低頻和中頻段是很常見的,而在較高頻段,感興趣的信息經常被噪聲淹沒。因此一個能降低高頻成分幅度的濾波器就能夠減弱噪聲的影響。
圖像濾波的目的有兩個:一是抽出對象的特征作為圖像識別的特征模式;另一個是為適應圖像處理的要求,消除圖像數字化時所混入的噪聲。
而對濾波處理的要求也有兩條:一是不能損壞圖像的輪廓及邊緣等重要信息;二是使圖像清晰視覺效果好。
平滑濾波是低頻增強的空間域濾波技術。它的目的有兩類:一類是模糊;另一類是消除噪音。(各種“兩",:))
空間域的平滑濾波一般采用簡單平均法進行,就是求鄰近像元點的平均亮度值。鄰域的大小與平滑的效果直接相關,鄰域越大平滑的效果越好,但鄰域過大,平滑會使邊緣信息損失的越大,從而使輸出的圖像變得模糊,因此需合理選擇鄰域的大小。
關于濾波器,一種形象的比喻法是:我們可以把濾波器想象成一個包含加權系數的窗口,當使用這個濾波器平滑處理圖像時,就把這個窗口放到圖像之上,透過這個窗口來看我們得到的圖像。
濾波器的種類有很多, 在新版本的OpenCV中,提供了如下五種常用的圖像平滑處理操作方法,且他們分別被封裝在單獨的函數中,使用起來非常方便:
?
- 方框濾波——boxblur函數
- 均值濾波(鄰域平均濾波)——blur函數
- 高斯濾波——GaussianBlur函數
- 中值濾波——medianBlur函數
- 雙邊濾波——bilateralFilter函數
?
今天我們要講解的是作為線性濾波的方框濾波,均值濾波和高斯濾波。兩種非線性濾波操作——中值濾波和雙邊濾波,我們留待下次講解。
?
<3>對線性濾波器的簡介
?
線性濾波器:線性濾波器經常用于剔除輸入信號中不想要的頻率或者從許多頻率中選擇一個想要的頻率。
幾種常見的線性濾波器:
- 允許低頻率通過的低通濾波器。
- 允許高頻率通過的高通濾波器。
- 允許一定范圍頻率通過的帶通濾波器。
- 阻止一定范圍頻率通過并且允許其它頻率通過的帶阻濾波器。
- 允許所有頻率通過、僅僅改變相位關系的全通濾波器。
- 阻止一個狹窄頻率范圍通過的特殊帶阻濾波器,陷波濾波器(Band-stop filter)。
<4>關于濾波和模糊
關于濾波和模糊,大家往往在初次接觸的時候會弄混淆,“一會兒說濾波,一會兒又說模糊,什么玩意兒啊”。
沒關系,在這里,我們就來辨別一下,為大家掃清障礙。
我們上文已經提到過,濾波是將信號中特定波段頻率濾除的操作,是抑制和防止干擾的一項重要措施。
為了方便說明,就拿我們經常用的高斯濾波來作例子吧。我們知道,濾波可分低通濾波和高通濾波兩種。而高斯濾波是指用高斯函數作為濾波函數的濾波操作,至于是不是模糊,要看是高斯低通還是高斯高通,低通就是模糊,高通就是銳化。
其實說白了是很簡單的,對吧:
高斯濾波是指用高斯函數作為濾波函數的濾波操作。
高斯模糊就是高斯低通濾波。
<5>鄰域算子與線性鄰域濾波
鄰域算子(局部算子)是利用給定像素周圍的像素值的決定此像素的最終輸出值的一種算子。而線性鄰域濾波是一種常用的鄰域算子,像素的輸出值取決于輸入像素的加權和,具體過程如下圖。
鄰域算子除了用于局部色調調整以外,還可以用于圖像濾波,實現圖像的平滑和銳化,圖像邊緣增強或者圖像噪聲的去除。本篇文章,我們介紹的主角是線性鄰域濾波算子,即用不同的權重去結合一個小鄰域內的像素,來得到應有的處理效果。
圖注:鄰域濾波(卷積):左邊圖像與中間圖像的卷積產生右邊圖像。目標圖像中藍色標記的像素是利用原圖像中紅色標記的像素計算得到的。
?
線性濾波處理的輸出像素值是輸入像素值的加權和 :
?
其中的加權和為 ,我們稱其為“核”,濾波器的加權系數,即濾波器的“濾波系數”。
?
上面的式子可以簡單寫作:
?
其中f表示輸入像素值,h表示加權系數“核“,g表示輸出像素值
在新版本的OpenCV中,提供了如下三種常用的線性濾波操作,他們分別被封裝在單獨的函數中,使用起來非常方便:
?
方框濾波——boxblur函數
均值濾波——blur函數
高斯濾波——GaussianBlur函數
?
下面我們來對他們進行一一介紹。
<6>方框濾波(box Filter)
方框濾波(box Filter)被封裝在一個名為boxblur的函數中,即boxblur函數的作用是使用方框濾波器(box filter)來模糊一張圖片,從src輸入,從dst輸出。
函數原型如下:
C++:?void?boxFilter(InputArray?src,OutputArray?dst,?int?ddepth,?Size?ksize,?Point?anchor=Point(-1,-1),?boolnormalize=true,?int?borderType=BORDER_DEFAULT?)?
??
參數詳解:
- 第一個參數,InputArray類型的src,輸入圖像,即源圖像,填Mat類的對象即可。該函數對通道是獨立處理的,且可以處理任意通道數的圖片,但需要注意,待處理的圖片深度應該為CV_8U, CV_16U, CV_16S, CV_32F 以及 CV_64F之一。
- 第二個參數,OutputArray類型的dst,即目標圖像,需要和源圖片有一樣的尺寸和類型。
- 第三個參數,int類型的ddepth,輸出圖像的深度,-1代表使用原圖深度,即src.depth()。
- 第四個參數,Size類型(對Size類型稍后有講解)的ksize,內核的大小。一般這樣寫Size( w,h )來表示內核的大小( 其中,w 為像素寬度, h為像素高度)。Size(3,3)就表示3x3的核大小,Size(5,5)就表示5x5的核大小
- 第五個參數,Point類型的anchor,表示錨點(即被平滑的那個點),注意他有默認值Point(-1,-1)。如果這個點坐標是負值的話,就表示取核的中心為錨點,所以默認值Point(-1,-1)表示這個錨點在核的中心。
- 第六個參數,bool類型的normalize,默認值為true,一個標識符,表示內核是否被其區域歸一化(normalized)了。
- 第七個參數,int類型的borderType,用于推斷圖像外部像素的某種邊界模式。有默認值BORDER_DEFAULT,我們一般不去管它。
boxFilter()函數方框濾波所用的核為:
?
?
其中:
?
?
其中f表示原圖,h表示核,g表示目標圖,當normalize=true的時候,方框濾波就變成了我們熟悉的均值濾波。也就是說,均值濾波是方框濾波歸一化(normalized)后的特殊情況。其中,歸一化就是把要處理的量都縮放到一個范圍內,比如(0,1),以便統一處理和直觀量化。
而非歸一化(Unnormalized)的方框濾波用于計算每個像素鄰域內的積分特性,比如密集光流算法(dense optical flow algorithms)中用到的圖像倒數的協方差矩陣(covariance matrices of image derivatives)
如果我們要在可變的窗口中計算像素總和,可以使用integral()函數。
<7>均值濾波
均值濾波,是最簡單的一種濾波操作,輸出圖像的每一個像素是核窗口內輸入圖像對應像素的像素的平均值( 所有像素加權系數相等),其實說白了它就是歸一化后的方框濾波。
我們在下文進行源碼剖析時會發現,blur函數內部中其實就是調用了一下boxFilter。
下面開始講均值濾波的內容吧。
1)均值濾波的理論簡析
均值濾波是典型的線性濾波算法,主要方法為鄰域平均法,即用一片圖像區域的各個像素的均值來代替原圖像中的各個像素值。一般需要在圖像上對目標像素給出一個模板(內核),該模板包括了其周圍的臨近像素(比如以目標像素為中心的周圍8(3x3-1)個像素,構成一個濾波模板,即去掉目標像素本身)。再用模板中的全體像素的平均值來代替原來像素值。即對待處理的當前像素點(x,y),選擇一個模板,該模板由其近鄰的若干像素組成,求模板中所有像素的均值,再把該均值賦予當前像素點(x,y),作為處理后圖像在該點上的灰度個g(x,y),即個g(x,y)=1/m ∑f(x,y) ,其中m為該模板中包含當前像素在內的像素總個數。
?
2)均值濾波的缺陷
均值濾波本身存在著固有的缺陷,即它不能很好地保護圖像細節,在圖像去噪的同時也破壞了圖像的細節部分,從而使圖像變得模糊,不能很好地去除噪聲點。
?
3)在OpenCV中使用均值濾波——blur函數
blur函數的作用是,對輸入的圖像src進行均值濾波后用dst輸出。
blur函數文檔中,給出的其核是這樣的:
這個內核一看就明了,就是在求均值,即blur函數封裝的就是均值濾波。
?blur函數的原型:C++:?void?blur(InputArray?src,?OutputArraydst,?Size?ksize,?Point?anchor=Point(-1,-1),?int?borderType=BORDER_DEFAULT?)?
[cpp]?view plaincopy
- 第一個參數,InputArray類型的src,輸入圖像,即源圖像,填Mat類的對象即可。該函數對通道是獨立處理的,且可以處理任意通道數的圖片,但需要注意,待處理的圖片深度應該為CV_8U, CV_16U, CV_16S, CV_32F 以及 CV_64F之一。
- 第二個參數,OutputArray類型的dst,即目標圖像,需要和源圖片有一樣的尺寸和類型。比如可以用Mat::Clone,以源圖片為模板,來初始化得到如假包換的目標圖。
- 第三個參數,Size類型(對Size類型稍后有講解)的ksize,內核的大小。一般這樣寫Size( w,h )來表示內核的大小( 其中,w 為像素寬度, h為像素高度)。Size(3,3)就表示3x3的核大小,Size(5,5)就表示5x5的核大小
- 第四個參數,Point類型的anchor,表示錨點(即被平滑的那個點),注意他有默認值Point(-1,-1)。如果這個點坐標是負值的話,就表示取核的中心為錨點,所以默認值Point(-1,-1)表示這個錨點在核的中心。
- 第五個參數,int類型的borderType,用于推斷圖像外部像素的某種邊界模式。有默認值BORDER_DEFAULT,我們一般不去管它。
<8>高斯濾波
1)高斯濾波的理論簡析
?
高斯濾波是一種線性平滑濾波,適用于消除高斯噪聲,廣泛應用于圖像處理的減噪過程。通俗的講,高斯濾波就是對整幅圖像進行加權平均的過程,每一個像素點的值,都由其本身和鄰域內的其他像素值經過加權平均后得到。高斯濾波的具體操作是:用一個模板(或稱卷積、掩模)掃描圖像中的每一個像素,用模板確定的鄰域內像素的加權平均灰度值去替代模板中心像素點的值。
大家常常說高斯濾波最有用的濾波操作,雖然它用起來,效率往往不是最高的。
高斯模糊技術生成的圖像,其視覺效果就像是經過一個半透明屏幕在觀察圖像,這與鏡頭焦外成像效果散景以及普通照明陰影中的效果都明顯不同。高斯平滑也用于計算機視覺算法中的預先處理階段,以增強圖像在不同比例大小下的圖像效果(參見尺度空間表示以及尺度空間實現)。從數學的角度來看,圖像的高斯模糊過程就是圖像與正態分布做卷積。由于正態分布又叫作高斯分布,所以這項技術就叫作高斯模糊。
圖像與圓形方框模糊做卷積將會生成更加精確的焦外成像效果。由于高斯函數的傅立葉變換是另外一個高斯函數,所以高斯模糊對于圖像來說就是一個低通濾波操作。
?高斯濾波器是一類根據高斯函數的形狀來選擇權值的線性平滑濾波器。高斯平滑濾波器對于抑制服從正態分布的噪聲非常有效。一維零均值高斯函數為:
???
其中,高斯分布參數Sigma決定了高斯函數的寬度。對于圖像處理來說,常用二維零均值離散高斯函數作平滑濾波器。
二維高斯函數為:
?
?
2)在OpenCV中使用高斯濾波——GaussianBlur函數
?
GaussianBlur函數的作用是用高斯濾波器來模糊一張圖片,對輸入的圖像src進行高斯濾波后用dst輸出。它將源圖像和指定的高斯核函數做卷積運算,并且支持就地過濾(In-placefiltering)。
C++: void GaussianBlur(InputArray src,OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, intborderType=BORDER_DEFAULT ) ?
- 第一個參數,InputArray類型的src,輸入圖像,即源圖像,填Mat類的對象即可。它可以是單獨的任意通道數的圖片,但需要注意,圖片深度應該為CV_8U,CV_16U, CV_16S, CV_32F 以及 CV_64F之一。
- 第二個參數,OutputArray類型的dst,即目標圖像,需要和源圖片有一樣的尺寸和類型。比如可以用Mat::Clone,以源圖片為模板,來初始化得到如假包換的目標圖。
- 第三個參數,Size類型的ksize高斯內核的大小。其中ksize.width和ksize.height可以不同,但他們都必須為正數和奇數。或者,它們可以是零的,它們都是由sigma計算而來。
- 第四個參數,double類型的sigmaX,表示高斯核函數在X方向的的標準偏差。
- 第五個參數,double類型的sigmaY,表示高斯核函數在Y方向的的標準偏差。若sigmaY為零,就將它設為sigmaX,如果sigmaX和sigmaY都是0,那么就由ksize.width和ksize.height計算出來。
- 為了結果的正確性著想,最好是把第三個參數Size,第四個參數sigmaX和第五個參數sigmaY全部指定到。
- 第六個參數,int類型的borderType,用于推斷圖像外部像素的某種邊界模式。有默認值BORDER_DEFAULT,我們一般不去管它。
?嗯,第一部分的理論介紹大概就是這些了,我們接著進入第二部分,OpenCV的源碼剖析。
二、深入——OpenCV源碼剖析
上一篇文章中我們已經和當前最新版的OpenCV的源碼親密接觸過。 在這一部分中,淺墨將帶領大家領略OpenCV的開源魅力,對OpenCV中本篇文章里講解到線性濾波函數——boxFilter,blur和GaussianBlur函數以及周邊的涉及到的源碼進行適當的剖析。
這樣,我們就可以對 OpenCV有一個更加深刻的理解,成為一個高端大氣的OpenCV使用者。
<1>OpenCV中boxFilter函數源碼解析
我們可以在OpenCV的安裝路徑的\sources\modules\imgproc\src下的smooth.cpp源文件的第711行找到boxFilter函數的源代碼。對應于淺墨將OpenCV 2.4.8安裝在D:\Program Files\opencv的路徑下,那么,smooth.cpp文件就在D:\ProgramFiles\opencv\sources\modules\imgproc\src路徑下。
?//-----------------------------------【boxFilter()函數中文注釋版源代碼】---------------------------- ?
// ? ? 代碼作用:進行box Filter濾波操作的函數 ?
// ? ? 說明:以下代碼為來自于計算機開源視覺庫OpenCV的官方源代碼 ?
// ? ? OpenCV源代碼版本:2.4.8 ?
// ? ? 源碼路徑:…\opencv\sources\modules\imgproc\src\smooth.cpp ?
// ? ? 源文件中如下代碼的起始行數:711行 ?
// ? ? 中文注釋by淺墨 ?
//-------------------------------------------------------------------------------------------------------- ?
void cv::boxFilter( InputArray _src,OutputArray _dst, int ddepth, ?
? ? ? ? ? ? ? ? Size ksize, Point anchor, ?
? ? ? ? ? ? ? ? bool normalize, int borderType) ?
{ ?
? ?Mat src = _src.getMat();//拷貝源圖的形參Mat數據到臨時變量,用于稍后的操作 ?
int sdepth =src.depth(), cn = src.channels();//定義int型臨時變量,代表源圖深度的sdepth,源圖通道的引用cn ?
? ?
//處理ddepth小于零的情況 ?
? ?if( ddepth < 0 ) ?
? ? ? ?ddepth = sdepth; ?
? ?_dst.create( src.size(), CV_MAKETYPE(ddepth, cn) );//初始化目標圖 ?
Mat dst =_dst.getMat();//拷貝目標圖的形參Mat數據到臨時變量,用于稍后的操作 ?
? ?
//處理 borderType不為 BORDER_CONSTANT 且normalize為真的情況 ?
? ?if( borderType != BORDER_CONSTANT && normalize ) ? ?{ ?
? ? ? ?if( src.rows == 1 ) ?
? ? ? ? ? ?ksize.height = 1; ?
? ? ? ?if( src.cols == 1 ) ?
? ? ? ? ? ?ksize.width = 1; ?
} ?
? ?
//若之前有過HAVE_TEGRA_OPTIMIZATION優化選項的定義,則執行宏體中的tegra優化版函數并返回 ?
#ifdef HAVE_TEGRA_OPTIMIZATION ?
? ?if ( tegra::box(src, dst, ksize, anchor, normalize, borderType) ) ?
? ? ? ?return; ?
#endif ?
? ?
? ? ? ?//調用FilterEngine濾波引擎,正式開始濾波操作 ?
? ?Ptr<FilterEngine> f = createBoxFilter( src.type(), dst.type(), ?
? ? ? ? ? ? ? ? ? ? ? ? ksize, anchor,normalize, borderType ); ?
? ?f->apply( src, dst ); ?
} ?
轉載于:https://www.cnblogs.com/huty/p/8518168.html
總結
以上是生活随笔為你收集整理的【图像处理】【计算机视觉】线性邻域滤波专场:方框滤波、均值滤波与高斯滤波...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 足球队
- 下一篇: 搭建Python+Django开发环境