0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

高斯滤波器的原理及其实现过程

新机器视觉 来源:新机器视觉 作者:新机器视觉 2021-03-20 10:41 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

本文主要介绍了高斯滤波器的原理及其实现过程 高斯滤波器是一种线性滤波器,能够有效的抑制噪声,平滑图像。其作用原理和均值滤波器类似,都是取滤波器窗口内的像素的均值作为输出。其窗口模板的系数和均值滤波器不同,均值滤波器的模板系数都是相同的为1;而高斯滤波器的模板系数,则随着距离模板中心的增大而系数减小。所以,高斯滤波器相比于均值滤波器对图像个模糊程度较小。 什么是高斯滤波器 既然名称为高斯滤波器,那么其和高斯分布(正态分布)是有一定的关系的。一个二维的高斯函数如下:

cddf0d76-88ef-11eb-8b86-12bb97331649.png

其中(x,y)(x,y)为点坐标,在图像处理中可认为是整数;σσ是标准差。要想得到一个高斯滤波器的模板,可以对高斯函数进行离散化,得到的高斯函数值作为模板的系数。例如:要产生一个3×33×3的高斯滤波器模板,以模板的中心位置为坐标原点进行取样。模板在各个位置的坐标,如下所示(x轴水平向右,y轴竖直向下)

这样,将各个位置的坐标带入到高斯函数中,得到的值就是模板的系数。 对于窗口模板的大小为(2k+1)×(2k+1),模板中各个元素值的计算公式如下:

ce5ab9ee-88ef-11eb-8b86-12bb97331649.png

这样计算出来的模板有两种形式:小数和整数。

小数形式的模板,就是直接计算得到的值,没有经过任何的处理;

整数形式的,则需要进行归一化处理,将模板左上角的值归一化为1,下面会具体介绍。使用整数的模板时,需要在模板的前面加一个系数,系数为也就是模板系数和的倒数。

高斯模板的生成 知道模板生成的原理,实现起来也就不困难了

