1 圖像平滑
圖像平滑,一種圖像空間濾波方法 (低通濾波),可對圖像進行去噪 或 模糊化 (blurring)
以 3X3 的濾波器為例 (即 a=b=1),則矩陣 Mx 和 Mf 對應的元素乘積之和,就是 g(x, y)
其中,$ M_x = \begin{bmatrix} w(-1,-1) & w(-1,0) & w(-1,1) \\ w(0,-1) & w(0,0) & w(1,1) \\ w(1,-1) & w(1,0) & w(1,1) \\ \end{bmatrix} \qquad M_f = \begin{bmatrix} f(x-1,y-1) & f(x-1,y) & f(x-1,y+1) \\ f(x,y-1) & f(x,y) & f(x+1,y+1) \\ f(x+1,y-1) & f(x+1,y) & f(x+1,y+1) \\ \end{bmatrix}$
2 OpenCV 函數
OpenCV 中主要有四個函數,分別是盒式濾波 (box),高斯濾波 (Gaussian),中值濾波 (median),雙邊濾波 (bilateral)
2.1 盒式濾波
2.1.1 boxFilter
輸出圖像的任一像素灰度值,等於其所有鄰域像素灰度值的平均值
模糊化核為,$ K = \alpha \begin{bmatrix} 1 & 1 & ... & 1 & 1 \\ 1 & 1 & ... & 1 & 1 \\ \: & \: & ... & & & \\ 1 & 1 & ... & 1 & 1 \end{bmatrix} $ 其中,$\alpha = \begin{cases} \frac{1}{ksize.width * ksize.height} & \text{when normalize = true} \\ 1 & \text{otherwise} \\ \end{cases} $
void cv::boxFilter ( InputArray src, // 輸入圖像 OutputArray dst, // 輸出圖像 int ddepth, // 輸出圖像深度,-1 表示等於 src.depth() Size ksize, // 模糊化核 (kernel) 的大小 Point anchor = Point(-1,-1), // 錨點位置,缺省值表示 anchor 位於模糊核的正中心 bool normalize = true, // 是否歸一化處理 int borderType = BORDER_DEFAULT // 邊界模式 )
2.1.2 blur
取 ddepth = -1,normalize = true,則可由 boxFilter 得到模糊化函數 (blur)
boxFilter( src, dst, -1, ksize, anchor, true, borderType );
blur 本質上是一個輸入和輸出圖像深度 (ddepth) 相同,並且做歸一化處理的盒式濾波器
void cv::blur ( InputArray src, OutputArray dst,
Size ksize, Point anchor = Point(-1,-1), int borderType = BORDER_DEFAULT )
2.2 中值濾波
中值濾波最為簡單,常用來消除椒鹽噪聲。輸出圖像 g (x, y) 的像素值,等於以輸入圖像 f (x, y) 為中心點的鄰域像素 (ksize x ksize) 平均值
void cv::medianBlur ( InputArray src, OutputArray dst, int ksize // 濾波器孔徑大小,一般為奇數且大於 1,比如 3, 5, 7, ... )
2.3 高斯濾波
高斯濾波最為有用,它是根據當前像素和鄰域像素之間,空間距離的不同,計算得出一個高斯核 (鄰域像素的加權系數),
然后,高斯核從左至右、從上到下遍歷輸入圖像,與輸入圖像的像素值求卷積和,得到輸出圖像的各個像素值
$\quad G_{0}(x, y) = A e^{ \dfrac{ -(x - \mu_{x})^{2} }{ 2\sigma^{2}_{x} } + \dfrac{ -(y - \mu_{y})^{2} }{ 2\sigma^{2}_{y} } } $
無須理會公式的復雜,只需要記住一點即可:鄰域像素距離當前像素越遠 (saptial space),則其相應的加權系數越小
為了便於直觀理解,可看下面這個一維高斯核,推而廣之將 G(x) 曲線以 x=0 這條軸為中心線,旋轉360度可想象其二維高斯核
void cv::GaussianBlur ( InputArray src, OutputArray dst, Size ksize, // 高斯核的大小 double sigmaX, // 高斯核在x方向的標准差 double sigmaY = 0, // 高斯核在y方向的標准差,缺省為 0,表示 sigmaY = sigmaX int borderType = BORDER_DEFAULT )
注意: 高斯核的大小 Size(width, height),w 和 h 二者不必相同但必須都是奇數,若都設為 0,則從 sigma 自動計算得出
2.4 雙邊濾波
上面三種方法都是低通濾波,因此在消除噪聲的同時,也常會將邊緣信息模糊化。雙邊濾波和高斯濾波類似,但是它將鄰域像素的加權系數分為兩部分,
第一部分與高斯濾波的完全相同,第二部分則考慮當前像素和鄰域像素之間灰度值的差異,從而在消除噪聲的基礎上,也較好的保留了圖像的邊緣信息
void cv::bilateralFilter ( InputArray src, OutputArray dst, int d, // 像素鄰域直徑,若為非正值,則從 sigmaSpace 自動計算得出 double sigmaColor, // 顏色空間的標注方差 double sigmaSpace, // 坐標空間的標准方差 int borderType = BORDER_DEFAULT )
注意 1) 雙邊濾波相比以上三種濾波方法,其處理速度很慢,因此,一般建議取 d=5 用於實時圖像處理,d=9 適合於非實時的圖像領域
注意 2) sigmaColor 和 sigmaSpace 可取相同值,一般在 10 ~ 150 之間,小於 10,則沒什么效果,大於 150,則效果太強烈,看起來明顯“卡通化”
3 代碼示例
3.1 OpenCV
OpenCV 中的示例,通過逐漸增大像素鄰域的大小 Size(w, h),將上述濾波過程動態化,非常形象的展示了鄰域大小對濾波效果的影響
代碼摘抄:

1 /** 2 * file Smoothing.cpp 3 * brief Sample code for simple filters 4 * author OpenCV team 5 */ 6 #include <iostream> 7 #include <vector> 8 9 #include "opencv2/imgproc/imgproc.hpp" 10 #include "opencv2/imgcodecs.hpp" 11 #include "opencv2/highgui/highgui.hpp" 12 #include "opencv2/features2d/features2d.hpp" 13 14 using namespace std; 15 using namespace cv; 16 17 /// Global Variables 18 int DELAY_CAPTION = 1500; 19 int DELAY_BLUR = 100; 20 int MAX_KERNEL_LENGTH = 31; 21 22 Mat src; Mat dst; 23 char window_name[] = "Smoothing Demo"; 24 25 /// Function headers 26 int display_caption( const char* caption ); 27 int display_dst( int delay ); 28 29 30 /** 31 * function main 32 */ 33 int main( void ) 34 { 35 namedWindow( window_name, WINDOW_AUTOSIZE ); 36 37 /// Load the source image 38 src = imread( "../data/lena.jpg", 1 ); 39 40 if( display_caption( "Original Image" ) != 0 ) { return 0; } 41 42 dst = src.clone(); 43 if( display_dst( DELAY_CAPTION ) != 0 ) { return 0; } 44 45 46 /// Applying Homogeneous blur 47 if( display_caption( "Homogeneous Blur" ) != 0 ) { return 0; } 48 49 for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) 50 { blur( src, dst, Size( i, i ), Point(-1,-1) ); 51 if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } 52 53 54 /// Applying Gaussian blur 55 if( display_caption( "Gaussian Blur" ) != 0 ) { return 0; } 56 57 for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) 58 { GaussianBlur( src, dst, Size( i, i ), 0, 0 ); 59 if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } 60 61 62 /// Applying Median blur 63 if( display_caption( "Median Blur" ) != 0 ) { return 0; } 64 65 for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) 66 { medianBlur ( src, dst, i ); 67 if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } 68 69 70 /// Applying Bilateral Filter 71 if( display_caption( "Bilateral Blur" ) != 0 ) { return 0; } 72 73 for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) 74 { bilateralFilter ( src, dst, i, i*2, i/2 ); 75 if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } 76 77 /// Wait until user press a key 78 display_caption( "End: Press a key!" ); 79 80 waitKey(0); 81 82 return 0; 83 } 84 85 /** 86 * @function display_caption 87 */ 88 int display_caption( const char* caption ) 89 { 90 dst = Mat::zeros( src.size(), src.type() ); 91 putText( dst, caption, 92 Point( src.cols/4, src.rows/2), 93 FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) ); 94 95 imshow( window_name, dst ); 96 int c = waitKey( DELAY_CAPTION ); 97 if( c >= 0 ) { return -1; } 98 return 0; 99 } 100 101 /** 102 * @function display_dst 103 */ 104 int display_dst( int delay ) 105 { 106 imshow( window_name, dst ); 107 int c = waitKey ( delay ); 108 if( c >= 0 ) { return -1; } 109 return 0; 110 }
3.2 濾波對比
實際中,可直接調用以上四個濾波函數,代碼如下:
1 #include "opencv2/imgproc/imgproc.hpp" 2 #include "opencv2/highgui/highgui.hpp" 3 4 using namespace cv; 5 6 int main() 7 { 8 Mat src = imread("E:/smooth/bird.jpg"); 9 if(src.empty()) { 10 return -1; 11 } 12 imshow("original", src); 13 14 Mat dst; 15 16 blur(src, dst, Size(3,3)); 17 imshow("blur", dst); 18 19 medianBlur(src,dst,3); 20 imshow("medianBlur",dst); 21 22 GaussianBlur(src,dst,Size(3,3),0); 23 imshow("GaussianBlur",dst); 24 25 bilateralFilter(src,dst,9,50,50); 26 imshow("bilateralFilter",dst); 27 28 waitKey(0); 29 }
四種濾波方法的效果圖,如下所示:
參考資料
<Digital Image Processing> 3rd, chapter 3
<Learning OpenCV3>
OpenCV Tutorials \ Image Processing (imgproc module) \ Smoothing Images
圖像卷積與濾波的一些知識點,zouxy09