1. 程式人生 > >openCV之高斯濾波(及程式碼實現)

openCV之高斯濾波(及程式碼實現)

        高斯濾波是一種線性平滑濾波,適用於消除高斯噪聲,廣泛應用於影象處理的減噪過程。通俗的講,高斯濾波就是對整幅影象進行加權平均的過程,每一個畫素點的值,都由其本身和鄰域內的其他畫素值經過加權平均後得到。高斯濾波的具體操作是:用一個模板(或稱卷積、掩模)掃描影象中的每一個畫素,用模板確定的鄰域內畫素的加權平均灰度值去替代模板中心畫素點的值。

       高斯濾波(Gauss filter)實質上是一種訊號的濾波器,其用途為訊號的平滑處理,數字影象用於後期應用,其噪聲是最大的問題,因為誤差會累計傳遞等原因,大多影象處理教材會在很早的時候介紹Gauss濾波器,用於得到信噪比SNR較高的影象(反應真實訊號)。高斯平滑濾波器對於抑制服從正態分佈

的噪聲非常有效。

下面我們來看一下高斯函式:

這是一維的

這是二維的

一維函式圖

二維函式圖

          我們對影象進行處理時,我們需要取一塊區域(一般是3*3的畫素點圖)。以這個矩形的中心為原點,去任意的運sigma,用上面的二維高斯函式我們可以求出這個3*3區域每個點的權值(權值相加之和為1)

比如我們取sigma為1.5

我們執行一下程式碼求出3*3矩陣的權值陣列

	double arr[3][3];
	double sum = 0.0;
	double sigma = 1.5;
	for (int i = 0; i < 3; ++i)
		for (int j = 0; j < 3; ++j) 
			sum += arr[i][j] = exp(-((i - 1)*(i - 1) + (j - 1)*(j - 1)) / (2 * sigma*sigma));
	for (int i = 0; i < 3; ++i)
		for (int j = 0; j < 3; ++j)
			arr[i][j] /= sum;
	for (int i = 0; i < 3; ++i) {
		for (int j = 0; j < 3; ++j)
			cout << arr[i][j] << " ";
		cout << endl;
	}
這是執行結果

如果我們改變sigma為0.5:


可以看見當sigma為0.5時,越靠近中間的值越大,我們在進行高斯濾波處理時就可以選擇不同的sigma的值來對影象進行相應的操作。值越大影象越模糊。

下面我們進行影象操作示例:

首先編寫我們自己的高斯濾波器,然後匯入我們要進行處理的影象並椒鹽化,接著分別用openCV自帶的高斯濾波器以及我們自己編寫的高斯濾波器來看看有什麼不同。

double **getGuassionArray(int size,double sigma) {
	int i, j;
	double sum = 0.0;
	int center = size; //以第一個點的座標為原點,求出中心點的座標

	double **arr = new double*[size];//建立一個size*size大小的二維陣列
	for (i = 0; i < size; ++i)
		arr[i] = new double[size];
	
	for (i = 0; i < size; ++i)
		for (j = 0; j < size; ++j) {
			arr[i][j] = exp(-((i - center)*(i - center) + (j - center)*(j - center)) / (sigma*sigma * 2));
			sum += arr[i][j];
		}
	for (i = 0; i < size; ++i)
		for (j = 0; j < size; ++j)
			arr[i][j] /= sum;
	return arr;
}

void myGaussian(const Mat _src, Mat &_dst) {
	if (!_src.data) return;
	double **arr;
	Mat tmp(_src.size(), _src.type());
	for (int i = 0; i < _src.rows; ++i)
		for (int j = 0; j < _src.cols; ++j) {
			//邊緣不進行處理
			if ((i - 1) > 0 && (i + 1) < _src.rows && (j - 1) > 0 && (j + 1) < _src.cols) {
				arr = getGuassionArray(3, 1);//自定義得到的權值陣列
				tmp.at<Vec3b>(i, j)[0] = 0;
				tmp.at<Vec3b>(i, j)[1] = 0;
				tmp.at<Vec3b>(i, j)[2] = 0;
				for (int x = 0; x < 3; ++x) {
					for (int y = 0; y < 3; ++y) {
							tmp.at<Vec3b>(i, j)[0] += arr[x][y] * _src.at<Vec3b>(i + 1 - x, j + 1 - y)[0];
							tmp.at<Vec3b>(i, j)[1] += arr[x][y] * _src.at<Vec3b>(i + 1 - x, j + 1 - y)[1];
							tmp.at<Vec3b>(i, j)[2] += arr[x][y] * _src.at<Vec3b>(i + 1 - x, j + 1 - y)[2];
					}
				}
			}
		}
	tmp.copyTo(_dst);
}

void main() {
	Mat image = imread("路飛.jpg");
	Mat salt_image;
	image.copyTo(salt_image);

	Mat _gaussian;
	Mat image1;
	salt(salt_image, 1000);
	myGaussian(salt_image, _gaussian);
	GaussianBlur(salt_image, image1, Size(3, 3), 1);

	imshow("原圖", image);
	imshow("椒鹽化圖", salt_image);
	imshow("opencv自帶的高斯濾波", image1);
	imshow("自定義高斯濾波", _gaussian);
	waitKey();
}


可以看到openCV的高斯濾波器與自己編寫的處理效果是差不多的,即便我們在改變sigma值之後處理後圖像依然看不出有很大的差別,說明我們的編寫算是成功了。