影象處理(三)——高斯濾波
阿新 • • 發佈:2018-11-11
一、高斯濾波
高斯濾波是一種線性平滑濾波,適用於消除高斯噪聲,廣泛應用於影象處理的減噪過程。通俗的講,高斯濾波就是對整幅影象進行加權平均的過程,每一個畫素點的值,都由其本身和鄰域內的其他畫素值經過加權平均後得到。
實現影象的高斯濾波:
- 通過調整高斯函式的標準差(sigma)來控制平滑程度;
- 濾波視窗大小取為[6*sigma-1],[.]表示取整;
- 利用二維高斯函式的行列可分離性進行加速;
先對每行進行一維高斯濾波,再對結果的每列進行同樣的一維高斯濾波;
實現過程:
使用高斯濾波器來進行影象的濾波操作,高斯濾波=以高斯函式為卷積核的影象卷積,高斯濾波器的函式及影象如下:
但是我們不能直接使用高斯濾波器進行濾波,而是要利用二維高斯函式的行列可分離性進行加速,通過調整高斯函式的標準差(sigma)來控制平滑程度,實現不同濾波程度的目的。
分別對行和列做卷積運算:
先對每一行進行一維高斯濾波,再對每一列進行一維高斯濾波。
不過需要注意的是,在進行高斯濾波之前,要進行邊界擴充套件:
此外,我還添加了滑動條選項,來讓使用者自己選擇平滑度(sigma值),最終結果如下:
高斯濾波和均值濾波應該是影象處理中使用的較為頻繁的濾波器,而且兩種濾波器雖然相似卻又不太一樣,高斯濾波器是一種線性濾波器,能夠有效的抑制噪聲,平滑影象。其作用原理和均值濾波器類似,都是取濾波器視窗內的畫素的均值作為輸出。其視窗模板的係數和均值濾波器不同,均值濾波器的模板係數都是相同的為1;而高斯濾波器的模板係數,則隨著距離模板中心的增大而係數減小。所以,高斯濾波器相比於均值濾波器對影象的模糊程度較小。
程式碼自取:
// CVE4.cpp: 定義控制檯應用程式的入口點。 // #include "stdafx.h" #include<opencv2/opencv.hpp> #include<iostream> #include<math.h> #include<cxcore.h> #include<cmath> #include<cv.h> #include<highgui.h> using namespace std; using namespace cv; void listPixel_Operate(int, void*); void Gaussian(const Mat &input, Mat &output, double sigma) { int row = input.rows, col = input.cols; int window = (int)((6 * sigma - 1) / 2) * 2 + 1;//濾波視窗 double *temp = new double[window]; //擴充邊界 Mat INPUT; copyMakeBorder(input, INPUT, window / 2, window / 2, window / 2, window / 2, BORDER_REFLECT_101); double sum = 0; for (int w = 0; w < window; w++) { int mid = w - window / 2; temp[w] = exp(-(mid*mid) / (2 * sigma*sigma)); sum += temp[w]; } //歸一化濾波核,和為1 for (int w = 0; w < window; w++) { temp[w] = temp[w] / sum; } //擴充邊界之後的長寬 int rows = row + window - 1; int cols = col + window - 1; //先對每行進行一維高斯濾波 for (int y = window / 2; y < row + window / 2; y++)//行 { for (int x = window / 2; x < col + window / 2; x++) //列 { int num = 0; double pix[3] = { 0 }; for (int k = x - window / 2; k < x + window / 2; k++) { for (int c = 0; c < INPUT.channels(); c++) { pix[c] += (INPUT.at<Vec3b>(y, k)[c])*temp[num]; //列座標<矩陣列數 } num++; } for (int c = 0; c < INPUT.channels(); c++) { INPUT.at<Vec3b>(y, x)[c] = pix[c]; } } } //再對每列進行一維高斯濾波 for (int x = window / 2; x < col + window / 2; x++) //列 { for (int y = window / 2; y < row + window / 2; y++) //行 { int num = 0; double pix[3] = { 0 }; for (int k = y - window / 2; k < y + window / 2; k++) { for (int c = 0; c < INPUT.channels(); c++) { pix[c] += (INPUT.at<Vec3b>(k, x)[c])*temp[num]; } num++; } for (int c = 0; c < INPUT.channels(); c++) { INPUT.at<Vec3b>(y, x)[c] = pix[c]; } } } for (int y = 0; y < row; y++) { for (int x = 0; x < col; x++) { output.at<Vec3b>(y, x) = INPUT.at<Vec3b>(y + window / 2, x + window / 2); } } } int sig; Mat image; int main() { //cout << "請輸入sigma的值:" << endl; //cin >> sig; sig = 1; image = imread("../res/img.jpg"); namedWindow("【效果圖視窗】", 1); //建立滑動條 createTrackbar("sigma", "【效果圖視窗】", &sig, 10, listPixel_Operate); //呼叫回撥函式 listPixel_Operate(sig, 0); //system("pause"); waitKey(0); return 0; } void listPixel_Operate(int, void*) { Mat dst = Mat::zeros(image.rows, image.cols, image.type()); imshow("原圖視窗", image); Gaussian(image, dst, sig); imshow("【效果圖視窗】", dst); }