圖像濾波的主要目的是爲了在保留圖像細節的狀況下儘可能的對圖像的噪聲進行消除,從而是後來的圖像處理變得更加的方便.算法
圖像的濾波效果要知足兩個條件:1.不能損壞圖像的輪廓和邊緣這些重要的特徵信息.2.圖像的視覺效果更好數據結構
opencv支持圖像濾波,提供了五個基本算法,分別是方框濾波,均值濾波,高斯濾波,中值濾波以及雙邊濾波,前三種爲線性濾波算法,後兩種爲非線性濾波算法,接下來分別對這五種濾波方式進行講解和演示函數
一.方框濾波blog
首先,線性濾波算法必須知道的概念叫作鄰域算子,是指利用一張圖片中給點的像素點的周圍的像素值決定該給定點的像素的一種算子,愛opencv中常用,用來作圖像的模糊或者是銳化,例如,鄰域算子其實是一個X*Y的矩陣和該矩陣怎麼和圖像中的像素進行計算並獲得最終的結果的一種集合性質的描述.排序
就像程序=算法+數據結構同樣,鄰域算子=矩陣+計算方法,計算方法能夠是乘法,除法,求和,卷積等.接口
方框濾波算法的原理很簡單,指定一個X*Y的矩陣大小,目標像素的周圍X*Y矩陣內的像素所有相加做爲目標像素的值,就這麼簡單.圖片
API: void boxFilter(源圖像,目的圖像,int 輸出圖像的深度,Size 鄰域算子的大小,Point 錨點,bool 歸一化標誌,int 邊界模式).it
說明:1.源圖像能夠是彩色圖或者是灰度圖,由於圖像處理的時候,通道是分開來處理的圖像處理
2.目的圖像的大小和通道數必須和源圖像相同,另外,目的圖像的深度由後一個參 數決定opencv
3.輸出圖像的深度,指定CV_8U....,當爲-1的時候,目標圖像的深度和源圖像的深度 相同
4.錨點,指被平滑的那個點位於領域算子矩陣的哪個位置,從而肯定計算時候的 像素點的取值,若是是Point(-1,-1),那麼自動取值中間的那個點.
5.歸一化標誌,默認歸一化爲真,會將目標圖像歸一化到源圖像的取值範圍
能夠看到,咱們能夠改變的參數就是鄰域算子的大小,經過這種算法,咱們可以去除圖像中忽然出現的極大值點(噪點)的影響,可是同時,這種算法不能很好的保存圖像的細節,在濾波的時候容易丟失細節.一下是方框濾波的程序演示.
//方¤?框¨°濾?波¡§ const int g_boxFilterMax = 100;//最大的鄰域取值 int g_nboxFilterValue; Mat boxFilterImage; Mat srcImage; void onBoxFilterTrackBar(int pos,void* userData); int main(int argc,char* argv[]) { g_nboxFilterValue = 5; srcImage = imread("F:\\opencv\\OpenCVImage\\boxFilter.jpg"); namedWindow("box filter"); createTrackbar("size value ", "box filter", &g_nboxFilterValue, g_boxFilterMax,onBoxFilterTrackBar,0); onBoxFilterTrackBar(g_nboxFilterValue, 0); imshow("src image", srcImage); moveWindow("src image", 0, 0); moveWindow("box filter", srcImage.cols, 0); waitKey(0); return 0; } void onBoxFilterTrackBar(int pos,void* userData) { if(pos == 0) { imshow("box filter", srcImage); } else { boxFilter(srcImage, boxFilterImage, srcImage.depth(), Size(pos,pos)); imshow("box filter", boxFilterImage); } }
二.均值濾波
均值濾波其實就是方框濾波的默認歸一化版本,這個算法接口取消了歸一化參數,因此實際效果和方框濾波,差別不大
API void blur(源圖,目標圖,size,錨點,邊界模式);
實際操做代碼以下
// 均值濾波 Mat srcImage; const int g_blurMax = 100; int g_nblurValue; Mat blurImage; void onBlurTrackBar(int pos,void* userData); int main(int argc,char* argv[]) { srcImage = imread("F:\\opencv\\OpenCVImage\\boxFilter.jpg"); g_nblurValue = 5; namedWindow("blur"); createTrackbar("size value ", "blur", &g_nblurValue, g_blurMax,onBlurTrackBar,0); onBlurTrackBar(g_nblurValue, 0); imshow("src image", srcImage); moveWindow("src image", 0, 0); moveWindow("blur", srcImage.cols, 0); waitKey(0); return 0; } void onBlurTrackBar(int pos,void* userData) { if(pos == 0) { imshow("blur", srcImage); } else { boxFilter(srcImage, blurImage, srcImage.depth(), Size(pos,pos)); imshow("blur", blurImage); } }
三.高斯濾波
高斯濾波是專門用於消除知足高斯分佈(正態分佈)的偏差而存在的濾波,此時鄰域算子是專門的高斯核,圖像中的像素與高斯核作卷積,生成的結果加權平均存放到目標像素中,對於抑制符合正態分佈的噪聲很是有效,並能夠加強圖像值不一樣比例下的圖像效果,視覺效果相似於隔了一層半透明玻璃看圖像.
API:void GaussianBlur(源圖像,目標圖像,Size 高斯內核,double 高斯核函數在X方向上的標準差,double 高斯核函數在Y方向的標準差,int 邊界模式).
注:高斯核函數的大小必須爲奇數,同時也必須爲正數,原圖片可使單通道或者是多通道,若是X,Y方向標準差都爲0,那麼API將自動根據核函數的長寬,計算出一個合適的二維零均值高斯函數.
使用代碼以下
Mat srcImage; const int g_GaussianBlurMax = 100; int g_nGaussianBlurValue; Mat GaussianBlurImage; void onGaussianBlurTrackBar(int pos,void* userData); int main(int argc,char* argv[]) { srcImage = imread("F:\\opencv\\OpenCVImage\\boxFilter.jpg"); g_nGaussianBlurValue = 5; namedWindow("GaussianBlur"); createTrackbar("size value ", "GaussianBlur", &g_nGaussianBlurValue, g_GaussianBlurMax,onGaussianBlurTrackBar,0); onGaussianBlurTrackBar(g_nGaussianBlurValue, 0); imshow("src image", srcImage); moveWindow("src image", 0, 0); moveWindow("GaussianBlur", srcImage.cols, 0); waitKey(0); return 0; } void onGaussianBlurTrackBar(int pos,void* userData) { if(pos == 0) { imshow("GaussianBlur", srcImage); } else { //高斯濾波核必須爲奇數 if(pos%2 == 0) { pos++; } GaussianBlur(srcImage, GaussianBlurImage, Size(pos,pos), 0,0);//自動計算xy標準差 imshow("GaussianBlur",GaussianBlurImage); } }
經過以上的狀況咱們能夠看到,對於那種散粒噪聲,尖峯噪聲,線性濾波每每不能很好的清除,或者清除以後必然會帶來對鄰域的影響,噪聲只是變得柔和了而已.這時候就能夠考慮非線性濾波
四.中值濾波
線性濾波的基本原理是對指定像素的指定鄰域的灰度值進行一個排序,而後選擇中間的灰度值來直接替代指定像素的灰度值,從而消除孤立的噪聲點,對於斑點噪聲和椒鹽噪聲尤爲有用,同時還能夠保存邊緣.對脈衝型的干擾尤爲有效,由於在實際狀況中,噪聲點的灰度和鄰域的值的差異很大,因此,中值通常不容易是噪聲點灰度.可是由於基於統計排序,因此運行時間通常是均值濾波的五倍以上.
API:void medianBlur(源圖像,目標圖像,int 鄰域大小)
注:鄰域必須是大於1的奇數
使用例子以下
const int g_MedianBlurMax = 100; int g_nMedianBlurValue; Mat MedianBlurImage; Mat srcImage; void onMedianBlurTrackBar(int pos,void* userData); int main(int argc,char* argv[]) { srcImage = imread("F:\\opencv\\OpenCVImage\\boxFilter.jpg"); g_nMedianBlurValue = 5; namedWindow("median filter"); createTrackbar("size value ", "median filter", &g_nMedianBlurValue, g_MedianBlurMax,onMedianBlurTrackBar,0); onMedianBlurTrackBar(g_nMedianBlurValue, 0); imshow("src image", srcImage); moveWindow("src image", 0, 0); moveWindow("median filter", srcImage.cols, 0); waitKey(0); return 0; } void onMedianBlurTrackBar(int pos,void* userData) { if(pos == 0) { imshow("median filter", srcImage); } else { //中值¦濾波孔徑大小必須爲奇數 if(pos%2 == 0) { pos++; } medianBlur(srcImage, MedianBlurImage, pos); imshow("median filter",MedianBlurImage); } }
五.雙邊濾波
前面的濾波,或多或少的都會使得目標點的像素受到鄰域的影響,鄰域越大,影響越大,而雙邊濾波同時考慮了圖像的灰度類似性和空間域信息,基本理念是鄰域的計算附帶權重,距離目標點越遠的鄰域像素對目標像素的影響越小,也就是權重越低,這樣,離得較遠的像素就不會對邊緣的影響過多,能很好的保存邊緣,同時也能濾波部分噪聲.
可是,雙邊濾波保存了過多的高頻信息,對於彩色圖像中的高頻噪聲,雙邊濾波不能很好的濾除掉.
API:void bilateralFilter(源圖像,目標圖像,int 像素鄰域直徑, ,double 顏色空間濾波器sigma doble 座標空間濾波器sigma,int 邊緣類型);
注:1.若像素直徑爲負數,會自動從座標空間濾波器sigma來計算像素鄰域直徑.
2.顏色空間濾波器sigma值,這個值越大,表明像素領域內越寬廣的顏色會被混合在一 起,形成更大的半相等的顏色區域
3.座標空間濾波器sigma,這是座標空間的標準方差,這個值越大,表明鄰域空間中越遠 的值會相互影響
例程以下
Mat srcImage; const int g_BialateralFilterMax = 100; int g_nBialateralFilterValue; Mat BialateralFilterImage; void onBialateralFilterTrackBar(int pos,void* userData); int main(int argc,char* argv[]) { srcImage = imread("F:\\opencv\\OpenCVImage\\boxFilter.jpg"); g_nBialateralFilterValue = 5; namedWindow("bilateral filter"); createTrackbar("size value ", "bilateral filter", &g_nBialateralFilterValue, g_BialateralFilterMax,onBialateralFilterTrackBar,0); onBialateralFilterTrackBar(g_nBialateralFilterValue, 0); imshow("src image", srcImage); moveWindow("src image", 0, 0); moveWindow("bilateral filter", srcImage.cols, 0); waitKey(0); return 0; } //雙邊濾波計算速度比較慢 void onBialateralFilterTrackBar(int pos,void* userData) { if(pos == 0) { imshow("bilateral filter", srcImage); } else { //必須爲奇數 if(pos%2 == 0) { pos++; } bilateralFilter(srcImage, BialateralFilterImage, pos, pos/2, pos*2); imshow("bilateral filter",BialateralFilterImage); } }
小結:以上就是opencv的五種基本濾波操做,在實際應用中,要根據實際狀況靈活的選擇濾波方式,噪聲不一樣,圖像數據的分析重點不一樣,都會影響最終濾波算法的選擇.