高斯函数
高斯滤波器是也一种线性滤波器,能够有效的抑制噪声,平滑图像。其作用原理和均值滤波器类似,都是取滤波器窗口内的像素的均值作为输出。其窗口模板的系数和均值滤波器不同,均值滤波器的模板系数都是相同的为1;而高斯滤波器根据高斯分布来确定各模板得系数,所以高斯滤波器相比于均值滤波器对图像个模糊程度较小。
二维高斯函数如下:
G
(
x
,
y
)
=
1
2
π
σ
2
e
−
x
2
+
y
2
2
σ
2
G(x,y)=\frac{1}{2\pi\sigma^2}e^-\frac{x^2+y^2}{2\sigma^2}
G(x,y)=2πσ21e−2σ2x2+y2
其中(x,y)为点坐标,在图像中为整数,σ是标准差。标准差代表着数据的离散程度,如下图所示,σ越大,高斯函数越平滑,数据的离散程序越大。对于图像滤波来说,如果σ较小,那么生成的模板的中心系数较大,而周围的系数较小,这样对图像的平滑效果就不是很明显;反之,σ较大,则生成的模板的各个系数相差就不是很大,比较类似均值模板,对图像的平滑效果比较明显。σ值的确定依赖于问题背景,需要具体问题具体分析。


从上图可以看出:
(1)在核大小固定的情况下,sigma值越大,权值分布越平缓。因此,邻域各个点的值对输出值的影响越大,最终结果造成图像越模糊。
(2)在核大小固定的情况下,sigma值越小,权值分布越突起。因此,邻域各个点的值对输出值的影响越小,图像变化也越小。假如中心点权值为1,其他点权值为0,那么最终结果是图像没有任何变化。
(3)sigma固定时,核越大图像越模糊。
(4)sigma固定时,核越小图像变化越小。
相比于图像的简单平滑,高斯滤波效率要低一些,在离散型噪声的消除方面,高斯滤波的效果并不理想。然而如果要对图像的总体特征进行提取和增强时,高斯滤波相对就具有很大的优势。下图对比了图像的简单滤波和高斯滤波的处理差异,图(a)表示了一个5×5邻域内的像素灰度分布情况,从图中可以看出此邻域内有两处灰度较高的亮度。图(b)对图(a)进行3×3邻域线性滤波的结果,从图(b)中可以看出,原图像中的两处亮点被连接在了一起,失去了原图像的特征,图(c)为对图(a)进行3×3邻域高斯滤波的结果,可以发现图(c)中依然保留着原图像的特征。

高斯模板
标准差σ确定后,就可以确定模板的大小。高斯函数是钟形曲线,距离中心越远数值越小,足够远处可以忽略不计。在区间(μ−σ,μ+σ)范围内的面积占曲线下总面积的68%,(μ−2σ,μ+2σ)范围占95%,(μ−3σ,μ+3σ)范围占99.7%,一般3σ外的数值已接近于0,可以忽略。半径为3σ即窗口大小为6σ×6σ即可,通常取最近的奇数。

要想得到一个高斯滤波器的模板,可以对高斯函数进行离散化,得到的高斯函数值作为模板的系数。对于模板的大小为 (2k+1)×(2k+1),模板中各个元素值的计算公式如下:
H
(
i
,
i
)
=
1
2
π
σ
2
e
−
i
2
+
i
2
2
σ
2
H(i,i)=\frac{1}{2\pi\sigma^2}e^-\frac{i^2+i^2}{2\sigma^2}
H(i,i)=2πσ21e−2σ2i2+i2
这样计算出来的模板有两种形式:小数和整数。
小数形式的模板,就是直接计算得到的值,然后进行归一化处理;
整数形式的,则需要进行归一化处理,将模板左上角的值归一化为1,下面会具体介绍。使用整数的模板时,需要在模板的前面加一个系数。
例如,大小为3×3,σ=0.8的模板系数计算过程如下:

