1 圖像平滑
圖像平滑,可用來對圖像進行去噪 (noise reduction) 或 模糊化處理 (blurring),實際上圖像平滑仍然屬於圖像空間濾波的一種 (低通濾波)
既然是濾波,則圖像中任一點 (x, y),經過平滑濾波後的輸出 g(x, y) 如下:
g(x,y)=∑ s=−a a ∑ t=−b b w(s,t)f(x+s,y+t) g(x,y)=∑s=−aa∑t=−bbw(s,t)f(x+s,y+t)
以 3X3 的濾波器為例 (即 a=b=1),則矩陣 Mx 和 Mf 對應的元素乘積之和,就是 g(x, y)
其中,M x =⎡ ⎣ ⎢ w(−1,−1)w(0,−1)w(1,−1) w(−1,0)w(0,0)w(1,0) w(−1,1)w(1,1)w(1,1) ⎤ ⎦ ⎥ M f =⎡ ⎣ ⎢ f(x−1,y−1)f(x,y−1)f(x+1,y−1) f(x−1,y)f(x,y)f(x+1,y) f(x−1,y+1)f(x+1,y+1)f(x+1,y+1) ⎤ ⎦ ⎥ Mx=[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)]Mf=[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)]
2 OpenCV 函數
OpenCV 中主要有四個函數涉及到圖像平滑,分別是盒式濾波 (box),高斯濾波 (Gaussian),中值濾波 (median),雙邊濾波 (bilateral)
2.1 盒式濾波
輸出圖像的任一像素灰度值,等於其所有鄰域像素灰度值的平均值
模糊化核為,K=α⎡ ⎣ ⎢ ⎢ ⎢ 111 111 ............ 111 111 ⎤ ⎦ ⎥ ⎥ ⎥ K=α[11...1111...11...11...11] 其中,α={1ksize.weidth∗ksize.height 1 when normalize = trueotherwise α={1ksize.weidth∗ksize.heightwhen normalize = true1otherwise
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 // 邊界模式
)
取 ddepth = 1,normalize = true,則可以得到模糊化函數 (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 中值濾波
中值濾波最為簡單,常用來消除椒鹽噪聲
輸出圖像中 (x, y) 點處的像素值,等於輸入圖像以 (x, y) 為中心點的鄰域像素 (ksize x ksize) 平均值
void cv::medianBlur (
InputArray src,
OutputArray dst,
int ksize // 濾波器孔徑大小,一般為奇數且大於 1,比如 3, 5, 7, ...
)
2.3 高斯濾波
高斯濾波最為有用,它是根據當前像素和鄰域像素之間,空間距離的不同,計算得出一個高斯核 (鄰域像素的加權系數),
然後,高斯核從左至右、從上到下遍歷輸入圖像,與輸入圖像的像素值求卷積和,得到輸出圖像的各個像素值
G 0 (x,y)=Ae −(x−μ x ) 2 2σ 2 x +−(y−μ y ) 2 2σ 2 y G0(x,y)=Ae−(x−μx)22σx2+−(y−μy)22σy2
無須理會公式的復雜,只需要記住一點即可:鄰域像素距離當前像素越遠 (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 }
View Code
3.2 濾波對比
實際中,可直接調用以上四個濾波函數,代碼如下:
1 #include "opencv2/imgproc/imgproc.hpp"
2 #include "opencv2/highgui/highgui.hpp"
3
4 using namespace std;
5 using namespace cv;
6
7 int main()
8 {
9 Mat src = imread("E:/smooth/bird.jpg");
10 if(src.empty()) return -1;
11
12 namedWindow("original", CV_WINDOW_AUTOSIZE);
13 namedWindow("blur", CV_WINDOW_AUTOSIZE);
14 namedWindow("GaussianBlur", CV_WINDOW_AUTOSIZE);
15 namedWindow("medianBlur", CV_WINDOW_AUTOSIZE);
16 namedWindow("bilateralFilter", CV_WINDOW_AUTOSIZE);
17
18 imshow("original", src);
19
20 Mat dst;
21
22 blur(src, dst, Size(3,3));
23 imshow("blur", dst);
24
25 medianBlur(src,dst,3);
26 imshow("medianBlur",dst);
27
28 GaussianBlur(src,dst,Size(3,3),0);
29 imshow("GaussianBlur",dst);
30
31 bilateralFilter(src,dst,9,50,50);
32 imshow("bilateralFilter",dst);
33
34 waitKey(0);
35 return 0;
36 }
四種濾波方法的效果圖,如下所示:
參考資料
<Digital Image Processing_3rd> chapter 3
<Learning OpenCV_2nd>
<OpenCV Tutorials> imgproc module - Smoothing Images
OpenCV官方教程中文版(For Python) PDF http://www.linuxidc.com/Linux/2015-08/121400.htm
Ubuntu Linux下安裝OpenCV2.4.1所需包 http://www.linuxidc.com/Linux/2012-08/68184.htm
Ubuntu 12.04 安裝 OpenCV2.4.2 http://www.linuxidc.com/Linux/2012-09/70158.htm
CentOS下OpenCV無法讀取視頻文件 http://www.linuxidc.com/Linux/2011-07/39295.htm
Ubuntu 12.04下安裝OpenCV 2.4.5總結 http://www.linuxidc.com/Linux/2013-06/86704.htm
Ubuntu 10.04中安裝OpenCv2.1九步曲 http://www.linuxidc.com/Linux/2010-09/28678.htm
基於QT和OpenCV的人臉識別系統 http://www.linuxidc.com/Linux/2011-11/47806.htm
[翻譯]Ubuntu 14.04, 13.10 下安裝 OpenCV 2.4.9 http://www.linuxidc.com/Linux/2014-12/110045.htm
OpenCV的詳細介紹:請點這裡
OpenCV的下載地址:請點這裡