图像处理(三)——高斯滤波

版权声明: https://blog.csdn.net/Godsolve/article/details/83627066

一、高斯滤波

高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。

实现图像的高斯滤波:

  • 通过调整高斯函数的标准差(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);
}


猜你喜欢

转载自blog.csdn.net/Godsolve/article/details/83627066