圖像濾波的主要目的是為了在保留圖像細節的情況下盡量的對圖像的噪聲進行消除,從而是后來的圖像處理變得更加的方便.
圖像的濾波效果要滿足兩個條件:1.不能損壞圖像的輪廓和邊緣這些重要的特征信息.2.圖像的視覺效果更好
opencv支持圖像濾波,提供了五個基本算法,分別是方框濾波,均值濾波,高斯濾波,中值濾波以及雙邊濾波,前三種為線性濾波算法,后兩種為非線性濾波算法,接下來分別對這五種濾波方式進行講解和演示
一.方框濾波
首先,線性濾波算法必須知道的概念叫做鄰域算子,是指利用一張圖片中給點的像素點的周圍的像素值決定該給定點的像素的一種算子,愛opencv中經常使用,用來做圖像的模糊或者是銳化,例如,鄰域算子實際上是一個X*Y的矩陣和該矩陣怎么和圖像中的像素進行計算並得到最終的結果的一種集合性質的描述.
就像程序=算法+數據結構一樣,鄰域算子=矩陣+計算方法,計算方法可以是乘法,除法,求和,卷積等.
方框濾波算法的原理很簡單,指定一個X*Y的矩陣大小,目標像素的周圍X*Y矩陣內的像素全部相加作為目標像素的值,就這么簡單.
API: void boxFilter(源圖像,目的圖像,int 輸出圖像的深度,Size 鄰域算子的大小,Point 錨點,bool 歸一化標志,int 邊界模式).
說明:1.源圖像可以是彩色圖或者是灰度圖,因為圖像處理的時候,通道是分開來處理的
2.目的圖像的大小和通道數必須和源圖像相同,另外,目的圖像的深度由后一個參 數決定
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的五種基本濾波操作,在實際應用中,要根據實際情況靈活的選擇濾波方式,噪聲不同,圖像數據的分析重點不同,都會影響最終濾波算法的選擇.