可以严格证明,一个2-D的高斯卷积可分解为顺序执行的两个1-D高斯卷积,即一个2-D高斯平均模板可拆分成两个1-D高斯平均模板。例如:
1
16
[
1
2
1
2
4
2
1
2
1
]
=
1
4
[
1
2
1
]
1
4
[
1
2
1
]
\frac{1}{16}\left[ \begin{matrix}1 & 2 & 1 \\2 & 4 & 2 \\ 1&2&1\end{matrix} \right]=\frac{1}{4}\left[ \begin{matrix}1 \\ 2\\ 1 \end{matrix}\right]\frac{1}{4}\left[\begin{matrix}1&2&1\end{matrix}\right]
161⎣⎡121242121⎦⎤=41⎣⎡121⎦⎤41[121]
对n×n的模板,这样的分解可将一个计算量为O(n^2)的操作用两个计算量为O(n)的操作来代替。为了得到1-D的离散模板,可对高斯函数在整数位置-n,…0,…+n采样。具体可取n=2σ+1(σ高斯方差),而模板尺寸是S=2n+1。例如,对σ=1,模板尺寸最多为7就够了;σ=2,则模板尺寸至少为11。
GaussianBlur
Opencv中使用GaussinBlur函数进行高斯滤波,函数声明如下:
void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY, int borderType)
src:输入图像,可以包含任意的通道数,每个通道都是单独处理。图像深度必须是CV_8U, CV_16U, CV_16S, CV_32F或者CV_64F。
dst:输出图像,大小和类型与输入图像相同
ksize: 高斯核大小。ksize.width和ksize.height可以不同,但它们都必须是正数和奇数。如果是零,则从给定的sigma计算得到。计算的公式为:
ksize.width = cvRound(sigma1*(depth == CV_8U ? 3 : 4)*2 + 1)|1;
ksize.height = cvRound(sigma2*(depth == CV_8U ? 3 : 4)*2 + 1)|1;
sigmaX: X方向的高斯核标准偏差。
sigmaY: Y方向的高斯核标准偏差。如果sigmaY为零,则将其设置为与sigmaX相同。如果两个sigma均为零,则分别从ksize.width和ksize.height计算。计算的公式为:
s
i
g
m
a
=
0.3
∗
(
(
k
s
i
z
e
−
1
)
∗
0.5
−
1
)
+
0.8
sigma = 0.3*((ksize-1)*0.5 - 1) + 0.8
sigma=0.3∗((ksize−1)∗0.5−1)+0.8
borderType:边界像素处理方式。
使用GaussianBlur函数的示例代码如下:
int main()
{
Mat srcImage = imread("lena512.bmp", IMREAD_GRAYSCALE);
Mat dstImage;
GaussianBlur(srcImage, dstImage, Size(5, 5), 1.0, 1.0);
namedWindow("源图像");
imshow("源图像", srcImage);
namedWindow("结果");
imshow("结果", dstImage);
waitKey(0);
return 0;
}
myGaussianBlur函数
void myapply(Mat& src, Mat& dst, Mat& kernelX, Mat& kernelY)
{
int chns = src.channels();
int a = (kernelX.rows - 1) / 2;
int b = (kernelY.rows - 1) / 2;
dst.create(src.rows, src.cols, src.type());
//分通道处理
vector<Mat> srcchns;
vector<Mat> dstchns;
split(src, srcchns);
split(dst, dstchns);
double* px = kernelX.ptr<double>();
for(int ch = 0; ch < chns; ch++)
{
//x方向一维高斯模糊
Mat mat(src.rows, src.cols, CV_64F);
for(int i = 0; i < src.rows; i++)
{
for(int j = a; j < src.cols - a; j++)
{
double t = 0.0;
for(int k = 0; k < kernelX.rows; k++)
{
t += srcchns[ch].at<uchar>(i, j - a + k) * px[k];
}
mat.at<double>(i, j) = t;
}
//左边界
for(int j = 0; j < a; j++)
{
double t = 0.0;
for(int k = 0; k < kernelX.rows; k++)
{
t += srcchns[ch].at<uchar>(i, abs(a - k - j)) * px[k];
}
mat.at<double>(i, j) = t;
}
//右边界
for(int j = src.cols - a; j < src.cols; j++)
{
double t = 0.0;
for(int k = 0; k < kernelX.rows; k++)
{
t += srcchns[ch].at<uchar>(i, j - abs(a - k)) * px[k];
}
mat.at<double>(i, j) = t;
}
}
//y方向一维高斯模糊
double* py = kernelY.ptr<double>();
for(int i = 0; i < srcchns[ch].cols; i++)
{
for(int j = b; j < srcchns[ch].rows - b; j++)
{
double t = 0.0;
for(int k = 0; k < kernelY.rows; k++)
{
t += mat.at<double>(j - b + k, i) * py[k];
}
dstchns[ch].at<uchar>(j, i) = saturate_cast<uchar>(t);
}
//上边界
for(int i = 0; i < srcchns[ch].cols; i++)
{
for(int j = 0; j < b; j++)
{
double t = 0.0;
for(int k = 0; k < kernelY.rows; k++)
{
t += mat.at<double>(abs(b - k - j), i) * py[k];
}
dstchns[ch].at<uchar>(j, i) = saturate_cast<uchar>(t);
}
}
//下边界
for(int i = 0; i < srcchns[ch].cols; i++)
{
for(int j = srcchns[ch].rows - b; j < srcchns[ch].rows; j++)
{
double t = 0.0;
for(int k = 0; k < kernelY.rows; k++)
{
t += mat.at<double>(j - abs(b - k), i) * py[k];
}
dstchns[ch].at<uchar>(j, i) = saturate_cast<uchar>(t);
}
}
}
}
merge (dstchns, dst);
}
cv::Mat mygetGaussianKernel( int n, double sigma )
{
Mat kernel(n, 1, CV_64F, Scalar::all(0));
double* cd = kernel.ptr<double>();
double sigmaX = sigma > 0 ? sigma : ((n - 1) * 0.5 - 1) * 0.3 + 0.8;
double scale2X = -0.5 / (sigmaX * sigmaX);
double sum = 0.0;
for(int i = 0; i < n; i++)
{
double x = i - (n - 1) * 0.5;
double t = exp(scale2X * x * x);
cd[i] = t;
sum += cd[i];
}
sum = 1.0 / sum;
for(int i = 0; i < n; i++ )
{
cd[i] *= sum;
}
return kernel;
}
void myGaussianBlur(Mat& src, Mat& dst, Size ksize, double sigmaX, double sigmaY)
{
Size size = src.size();
if(size.height == 1)
ksize.height = 1;
if(size.width == 1)
ksize.width = 1;
if(ksize.width == 1 && ksize.height == 1)
{
src.copyTo(dst);
return;
}
if(sigmaY <= 0)
sigmaY = sigmaX;
if( ksize.width <= 0 && sigmaX > 0 )
ksize.width = cvRound(sigmaX * 6 + 1) | 1;
if( ksize.height <= 0 && sigmaY > 0 )
ksize.height = cvRound(sigmaY * 6 + 1) | 1;
CV_Assert( ksize.width > 0 && ksize.width % 2 == 1 &&
ksize.height > 0 && ksize.height % 2 == 1 );
sigmaX = std::max( sigmaX, 0.0 );
sigmaY = std::max( sigmaY, 0.0 );
Mat kx, ky;
kx = mygetGaussianKernel( ksize.width, sigmaX);
if( ksize.height == ksize.width && std::abs(sigmaX - sigmaY) < DBL_EPSILON )
ky = kx;
else
ky = mygetGaussianKernel( ksize.height, sigmaY);
myapply (src, dst, kx, ky);
}
本文介绍了高斯滤波在图像处理中的应用,包括高斯函数、高斯模板及其与均值滤波的区别。高斯滤波器通过高斯分布确定模板系数,σ值影响滤波效果。当σ增大时,图像变得更加模糊。OpenCV中的GaussianBlur函数用于实现高斯滤波,详细阐述了其参数和使用方法。
高斯滤波&spm=1001.2101.3001.5002&articleId=113618703&d=1&t=3&u=f7c303a58b204fa1be77cea7a1ea9412)
6万+

被折叠的 条评论
为什么被折叠?



