根據數學知識,一維高斯函數能夠描述爲:
在圖像處理中,選定X方向上長度爲3的窗口,令δ=1,中心座標爲1,由上述公式,其卷積核(Xa,X,Xb)能夠以下計算:ios
Xa = exp(-1*(0-1)(0-1)/(2*1*1))= 0.606530659712633 X = exp(-1*(1-1)(1-1)/(2*1*1))= 1 Xb = exp(-1*(2-1)(2-1)/(2*1*1))= 0.606530659712633
能夠看到計算過程沒有用到常數部分,是由於須要歸一化,常數部分能夠省略:算法
Sum = Xa + X + Xb = 2.2130613194252668 Xa = Xa/Sum = 0.274068619061197 X = X/Sum = 0.451862761877606 Xb = Xb/Sum = 0.274068619061197
經過OpenCV驗證下上述結果是否正確,OpenCV能夠經過函數getGaussianKernel()來實現計算高斯核,運行以下代碼,能夠發現二者的計算結果是一致的。函數
Mat kernelX = getGaussianKernel(3, 1); cout << kernelX << endl;
上述的推導過程都是一維的,那麼二維狀況下的卷積核怎麼計算呢,其實很簡單,轉置並相乘就能夠了:學習
Mat kernelX = getGaussianKernel(3, 1); cout << kernelX << endl; Mat kernelY = getGaussianKernel(3, 1); Mat G = kernelX * kernelY.t(); cout << G << endl << endl << endl;
運行結果:
在獲得卷積核以後,將其放到圖像中進行二維卷積,對於原圖像中的一個像素P(x,y),有以下卷積過程:
將窗口覆蓋的對應位置的像素值相乘後相加,便可獲得新圖像對應位置的像素值Q(x,y)。當對圖像全部的像素值都這樣作時,就能夠獲得濾波後的圖像。因爲通常狀況下老是順序去卷積的,從左至右,由上而下,因此這個過程就是卷積核的滑動。spa
當滑動到邊界的時候,就會產生一個問題,就是卷積覈對應的位置沒有像素值。這時能夠將邊界像素值捨棄(卷積),或者自動填充爲0(濾波)。.net
在OpenCV中,能夠直接使用GaussianBlur()函數實現高斯濾波,可是爲了驗證和學習高斯濾波算法,也能夠本身構建高斯卷積核,使用濾波函數filter2D()進行濾波。其具體實現以下:code
#include <iostream> #include <opencv2\opencv.hpp> using namespace cv; using namespace std; int main() { //從文件中讀取成灰度圖像 const char* imagename = "C:\\Data\\imgDemo\\lena.jpg"; Mat img = imread(imagename, IMREAD_GRAYSCALE); if (img.empty()) { fprintf(stderr, "Can not load image %s\n", imagename); return -1; } //直接高斯濾波 Mat dst1; GaussianBlur(img, dst1, Size(3, 3), 1, 1); //自定義高斯濾波器 Mat kernelX = getGaussianKernel(3, 1); Mat kernelY = getGaussianKernel(3, 1); Mat G = kernelX * kernelY.t(); Mat dst2; filter2D(img, dst2, -1, G); //比較二者的結果 Mat c; compare(dst1, dst2, c, CMP_EQ); // imshow("原始", img); imshow("高斯濾波1", dst1); imshow("高斯濾波2", dst2); imshow("比較結果", c); waitKey(); return 0; }
能夠看到這裏分別用GaussianBlur()和filter2D()進行了高斯濾波,並經過compare()函數進行比較。運行結果以下所示,二者的濾波結果基本一致,說明構建的卷積核是正確的。
htm
1.OpenCV實現二維高斯核GaussianKernel
2.opencv3.2.0圖像處理之高斯濾波GaussianBlur API函數
3.OpenCV高斯濾波器詳解及代碼實現blog