void generateGaussianTemplate(double window[][11], int ksize, double sigma){ static const double pi = 3.1415926; int center = ksize / 2; // 模板的中心位置,也就是坐标的原点 double x2, y2; for (int i = 0; i < ksize; i++) { x2 = pow(i - center, 2); for (int j = 0; j < ksize; j++) { y2 = pow(j - center, 2); double g = exp(-(x2 + y2) / (2 * sigma * sigma)); g /= 2 * pi * sigma; window[i][j] = g; } } double k = 1 / window[0][0]; // 将左上角的系数归一化为1 for (int i = 0; i < ksize; i++) { for (int j = 0; j < ksize; j++) { window[i][j] *= k; } }}   需要一个二维数组,存放生成的系数(这里假设模板的最大尺寸不会超过11);第二个参数是模板的大小(不要超过11);第三个参数就比较重要了,是高斯分布的标准差。 生成的过程,首先根据模板的大小,找到模板的中心位置ksize/2。然后就是遍历,根据高斯分布的函数,计算模板中每个系数的值。   需要注意的是,最后归一化的过程,使用模板左上角的系数的倒数作为归一化的系数(左上角的系数值被归一化为1),模板中的每个系数都乘以该值(左上角系数的倒数),然后将得到的值取整,就得到了整数型的高斯滤波器模板。   下面截图生成的是,大小为3×3,σ=0.83×3,σ=0.8的模板  

对上述解结果取整后得到如下模板: ced64668-88ef-11eb-8b86-12bb97331649.png   这个模板就比较熟悉了,其就是根据σ=0.8的高斯函数生成的模板。   至于小数形式的生成也比较简单,去掉归一化的过程,并且在求解过程后,模板的每个系数要除以所有系数的和。具体代码如下:

void generateGaussianTemplate(double window[][11], int ksize, double sigma){ static const double pi = 3.1415926; int center = ksize / 2; // 模板的中心位置,也就是坐标的原点 double x2, y2; double sum = 0; for (int i = 0; i < ksize; i++) { x2 = pow(i - center, 2); for (int j = 0; j < ksize; j++) { y2 = pow(j - center, 2); double g = exp(-(x2 + y2) / (2 * sigma * sigma)); g /= 2 * pi * sigma; sum += g; window[i][j] = g; } } //double k = 1 / window[0][0]; // 将左上角的系数归一化为1 for (int i = 0; i < ksize; i++) { for (int j = 0; j < ksize; j++) { window[i][j] /= sum; } }}   3×3,σ=0.8的小数型模板。

σσ值的意义及选取 通过上述的实现过程,不难发现,高斯滤波器模板的生成最重要的参数就是高斯分布的标准差σσ。标准差代表着数据的离散程度,如果σσ较小,那么生成的模板的中心系数较大,而周围的系数较小,这样对图像的平滑效果就不是很明显;反之,σσ较大,则生成的模板的各个系数相差就不是很大,比较类似均值模板,对图像的平滑效果比较明显。 来看下一维高斯分布的概率分布密度图:

横轴表示可能得取值x,竖轴表示概率分布密度F(x),那么不难理解这样一个曲线与x轴围成的图形面积为1。σσ(标准差)决定了这个图形的宽度,可以得出这样的结论:σσ越大,则图形越宽,尖峰越小,图形较为平缓;σσ越小,则图形越窄,越集中,中间部分也就越尖,图形变化比较剧烈。这其实很好理解,如果sigma也就是标准差越大,则表示该密度分布一定比较分散,由于面积为1,于是尖峰部分减小,宽度越宽(分布越分散);同理,当σσ越小时,说明密度分布较为集中,于是尖峰越尖,宽度越窄! 于是可以得到如下结论: σσ越大,分布越分散,各部分比重差别不大,于是生成的模板各元素值差别不大,类似于平均模板; σσ越小,分布越集中,中间部分所占比重远远高于其他部分,反映到高斯模板上就是中心元素值远远大于其他元素值,于是自然而然就相当于中间值得点运算。 基于OpenCV的实现 在生成高斯模板好,其简单的实现和其他的空间滤波器没有区别,具体代码如下:

void GaussianFilter(const Mat &src, Mat &dst, int ksize, double sigma){ CV_Assert(src.channels() || src.channels() == 3); // 只处理单通道或者三通道图像 const static double pi = 3.1415926; // 根据窗口大小和sigma生成高斯滤波器模板 // 申请一个二维数组,存放生成的高斯模板矩阵 double **templateMatrix = new double*[ksize]; for (int i = 0; i < ksize; i++) templateMatrix[i] = new double[ksize]; int origin = ksize / 2; // 以模板的中心为原点 double x2, y2; double sum = 0; for (int i = 0; i < ksize; i++) { x2 = pow(i - origin, 2); for (int j = 0; j < ksize; j++) { y2 = pow(j - origin, 2); // 高斯函数前的常数可以不用计算,会在归一化的过程中给消去 double g = exp(-(x2 + y2) / (2 * sigma * sigma)); sum += g; templateMatrix[i][j] = g; } } for (int i = 0; i < ksize; i++) { for (int j = 0; j < ksize; j++) { templateMatrix[i][j] /= sum; cout << templateMatrix[i][j] << " "; } cout << endl; } // 将模板应用到图像中 int border = ksize / 2; copyMakeBorder(src, dst, border, border, border, border, BorderTypes::BORDER_REFLECT); int channels = dst.channels(); int rows = dst.rows - border; int cols = dst.cols - border; for (int i = border; i < rows; i++) { for (int j = border; j < cols; j++) { double sum[3] = { 0 }; for (int a = -border; a <= border; a++) { for (int b = -border; b <= border; b++) { if (channels == 1) { sum[0] += templateMatrix[border + a][border + b] * dst.at(i + a, j + b); } else if (channels == 3) { Vec3b rgb = dst.at(i + a, j + b); auto k = templateMatrix[border + a][border + b]; sum[0] += k * rgb[0]; sum[1] += k * rgb[1]; sum[2] += k * rgb[2]; } } } for (int k = 0; k < channels; k++) { if (sum[k] < 0) sum[k] = 0; else if (sum[k] > 255) sum[k] = 255; } if (channels == 1) dst.at(i, j) = static_cast(sum[0]); else if (channels == 3) { Vec3b rgb = { static_cast(sum[0]), static_cast(sum[1]), static_cast(sum[2]) }; dst.at(i, j) = rgb; } } } // 释放模板数组 for (int i = 0; i < ksize; i++) delete[] templateMatrix[i]; delete[] templateMatrix;}   只处理单通道或者三通道图像,模板生成后,其滤波(卷积过程)就比较简单了。不过,这样的高斯滤波过程,其循环运算次数为m×n×ksize2,其中m,n为图像的尺寸;ksize为高斯滤波器的尺寸。这样其时间复杂度为O(ksize2),随滤波器的模板的尺寸呈平方增长,当高斯滤波器的尺寸较大时,其运算效率是极低的。为了,提高滤波的运算速度,可以将二维的高斯滤波过程分解开来。  分离实现高斯滤波  由于高斯函数的可分离性,尺寸较大的高斯滤波器可以分成两步进行:首先将图像在水平(竖直)方向与一维高斯函数进行卷积;然后将卷积后的结果在竖直(水平)方向使用相同的一维高斯函数得到的模板进行卷积运算。具体实现代码如下:

// 分离的计算void separateGaussianFilter(const Mat &src, Mat &dst, int ksize, double sigma){ CV_Assert(src.channels()==1 || src.channels() == 3); // 只处理单通道或者三通道图像 // 生成一维的高斯滤波模板 double *matrix = new double[ksize]; double sum = 0; int origin = ksize / 2; for (int i = 0; i < ksize; i++) { // 高斯函数前的常数可以不用计算,会在归一化的过程中给消去 double g = exp(-(i - origin) * (i - origin) / (2 * sigma * sigma)); sum += g; matrix[i] = g; } // 归一化 for (int i = 0; i < ksize; i++) matrix[i] /= sum; // 将模板应用到图像中 int border = ksize / 2; copyMakeBorder(src, dst, border, border, border, border, BorderTypes::BORDER_REFLECT); int channels = dst.channels(); int rows = dst.rows - border; int cols = dst.cols - border; // 水平方向 for (int i = border; i < rows; i++) { for (int j = border; j < cols; j++) { double sum[3] = { 0 }; for (int k = -border; k <= border; k++) { if (channels == 1) { sum[0] += matrix[border + k] * dst.at(i, j + k); // 行不变,列变化;先做水平方向的卷积 } else if (channels == 3) { Vec3b rgb = dst.at(i, j + k); sum[0] += matrix[border + k] * rgb[0]; sum[1] += matrix[border + k] * rgb[1]; sum[2] += matrix[border + k] * rgb[2]; } } for (int k = 0; k < channels; k++) { if (sum[k] < 0) sum[k] = 0; else if (sum[k] > 255) sum[k] = 255; } if (channels == 1) dst.at(i, j) = static_cast(sum[0]); else if (channels == 3) { Vec3b rgb = { static_cast(sum[0]), static_cast(sum[1]), static_cast(sum[2]) }; dst.at(i, j) = rgb; } } } // 竖直方向 for (int i = border; i < rows; i++) { for (int j = border; j < cols; j++) { double sum[3] = { 0 }; for (int k = -border; k <= border; k++) { if (channels == 1) { sum[0] += matrix[border + k] * dst.at(i + k, j); // 列不变,行变化;竖直方向的卷积 } else if (channels == 3) { Vec3b rgb = dst.at(i + k, j); sum[0] += matrix[border + k] * rgb[0]; sum[1] += matrix[border + k] * rgb[1]; sum[2] += matrix[border + k] * rgb[2]; } } for (int k = 0; k < channels; k++) { if (sum[k] < 0) sum[k] = 0; else if (sum[k] > 255) sum[k] = 255; } if (channels == 1) dst.at(i, j) = static_cast(sum[0]); else if (channels == 3) { Vec3b rgb = { static_cast(sum[0]), static_cast(sum[1]), static_cast(sum[2]) }; dst.at(i, j) = rgb; } } } delete[] matrix;} 代码没有重构较长,不过其实现原理是比较简单的。首先得到一维高斯函数的模板,在卷积(滤波)的过程中,保持行不变,列变化,在水平方向上做卷积运算;接着在上述得到的结果上,保持列不边,行变化,在竖直方向上做卷积运算。这样分解开来,算法的时间复杂度为O(ksize)O(ksize),运算量和滤波器的模板尺寸呈线性增长。 在OpenCV也有对高斯滤波器的封装GaussianBlur,其声明如下:

CV_EXPORTS_W void GaussianBlur( InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY = 0, int borderType = BORDER_DEFAULT ); 二维高斯函数的标准差在x和y方向上应该分别有一个标准差,在上面的代码中一直设其在x和y方向的标准是相等的,在OpenCV中的高斯滤波器中,可以在x和y方向上设置不同的标准差。 下图是自己实现的高斯滤波器和OpenCV中的GaussianBlur的结果对比

上图是5×5,σ=0.8的高斯滤波器,可以看出两个实现得到的结果没有很大的区别。 总结 高斯滤波器是一种线性平滑滤波器,其滤波器的模板是对二维高斯函数离散得到。由于高斯模板的中心值最大,四周逐渐减小,其滤波后的结果相对于均值滤波器来说更好。 高斯滤波器最重要的参数就是高斯分布的标准差σσ,标准差和高斯滤波器的平滑能力有很大的能力,σσ越大,高斯滤波器的频带就较宽,对图像的平滑程度就越好。通过调节σσ参数,可以平衡对图像的噪声的抑制和对图像的模糊。

责任编辑:lq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 滤波器
    +关注

    关注

    162

    文章

    8464

    浏览量

    186229
  • 模板
    +关注

    关注

    0

    文章

    111

    浏览量

    21122
  • 函数
    +关注

    关注

    3

    文章

    4421

    浏览量

    67822

原文标题:高斯滤波器的原理及其实现过程(附模板代码)

文章出处:【微信号:vision263com,微信公众号:新机器视觉】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    输入滤波器 vs 输出滤波器:核心差异解析

    变频输入和输出滤波器虽然只有一字之差,但它们的角色、电路设计,甚至电气特性都截然不同。简单来说,输入滤波器是为了让变频与电网“和谐相处”,而输出
    的头像 发表于 04-20 11:43 393次阅读
    输入<b class='flag-5'>滤波器</b> vs 输出<b class='flag-5'>滤波器</b>:核心差异解析

    屏蔽电源滤波器的分类

    屏蔽房用来屏蔽 辐射 干扰,而滤波器用来滤除 传导 干扰。没有滤波器,屏蔽房的整体隔离效果会下降60dB以上(相当于百万倍的效能损失),因此滤波器是屏蔽房发挥完整功能的核心部件。 来看下分类: 屏蔽
    的头像 发表于 04-16 10:53 139次阅读
    屏蔽电源<b class='flag-5'>滤波器</b>的分类

    交流单相滤波器与三相滤波器的核心区别解析

    选型和实现有效电能质量管理的基础。 一、结构设计与电路拓扑的根本差异 单相滤波器基于单相两线制系统设计,其电路结构相对简单。它通常由针对特定谐波频率设计的电感、电容等无源元件构成,形成一个独立的滤波支路。其核心任务
    的头像 发表于 02-04 15:53 367次阅读

    如何选择一个合适的高阶低通滤波器

    高阶低通滤波器是一种通过组合多个二阶滤波器级来实现滤波器,用于抑制高频信号并保留低频信号。从信号处理的角度来看,世界上所有的信号都可以被理解为是一个或者多个或者无穷个不同频率、不同相
    的头像 发表于 12-30 15:37 1367次阅读
    如何选择一个合适的高阶低通<b class='flag-5'>滤波器</b>

    通信系统中滤波器的种类及特点(1)

    完全相同。从实现角度来说,每个滤波器实现方式也均不相同,有的是通过电磁谐振原理来实现,有的是通过薄膜技术来实现,甚至有的是用户自己搭建RL
    的头像 发表于 12-29 09:17 6441次阅读
    通信系统中<b class='flag-5'>滤波器</b>的种类及特点(1)

    高频滤波器精密加工——如何“筛”出纯净信号?

    、体积更小。而这一切的实现,离不开精密加工技术对材料、结构与工艺的极致把控。 一、高频滤波器的核心挑战:精度与性能的双重博弈 高频滤波器的性能直接取决于其内部结构的加工精度。例如,腔体滤波器
    的头像 发表于 09-24 15:02 770次阅读

    如何实现有源电磁干扰滤波器的出色性能

    作为昂贵的传统大型无源滤波器的出色替代品,有源电磁干扰滤波器 (AEF) 可以帮助设计人员应对不断增加的 EMI 挑战、提高功率密度以及降低电源解决方案的成本。
    的头像 发表于 09-08 13:46 5001次阅读
    如何<b class='flag-5'>实现</b>有源电磁干扰<b class='flag-5'>滤波器</b>的出色性能

    STM32单片机片上数字滤波器操作文档 快速入门数字滤波器在单片机上的实现

    这个文档,是为了帮助大家快速入门数字滤波器在单片机上的实现
    的头像 发表于 06-23 16:53 1923次阅读
    STM32单片机片上数字<b class='flag-5'>滤波器</b>操作文档 快速入门数字<b class='flag-5'>滤波器</b>在单片机上的<b class='flag-5'>实现</b>

    什么是滤波器?维爱普详细介绍

    滤波器是一种用于筛选特定频率信号或能量的电子元件,通过允许某些频率通过、抑制其他频率,实现信号优化或能量净化。它在电子设备、通信系统、电力工程等领域广泛应用,是保障系统稳定运行的核心组件。 滤波器
    的头像 发表于 06-19 15:08 1141次阅读

    常用的数字滤波器算法及其特性

    常用的软件滤波器有限幅滤波法、中位值滤波法、算数平均滤波法、递推平均滤波法、中位值平均滤波法、限
    的头像 发表于 06-18 09:04 1384次阅读

    有源滤波器与无源滤波器的区别

    滤波器是根据电路参数对电路频带宽度的影响而设计出来的工程应用电路,滤波器种类很多,有源滤波器和无源滤波器的区别我们最简单的分别办法是看看是否需要电源,在作用上最大的区别在于有源
    的头像 发表于 06-18 09:03 2206次阅读

    GNSS 低噪声放大器前端模块,集成前滤波器和后滤波器 skyworksinc

    电子发烧友网为你提供()GNSS 低噪声放大器前端模块,集成前滤波器和后滤波器相关产品参数、数据手册,更有GNSS 低噪声放大器前端模块,集成前滤波器和后滤波器的引脚图、接线图、封装手
    发表于 06-06 18:34
    GNSS 低噪声放大器前端模块,集成前<b class='flag-5'>滤波器</b>和后<b class='flag-5'>滤波器</b> skyworksinc

    Sky5® 低电流 GNSS LNA 前端模块,集成前置滤波器和后置滤波器 skyworksinc

    电子发烧友网为你提供()Sky5® 低电流 GNSS LNA 前端模块,集成前置滤波器和后置滤波器相关产品参数、数据手册,更有Sky5® 低电流 GNSS LNA 前端模块,集成前置滤波器和后置
    发表于 05-14 18:31
    Sky5® 低电流 GNSS LNA 前端模块,集成前置<b class='flag-5'>滤波器</b>和后置<b class='flag-5'>滤波器</b> skyworksinc

    电源滤波器频率选择要点

    电源滤波器通过电感、电容等元件,实现信号的滤波功能,衰减干扰信号,保障设备正常运行。选择合适频率的滤波器至关重要。在电磁干扰环境评估下,滤波器
    的头像 发表于 05-05 17:26 986次阅读
    电源<b class='flag-5'>滤波器</b>频率选择要点