1. 程式人生 > >影象處理(三)——高斯濾波

影象處理(三)——高斯濾波

一、高斯濾波

高斯濾波是一種線性平滑濾波,適用於消除高斯噪聲,廣泛應用於影象處理的減噪過程。通俗的講,高斯濾波就是對整幅影象進行加權平均的過程,每一個畫素點的值,都由其本身和鄰域內的其他畫素值經過加權平均後得到。

實現影象的高斯濾波:

  • 通過調整高斯函式的標準差(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);
}