opencv 图像去噪要点总结
生活随笔
收集整理的這篇文章主要介紹了
opencv 图像去噪要点总结
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
opencv 圖像去噪要點總結
圖像平滑與圖像模糊是同一概念,主要用于圖像的去噪。平滑要使用濾波器,為不改變圖像的相位信息,一般使用線性濾波器。不同的核函數代表不同的濾波器,有不同的用途。
常見的濾波器包括:歸一化濾波器,也是均值濾波器,用輸出像素點核窗口內的像素均值代替輸出點像素值。
高斯濾波器,實際中最常用的濾波器,高斯濾波是將輸入數組的每一個像素點與 高斯內核 卷積將卷積和當作輸出像素值。
中值濾波器,中值濾波將圖像的每個像素用鄰域(以當前像素為中心的正方形區域)像素的中值代替。對椒鹽噪聲最有效,去除跳變點非常有效。
雙邊濾波器,為避免濾波器平滑圖像去噪的同時使邊緣也模糊,這種情況下使用雙邊濾波器。
四種濾波方法分別使用到4個OpenCV函數,這些函數的前2個參數都是原圖像和濾波后圖像。
歸一化濾波器blur的第3個參數為濾波核窗口的大小,Size(i,i)表示ixi大小的窗口。
高斯濾波器GaussianBlur第3個參數也是濾波核窗口的大小,第4、第5個參數分辨表示x方向和y方向的δ。
中值濾波器medianBlur第3個參數是濾波器的長度,該濾波器的窗口為正方形。
雙邊濾波器的函數原型如下:
//! smooths the image using bilateral filter
CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?double sigmaColor, double sigmaSpace,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int borderType=BORDER_DEFAULT );
代數運算中比較常用的是圖像相加和相減。圖像相加常用來求平均值去除addtive噪聲或者實現二次曝光。
圖像相減用于減去背景或周期噪聲,污染等。
圖像相加
OpenCV中提供了相加的函數
void cvAcc( ??
? ? ? ? ? ?const CvArr* image,//輸入圖像 ?
? ? ? ? ? ?CvArr* sum, ?//累積圖像 ??
? ? ? ? ? ?const CvArr* mask=NULL//可選的運算 ?
?); ?
還需要用到一個線性變換轉換函數來對相加的結果求平均
void cvConvertScale( ??
? ? ? ? const CvArr* src, //輸入數組 ?
? ? ? ? CvArr* dst,//輸出數組 ?
? ? ? ? double scale=1,//比例 ?
? ? ? ? double shift=0 //縮放比例,可選 ?
); ?
曝光和去噪是一樣的,也是對幾幅圖像求平均。
圖像相減
OpenCV中用cvAbsDiff函數計算兩數組的差的絕對值
void cvAbsDiff( ??
? ? ? ? const CvArr* src1,//第一個輸入數組 ?
? ? ? ? const CvArr* src2,//第二個輸入數組 ?
? ? ? ? CvArr* dst//輸出數組 ?
); ?
減去背景是通過兩幅圖像代數相減,可以判斷出前景區域和運動區域,這是最簡單(很多時候也是效果很好的)運動檢測方法。
“平滑處理“(smoothing)也稱“模糊處理”(bluring)。平滑處理的用途,最常見的是用來減少圖像上的噪點或者失真。在涉及到降低圖像分辨率時,平滑處理是非常好用的方法。
2.濾波與濾波器
濾波是將信號中特定波段頻率濾除的操作,是抑制和防止干擾的一項重要措施。
而濾波器就是建立的一個數學模型,通過這個模型來將圖像數據進行能量轉化,能量低的就排除掉,噪聲就是屬于低能量部分。
一種形象的比喻法是:我們可以把濾波器想象成一個包含加權系數的窗口,當使用這個濾波器平滑處理圖像時,就把這個窗口放到圖像之上,透過這個窗口來看我們得到的圖像。
在新版本的OpenCV中,提供了如下五種常用的圖像平滑處理操作方法,且他們分別被封裝在單獨的函數中,
方框濾波——boxblur函數
均值濾波——blur函數
高斯濾波——GaussianBlur函數
中值濾波——medianBlur函數
雙邊濾波——bilateralFilter函數
3.線性濾波器
線性濾波器:線性濾波器經常用于剔除輸入信號中不想要的頻率或者從許多頻率中選擇一個想要的頻率。
幾種常見的線性濾波器:
允許低頻率通過的 低通濾波器 。
允許高頻率通過的 高通濾波器 。
允許一定范圍頻率通過的 帶通濾波器 。
阻止一定范圍頻率通過并且允許其它頻率通過的 帶阻濾波器 。
允許所有頻率通過、僅僅改變相位關系的 全通濾波器 。
阻止一個狹窄頻率范圍通過的特殊 帶阻濾波器 , 陷波濾波器 (Band-stop filter)。
4.關于濾波和模糊
濾波是將信號中特定波段頻率濾除的操作。
高斯濾波是指用高斯函數作為濾波函數的濾波操作 ,至于是不是模糊,要看是高斯低通還是高斯高通,低通就是模糊,高通就是銳化。
5.線性濾波
線性濾波是一種常用的鄰域算子,像素的輸出值取決于輸入像素的加權和。
6.方框濾波(box Filter)
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
,一般不去管它。
均值濾波是方框濾波歸一化(normalized)后的特殊情況。其中,歸一化就是把要處
理的量都縮放到一個范圍內,比如(0,1),以便統一處理和直觀量化。
而非歸一化(Unnormalized)的方框濾波用于計算每個像素鄰域內的積分特性,比如密集光流算法
(dense optical flow algorithms)中用到的圖像倒數的協方差矩陣(covariance matrices of image?
derivatives)
如果我們要在可變的窗口中計算像素總和,可以使用integral()函數。
7.均值濾波
均值濾波,是最簡單的一種濾波操作,輸出圖像的每一個像素是核窗口內輸入圖像對應像素的像素的平均
值( 所有像素加權系數相等),其實說白了它就是歸一化后的方框濾波。
均值濾波是典型的線性濾波算法,主要方法為鄰域平均法,即用一片圖像區域的各個像素的均值來代替原
圖像中的各個像素值。一般需要在圖像上對目標像素給出一個模板(內核),該模板包括了其周圍的臨近
像素(比如以目標像素為中心的周圍8(3x3-1)個像素,構成一個濾波模板,即去掉目標像素本身)。再
用模板中的全體像素的平均值來代替原來像素值。即對待處理的當前像素點(x,y),選擇一個模板,該
模板由其近鄰的若干像素組成,求模板中所有像素的均值,再把該均值賦予當前像素點(x,y),作為處
理后圖像在該點上的灰度個g(x,y),即個g(x,y)=1/m ∑f(x,y) ,其中m為該模板中包含當前像
素在內的像素總個數。
均值濾波的缺陷
它不能很好地保護圖像細節,在圖像去噪的同時也破壞了圖像的細節部分,從而使圖像變得模糊,不能很好地去除噪聲點。
blur 函數的原型:
void blur(InputArray src, OutputArraydst, Size ksize, Point anchor=Point(-1,-1), int?
borderType=BORDER_DEFAULT )
第一個參數,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.高斯濾波
高斯濾波是一種線性平滑濾波,適用于消除高斯噪聲,廣泛應用于圖像處理的減噪過程。高斯濾波就是對
整幅圖像進行加權平均的過程,每一個像素點的值,都由其本身和鄰域內的其他像素值經過加
權平均后得到。高斯濾波的具體操作是:用一個模板(或稱卷積、掩模)掃描圖像中的每一個像素,用模
板確定的鄰域內像素的加權平均灰度值去替代模板中心像素點的值。
高斯模糊技術生成的圖像,其視覺效果就像是經過一個半透明屏幕在觀察圖像,這與鏡頭焦外成像效果散
景以及普通照明陰影中的效果都明顯不同。高斯平滑也用于計算機視覺算法中的預先處理階段,以增強圖
像在不同比例大小下的圖像效果(參見尺度空間表示以及尺度空間實現)。從數學的角度來看,圖像的高
斯模糊過程就是圖像與正態分布做卷積。由于正態分布又叫作高斯分布,所以這項技術就叫作高斯模糊。
圖像與圓形方框模糊做卷積將會生成更加精確的焦外成像效果。由于高斯函數的傅立葉變換是另外一個高
斯函數,所以高斯模糊對于圖像來說就是一個低通濾波操作。
? 高斯濾波器是一類根據高斯函數的形狀來選擇權值的線性平滑濾波器。高斯平滑濾波器對于抑制服從正
態分布的噪聲非常有效。
對于圖像處理來說,常用二維零均值離散高斯函數作平滑濾波器。
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
,一般不去管它。
boxFilter()函數
代碼作用:進行box Filter濾波操作的函數
OpenCV源代碼版本:2.4.8
源碼路徑:…\opencv\sources\modules\imgproc\src\smooth.cpp
流程
拷貝源圖的形參Mat數據到臨時變量,用于稍后的操作
定義int型臨時變量,代表源圖深度的sdepth,源圖通道的引用cn
處理ddepth小于零的情況
初始化目標圖
拷貝目標圖的形參Mat數據到臨時變量,用于稍后的操作
處理 borderType不為 BORDER_CONSTANT 且normalize為真的情況
若之前有過HAVE_TEGRA_OPTIMIZATION優化選項的定義,則執行宏體中的tegra優化版函數并返回
調用FilterEngine濾波引擎,正式開始濾波操作
其中的Ptr是用來動態分配的對象的智能指針模板類。可以發現,函數的內部代碼思路是很清晰的,先拷貝源圖的形參Mat數據到臨時變量,定義一些臨時變量,在處理ddepth小于零的情況,接著處理?
borderType不為 BORDER_CONSTANT 且normalize為真的情況,最終調用FilterEngine濾波引擎創建一個
BoxFilter,正式開始濾波操作。
這里的FilterEngine是OpenCV圖像濾波功能的核心引擎。
這個類可以把幾乎是所有的濾波操作施加到圖像上。它包含了所有必要的中間緩存器。有很多和濾波相關
的create系函數的返回值直接就是Ptr<FilterEngine>。
其中的Ptr是用來動態分配的對象的智能指針模板類,而上面的尖括號里面的模板參數就是FilterEngine。
使用FilterEngine類可以分塊處理大量的圖像,構建復雜的管線,其中就包含一些進行濾波階段。如果我
們需要使用預先定義好的的濾波操作,cv::filter2D(), cv::erode(),以及cv::dilate(),可以選擇,他
們不依賴于FilterEngine,在自己函數體內部就實現了FilterEngine提供的功能。不像其他的諸如blur系列函數,依賴于FilterEngine引擎。
FilterEngine類源代碼流程
代碼作用:FilterEngine類,OpenCV圖像濾波功能的核心引擎
OpenCV源代碼版本:2.4.8
源碼路徑:…\opencv\sources\modules\imgproc\include\opencv2\imgproc\imgproc.hpp
?
默認構造函數
完整的構造函數
默認析構函數
重新初始化引擎。釋放之前濾波器申請的內存。
開始對指定了ROI區域和尺寸的圖片進行濾波操作
開始對指定了ROI區域的圖片進行濾波操作
處理圖像的下一個srcCount行(函數的第三個參數)
對圖像指定的ROI區域進行濾波操作,若srcRoi=(0,0,-1,-1),則對整個圖像進行濾波操作
如果濾波器可分離,則返回true
返回輸入和輸出行數
一些成員參數定義
原型聲明
typedef Size_<int> Size2i;
typedef Size2i Size;
Size_ 是個模板類,在這里Size_<int>表示其類體內部的模板所代表的類型為int。
首先給已知的數據類型Size_<int>起個新名字,叫Size2i。
然后又給已知的數據類型Size2i起個新名字,叫Size。
連起來就是,Size_<int>、Size2i、Size這三個類型名等價。
Size_模板類的定義:
OpenCV源代碼版本:2.4.8
源碼路徑:…\opencv\sources\modules\core\include\opencv2\core\core.hpp
不同的構造函數定義
區域(width*height)
轉化另一種數據類型。
轉換為舊式的OpenCV類型.
寬度和高度,常用屬性
可以看到Size_模板類的內部又是重載了一些構造函數以滿足我們的需要,其中,我們用得最多的是如下
這個構造函數:
Size_(_Tp _width, _Tp _height);
另外,代碼末尾定義了模板類型的寬度和高度:
_Tp width, height; //寬度和高度
于是我們可以用XXX. width和XXX.height來分別表示其寬度和高度。
一個示例,方便理解:
Size(5, 5);//構造出的Size寬度和高度都為5,即XXX.width和XXX.height都為5
blur
代碼作用:進行blur均值濾波操作的函數
OpenCV源代碼版本:2.4.8
源碼路徑:…\opencv\sources\modules\imgproc\src\smooth.cpp
流程
調用boxFilter函數進行處理
可以看到在blur函數內部就是調用了一個boxFilter函數,且第六個參數為true,即上文所說的
normalize=true,即均值濾波是均一化后的方框濾波。
代碼作用:封裝高斯濾波的GaussianBlur()函數
OpenCV源代碼版本:2.4.8
源碼路徑:…\opencv\sources\modules\imgproc\src\smooth.cpp
流程:
拷貝形參Mat數據到臨時變量,用于稍后的操作
處理邊界選項不為BORDER_CONSTANT時的情況
若ksize長寬都為1,將源圖拷貝給目標圖
若之前有過HAVE_TEGRA_OPTIMIZATION優化選項的定義,則執行宏體中的tegra優化版函數并返回
如果HAVE_IPP&& (IPP_VERSION_MAJOR >= 7為真,則執行宏體中語句
調動濾波引擎,正式進行高斯濾波操作
? ? ? ?//載入原圖
? ? ? ?Matimage=imread("2.jpg");
? ? ? ?//進行均值濾波操作
? ? ? ?Matout;
? ? ? ?boxFilter(image, out, -1,Size(5, 5));
2 blur函數——均值濾波
調用代碼示范:
? ? ? ?//載入原圖
? ? ? ?Matimage=imread("1.jpg");
? ? ? ?//進行均值濾波操作
? ? ? ?Matout;
? ? ? ?blur(image, out, Size(7, 7));
3 GaussianBlur函數——高斯濾波
調用示例:
//載入原圖
? ? ? ?Matimage=imread("1.jpg");
? ? ? ?//進行濾波操作
? ? ? ?Matout;
? ? ? ?blur(image, out, Size(5, 5));
線性濾波下的模糊度。
主要代碼如下;
......
//全局變量聲明
Matg_srcImage,g_dstImage1,g_dstImage2,g_dstImage3;//存儲圖片的Mat類型
int g_nBoxFilterValue=3; ?//方框濾波參數值
int g_nMeanBlurValue=3; ?//均值濾波參數值
int g_nGaussianBlurValue=3; ?//高斯濾波參數值
......
//全局函數聲明
//四個軌跡條的回調函數
static void on_BoxFilter(int, void *); ? ? //均值濾波
static void on_MeanBlur(int, void *); ? ?//均值濾波
static void on_GaussianBlur(int, void *); ? ? ?//高斯濾波
?
//改變console字體顏色
system("color5E");?
//載入原圖
g_srcImage= imread( "1.jpg", 1 );
if(!g_srcImage.data ) { printf("Oh,no,讀取srcImage錯誤~!\n"); return false; }
?
//克隆原圖到三個Mat類型中
g_dstImage1= g_srcImage.clone( );
g_dstImage2= g_srcImage.clone( );
g_dstImage3= g_srcImage.clone( );
?
//顯示原圖
namedWindow("<0>原圖窗口", 1);
imshow("<0>原圖窗口",g_srcImage);
?
//方框濾波
namedWindow("<1>方框濾波", 1);
//創建軌跡條
createTrackbar("內核值:", "<1>方框濾波",&g_nBoxFilterValue, 40,on_BoxFilter );
on_MeanBlur(g_nBoxFilterValue,0);
imshow("<1>方框濾波", g_dstImage1);
//均值濾波
namedWindow("<2>均值濾波", 1);
createTrackbar("內核值:", "<2>均值濾波",&g_nMeanBlurValue, 40,on_MeanBlur );
on_MeanBlur(g_nMeanBlurValue,0);
//高斯濾波
namedWindow("<3>高斯濾波", 1);
createTrackbar("內核值:", "<3>高斯濾波",&g_nGaussianBlurValue, 40,on_GaussianBlur );
//方框濾波操作的回調函數
static void on_BoxFilter(int, void *)
{
? //方框濾波操作
? boxFilter(g_srcImage, g_dstImage1, -1,Size( g_nBoxFilterValue+1, g_nBoxFilterValue+1));
? //顯示窗口
? imshow("<1>方框濾波", g_dstImage1);
}
?
//均值濾波操作的回調函數
static void on_MeanBlur(int, void *)
{
? //均值濾波操作
? blur(g_srcImage, g_dstImage2, Size( g_nMeanBlurValue+1, g_nMeanBlurValue+1),Point(-1,-1));
? //顯示窗口
? imshow("<2>均值濾波", g_dstImage2);
}
??
//高斯濾波操作的回調函數
static void on_GaussianBlur(int, void *)
{
? //高斯濾波操作
? GaussianBlur(g_srcImage, g_dstImage3, Size(?
g_nGaussianBlurValue*2+1,g_nGaussianBlurValue*2+1 ), 0, 0);
? //顯示窗口
? imshow("<3>高斯濾波", g_dstImage3);
}
一 圖像平滑
圖像平滑與圖像模糊是同一概念,主要用于圖像的去噪。平滑要使用濾波器,為不改變圖像的相位信息,一般使用線性濾波器。不同的核函數代表不同的濾波器,有不同的用途。
常見的濾波器包括:歸一化濾波器,也是均值濾波器,用輸出像素點核窗口內的像素均值代替輸出點像素值。
高斯濾波器,實際中最常用的濾波器,高斯濾波是將輸入數組的每一個像素點與 高斯內核 卷積將卷積和當作輸出像素值。
中值濾波器,中值濾波將圖像的每個像素用鄰域(以當前像素為中心的正方形區域)像素的中值代替。對椒鹽噪聲最有效,去除跳變點非常有效。
雙邊濾波器,為避免濾波器平滑圖像去噪的同時使邊緣也模糊,這種情況下使用雙邊濾波器。
四種濾波方法分別使用到4個OpenCV函數,這些函數的前2個參數都是原圖像和濾波后圖像。
歸一化濾波器blur的第3個參數為濾波核窗口的大小,Size(i,i)表示ixi大小的窗口。
高斯濾波器GaussianBlur第3個參數也是濾波核窗口的大小,第4、第5個參數分辨表示x方向和y方向的δ。
中值濾波器medianBlur第3個參數是濾波器的長度,該濾波器的窗口為正方形。
雙邊濾波器的函數原型如下:
//! smooths the image using bilateral filter
CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?double sigmaColor, double sigmaSpace,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int borderType=BORDER_DEFAULT );
二 圖像代數運算 - 平均值去噪,減去背景
代數運算,就是對兩幅圖像的點之間進行加、減、乘、除的運算。代數運算中比較常用的是圖像相加和相減。圖像相加常用來求平均值去除addtive噪聲或者實現二次曝光。
圖像相減用于減去背景或周期噪聲,污染等。
圖像相加
OpenCV中提供了相加的函數
void cvAcc( ??
? ? ? ? ? ?const CvArr* image,//輸入圖像 ?
? ? ? ? ? ?CvArr* sum, ?//累積圖像 ??
? ? ? ? ? ?const CvArr* mask=NULL//可選的運算 ?
?); ?
還需要用到一個線性變換轉換函數來對相加的結果求平均
void cvConvertScale( ??
? ? ? ? const CvArr* src, //輸入數組 ?
? ? ? ? CvArr* dst,//輸出數組 ?
? ? ? ? double scale=1,//比例 ?
? ? ? ? double shift=0 //縮放比例,可選 ?
); ?
曝光和去噪是一樣的,也是對幾幅圖像求平均。
圖像相減
OpenCV中用cvAbsDiff函數計算兩數組的差的絕對值
void cvAbsDiff( ??
? ? ? ? const CvArr* src1,//第一個輸入數組 ?
? ? ? ? const CvArr* src2,//第二個輸入數組 ?
? ? ? ? CvArr* dst//輸出數組 ?
); ?
減去背景是通過兩幅圖像代數相減,可以判斷出前景區域和運動區域,這是最簡單(很多時候也是效果很好的)運動檢測方法。
三?線性濾波 - 方框濾波、均值濾波與高斯濾波
一、理論
1.平滑處理“平滑處理“(smoothing)也稱“模糊處理”(bluring)。平滑處理的用途,最常見的是用來減少圖像上的噪點或者失真。在涉及到降低圖像分辨率時,平滑處理是非常好用的方法。
2.濾波與濾波器
濾波是將信號中特定波段頻率濾除的操作,是抑制和防止干擾的一項重要措施。
而濾波器就是建立的一個數學模型,通過這個模型來將圖像數據進行能量轉化,能量低的就排除掉,噪聲就是屬于低能量部分。
一種形象的比喻法是:我們可以把濾波器想象成一個包含加權系數的窗口,當使用這個濾波器平滑處理圖像時,就把這個窗口放到圖像之上,透過這個窗口來看我們得到的圖像。
在新版本的OpenCV中,提供了如下五種常用的圖像平滑處理操作方法,且他們分別被封裝在單獨的函數中,
方框濾波——boxblur函數
均值濾波——blur函數
高斯濾波——GaussianBlur函數
中值濾波——medianBlur函數
雙邊濾波——bilateralFilter函數
3.線性濾波器
線性濾波器:線性濾波器經常用于剔除輸入信號中不想要的頻率或者從許多頻率中選擇一個想要的頻率。
幾種常見的線性濾波器:
允許低頻率通過的 低通濾波器 。
允許高頻率通過的 高通濾波器 。
允許一定范圍頻率通過的 帶通濾波器 。
阻止一定范圍頻率通過并且允許其它頻率通過的 帶阻濾波器 。
允許所有頻率通過、僅僅改變相位關系的 全通濾波器 。
阻止一個狹窄頻率范圍通過的特殊 帶阻濾波器 , 陷波濾波器 (Band-stop filter)。
4.關于濾波和模糊
濾波是將信號中特定波段頻率濾除的操作。
高斯濾波是指用高斯函數作為濾波函數的濾波操作 ,至于是不是模糊,要看是高斯低通還是高斯高通,低通就是模糊,高通就是銳化。
5.線性濾波
線性濾波是一種常用的鄰域算子,像素的輸出值取決于輸入像素的加權和。
6.方框濾波(box Filter)
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
,一般不去管它。
均值濾波是方框濾波歸一化(normalized)后的特殊情況。其中,歸一化就是把要處
理的量都縮放到一個范圍內,比如(0,1),以便統一處理和直觀量化。
而非歸一化(Unnormalized)的方框濾波用于計算每個像素鄰域內的積分特性,比如密集光流算法
(dense optical flow algorithms)中用到的圖像倒數的協方差矩陣(covariance matrices of image?
derivatives)
如果我們要在可變的窗口中計算像素總和,可以使用integral()函數。
7.均值濾波
均值濾波,是最簡單的一種濾波操作,輸出圖像的每一個像素是核窗口內輸入圖像對應像素的像素的平均
值( 所有像素加權系數相等),其實說白了它就是歸一化后的方框濾波。
均值濾波是典型的線性濾波算法,主要方法為鄰域平均法,即用一片圖像區域的各個像素的均值來代替原
圖像中的各個像素值。一般需要在圖像上對目標像素給出一個模板(內核),該模板包括了其周圍的臨近
像素(比如以目標像素為中心的周圍8(3x3-1)個像素,構成一個濾波模板,即去掉目標像素本身)。再
用模板中的全體像素的平均值來代替原來像素值。即對待處理的當前像素點(x,y),選擇一個模板,該
模板由其近鄰的若干像素組成,求模板中所有像素的均值,再把該均值賦予當前像素點(x,y),作為處
理后圖像在該點上的灰度個g(x,y),即個g(x,y)=1/m ∑f(x,y) ,其中m為該模板中包含當前像
素在內的像素總個數。
均值濾波的缺陷
它不能很好地保護圖像細節,在圖像去噪的同時也破壞了圖像的細節部分,從而使圖像變得模糊,不能很好地去除噪聲點。
blur 函數的原型:
void blur(InputArray src, OutputArraydst, Size ksize, Point anchor=Point(-1,-1), int?
borderType=BORDER_DEFAULT )
第一個參數,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.高斯濾波
高斯濾波是一種線性平滑濾波,適用于消除高斯噪聲,廣泛應用于圖像處理的減噪過程。高斯濾波就是對
整幅圖像進行加權平均的過程,每一個像素點的值,都由其本身和鄰域內的其他像素值經過加
權平均后得到。高斯濾波的具體操作是:用一個模板(或稱卷積、掩模)掃描圖像中的每一個像素,用模
板確定的鄰域內像素的加權平均灰度值去替代模板中心像素點的值。
高斯模糊技術生成的圖像,其視覺效果就像是經過一個半透明屏幕在觀察圖像,這與鏡頭焦外成像效果散
景以及普通照明陰影中的效果都明顯不同。高斯平滑也用于計算機視覺算法中的預先處理階段,以增強圖
像在不同比例大小下的圖像效果(參見尺度空間表示以及尺度空間實現)。從數學的角度來看,圖像的高
斯模糊過程就是圖像與正態分布做卷積。由于正態分布又叫作高斯分布,所以這項技術就叫作高斯模糊。
圖像與圓形方框模糊做卷積將會生成更加精確的焦外成像效果。由于高斯函數的傅立葉變換是另外一個高
斯函數,所以高斯模糊對于圖像來說就是一個低通濾波操作。
? 高斯濾波器是一類根據高斯函數的形狀來選擇權值的線性平滑濾波器。高斯平滑濾波器對于抑制服從正
態分布的噪聲非常有效。
對于圖像處理來說,常用二維零均值離散高斯函數作平滑濾波器。
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中線性濾波函數——boxFilter,blur和GaussianBlur函數以及涉及到的源碼的流程。1 OpenCV中boxFilter函數
OpenCV的安裝路徑的\sources\modules\imgproc\src下的smooth.cpp源文件boxFilter()函數
代碼作用:進行box Filter濾波操作的函數
OpenCV源代碼版本:2.4.8
源碼路徑:…\opencv\sources\modules\imgproc\src\smooth.cpp
流程
拷貝源圖的形參Mat數據到臨時變量,用于稍后的操作
定義int型臨時變量,代表源圖深度的sdepth,源圖通道的引用cn
處理ddepth小于零的情況
初始化目標圖
拷貝目標圖的形參Mat數據到臨時變量,用于稍后的操作
處理 borderType不為 BORDER_CONSTANT 且normalize為真的情況
若之前有過HAVE_TEGRA_OPTIMIZATION優化選項的定義,則執行宏體中的tegra優化版函數并返回
調用FilterEngine濾波引擎,正式開始濾波操作
其中的Ptr是用來動態分配的對象的智能指針模板類。可以發現,函數的內部代碼思路是很清晰的,先拷貝源圖的形參Mat數據到臨時變量,定義一些臨時變量,在處理ddepth小于零的情況,接著處理?
borderType不為 BORDER_CONSTANT 且normalize為真的情況,最終調用FilterEngine濾波引擎創建一個
BoxFilter,正式開始濾波操作。
這里的FilterEngine是OpenCV圖像濾波功能的核心引擎。
2 FilterEngine 類 - OpenCV圖像濾波核心引擎
各種濾波函數比如blur, GaussianBlur,到頭來其實是就是在函數末尾處定義了一個Ptr<FilterEngine>類型的f,然后f->apply( src, dst )了一下而已。這個類可以把幾乎是所有的濾波操作施加到圖像上。它包含了所有必要的中間緩存器。有很多和濾波相關
的create系函數的返回值直接就是Ptr<FilterEngine>。
其中的Ptr是用來動態分配的對象的智能指針模板類,而上面的尖括號里面的模板參數就是FilterEngine。
使用FilterEngine類可以分塊處理大量的圖像,構建復雜的管線,其中就包含一些進行濾波階段。如果我
們需要使用預先定義好的的濾波操作,cv::filter2D(), cv::erode(),以及cv::dilate(),可以選擇,他
們不依賴于FilterEngine,在自己函數體內部就實現了FilterEngine提供的功能。不像其他的諸如blur系列函數,依賴于FilterEngine引擎。
FilterEngine類源代碼流程
代碼作用:FilterEngine類,OpenCV圖像濾波功能的核心引擎
OpenCV源代碼版本:2.4.8
源碼路徑:…\opencv\sources\modules\imgproc\include\opencv2\imgproc\imgproc.hpp
?
默認構造函數
完整的構造函數
默認析構函數
重新初始化引擎。釋放之前濾波器申請的內存。
開始對指定了ROI區域和尺寸的圖片進行濾波操作
開始對指定了ROI區域的圖片進行濾波操作
處理圖像的下一個srcCount行(函數的第三個參數)
對圖像指定的ROI區域進行濾波操作,若srcRoi=(0,0,-1,-1),則對整個圖像進行濾波操作
如果濾波器可分離,則返回true
返回輸入和輸出行數
一些成員參數定義
3 OpenCV中size類型剖析
……\opencv\sources\modules\core\include\opencv2\core\core.hpp路徑下原型聲明
typedef Size_<int> Size2i;
typedef Size2i Size;
Size_ 是個模板類,在這里Size_<int>表示其類體內部的模板所代表的類型為int。
首先給已知的數據類型Size_<int>起個新名字,叫Size2i。
然后又給已知的數據類型Size2i起個新名字,叫Size。
連起來就是,Size_<int>、Size2i、Size這三個類型名等價。
Size_模板類的定義:
OpenCV源代碼版本:2.4.8
源碼路徑:…\opencv\sources\modules\core\include\opencv2\core\core.hpp
不同的構造函數定義
區域(width*height)
轉化另一種數據類型。
轉換為舊式的OpenCV類型.
寬度和高度,常用屬性
可以看到Size_模板類的內部又是重載了一些構造函數以滿足我們的需要,其中,我們用得最多的是如下
這個構造函數:
Size_(_Tp _width, _Tp _height);
另外,代碼末尾定義了模板類型的寬度和高度:
_Tp width, height; //寬度和高度
于是我們可以用XXX. width和XXX.height來分別表示其寬度和高度。
一個示例,方便理解:
Size(5, 5);//構造出的Size寬度和高度都為5,即XXX.width和XXX.height都為5
4 OpenCV中blur函數源碼剖析
blur
代碼作用:進行blur均值濾波操作的函數
OpenCV源代碼版本:2.4.8
源碼路徑:…\opencv\sources\modules\imgproc\src\smooth.cpp
流程
調用boxFilter函數進行處理
可以看到在blur函數內部就是調用了一個boxFilter函數,且第六個參數為true,即上文所說的
normalize=true,即均值濾波是均一化后的方框濾波。
5 GaussianBlur函數源碼流程
代碼作用:封裝高斯濾波的GaussianBlur()函數
OpenCV源代碼版本:2.4.8
源碼路徑:…\opencv\sources\modules\imgproc\src\smooth.cpp
流程:
拷貝形參Mat數據到臨時變量,用于稍后的操作
處理邊界選項不為BORDER_CONSTANT時的情況
若ksize長寬都為1,將源圖拷貝給目標圖
若之前有過HAVE_TEGRA_OPTIMIZATION優化選項的定義,則執行宏體中的tegra優化版函數并返回
如果HAVE_IPP&& (IPP_VERSION_MAJOR >= 7為真,則執行宏體中語句
調動濾波引擎,正式進行高斯濾波操作
三、線性濾波函數調用示例
1 boxFilter函數——方框濾波
調用代碼示范:? ? ? ?//載入原圖
? ? ? ?Matimage=imread("2.jpg");
? ? ? ?//進行均值濾波操作
? ? ? ?Matout;
? ? ? ?boxFilter(image, out, -1,Size(5, 5));
2 blur函數——均值濾波
調用代碼示范:
? ? ? ?//載入原圖
? ? ? ?Matimage=imread("1.jpg");
? ? ? ?//進行均值濾波操作
? ? ? ?Matout;
? ? ? ?blur(image, out, Size(7, 7));
3 GaussianBlur函數——高斯濾波
調用示例:
//載入原圖
? ? ? ?Matimage=imread("1.jpg");
? ? ? ?//進行濾波操作
? ? ? ?Matout;
? ? ? ?blur(image, out, Size(5, 5));
四、圖像線性濾波綜合示例
示例程序中用軌跡條來控制三種線性濾波的核參數值,通過滑動滾動條,控制圖像在三種線性濾波下的模糊度。
主要代碼如下;
......
//全局變量聲明
Matg_srcImage,g_dstImage1,g_dstImage2,g_dstImage3;//存儲圖片的Mat類型
int g_nBoxFilterValue=3; ?//方框濾波參數值
int g_nMeanBlurValue=3; ?//均值濾波參數值
int g_nGaussianBlurValue=3; ?//高斯濾波參數值
......
//全局函數聲明
//四個軌跡條的回調函數
static void on_BoxFilter(int, void *); ? ? //均值濾波
static void on_MeanBlur(int, void *); ? ?//均值濾波
static void on_GaussianBlur(int, void *); ? ? ?//高斯濾波
?
//改變console字體顏色
system("color5E");?
//載入原圖
g_srcImage= imread( "1.jpg", 1 );
if(!g_srcImage.data ) { printf("Oh,no,讀取srcImage錯誤~!\n"); return false; }
?
//克隆原圖到三個Mat類型中
g_dstImage1= g_srcImage.clone( );
g_dstImage2= g_srcImage.clone( );
g_dstImage3= g_srcImage.clone( );
?
//顯示原圖
namedWindow("<0>原圖窗口", 1);
imshow("<0>原圖窗口",g_srcImage);
?
//方框濾波
namedWindow("<1>方框濾波", 1);
//創建軌跡條
createTrackbar("內核值:", "<1>方框濾波",&g_nBoxFilterValue, 40,on_BoxFilter );
on_MeanBlur(g_nBoxFilterValue,0);
imshow("<1>方框濾波", g_dstImage1);
//均值濾波
namedWindow("<2>均值濾波", 1);
createTrackbar("內核值:", "<2>均值濾波",&g_nMeanBlurValue, 40,on_MeanBlur );
on_MeanBlur(g_nMeanBlurValue,0);
//高斯濾波
namedWindow("<3>高斯濾波", 1);
createTrackbar("內核值:", "<3>高斯濾波",&g_nGaussianBlurValue, 40,on_GaussianBlur );
on_GaussianBlur(g_nGaussianBlurValue,0);
//方框濾波操作的回調函數
static void on_BoxFilter(int, void *)
{
? //方框濾波操作
? boxFilter(g_srcImage, g_dstImage1, -1,Size( g_nBoxFilterValue+1, g_nBoxFilterValue+1));
? //顯示窗口
? imshow("<1>方框濾波", g_dstImage1);
}
?
//均值濾波操作的回調函數
static void on_MeanBlur(int, void *)
{
? //均值濾波操作
? blur(g_srcImage, g_dstImage2, Size( g_nMeanBlurValue+1, g_nMeanBlurValue+1),Point(-1,-1));
? //顯示窗口
? imshow("<2>均值濾波", g_dstImage2);
}
??
//高斯濾波操作的回調函數
static void on_GaussianBlur(int, void *)
{
? //高斯濾波操作
? GaussianBlur(g_srcImage, g_dstImage3, Size(?
g_nGaussianBlurValue*2+1,g_nGaussianBlurValue*2+1 ), 0, 0);
? //顯示窗口
? imshow("<3>高斯濾波", g_dstImage3);
}
總結
以上是生活随笔為你收集整理的opencv 图像去噪要点总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: opencv入门 - 显示图像学习总结
- 下一篇: Java设计模式理论知识要点总结