gauss 函数

2023-10-31

高斯滤波(高斯平滑)是图像处理,计算机视觉里面最常见的操作。平时,我们都是用matlab或者opencv的函数调用:imfilter或者cvSmooth,并不关心底层的实现。然而当开发者要实做高斯滤波的时候,往往就会很迷惘,往往会被以下几个问题困扰:

  1. 给定sigma,即标准偏差,怎么确定离散化后滤波器的窗口大小?
  2. 给定窗口大小,怎么计算高斯核的sigma,即标准方差?
  3. 怎么实现可分离滤波器?

我在google上搜了一下,还真没几个人把实现的细节讲清楚了。这里,我尝试结合三份源码,做个小小的总结。

三份源码分别是:

  1. opencv 中的cvfilter.cpp
  2. autopano-sift-c 中的GaussianConvolution.c
  3. GIMP 中的blur-gauss.c和unsharp-mask.c

在图像处理中,高斯滤波一般有两种实现方式,一是用离散化窗口滑窗卷积,另一种通过傅里叶变换。最常见的就是第一种滑窗实现,只有当离散化的窗口非 常大,用滑窗计算量非常大(即使用可分离滤波器的实现)的情况下,可能会考虑基于傅里叶变化的实现方法。这里我们只讨论第一种方法。

二维高斯函数的形式是这样的:

f(x,y) = A e^{- /left(/frac{(x-x_o)^2}{2/sigma_x^2} + /frac{(y-y_o)^2}{2/sigma_y^2} /right)}.

有着如下的形状,形状很激凸,怎么会叫高斯平滑呢,分明是高斯激凸嘛:

基本上,离散化的主旨就是保留高斯函数中心能量最集中的中间部分,忽略四周能量很小的平坦区域。这只是个很感性的描述,具体实现起来,就会出现千奇百怪的版本。下面结合三份源码,看看现实世界里的高斯平滑到底长的什么样子。

首先是第一个问题:给定sigma,怎么计算窗口大小?

直接上opencv的源码,在cvFilter函数中:

param1 = cvRound(sigma1*(depth == CV_8U ? 3 : 4)*2 + 1)|1;

opencv认为半径为3*sigma的窗口就是高斯函数能量最集中的区域。(为什么在图像深度不是8U的时候,使用4*sigma半径的窗口就不得而知了,有高人指点一下?)

autopan0-sift-c是图像拼接软件hugin里面的sift实现,在实现DoG的时候需要做不同尺度的高斯平滑,实现如下,在GaussianConvolution_new1函数中:

dim = 1 + 2 * ((int) (3.0 * sigma));

可见autopano也是实现的3*sigma半径的窗口。

在GIMP里,实现比较奇特,在blur_gauss.c的make_rle_curve函数里面,

const gdouble sigma2 = 2 * sigma * sigma;
const gdouble l = sqrt (-sigma2 * log (1.0 / 255.0));
int n = ceil (l) * 2;
if ((n % 2) == 0)
n += 1;

我是没看懂那个 log (1.0 / 255.0)是干嘛的。。。惭愧。效果来看,这个实现的窗口半径是约等于2.2*sigma。

然后是第二个问题:给定窗口大小,怎么计算sigma?

opencv的实现,在cvFilter.cpp的init_gaussian_kernel函数中:

sigmaX = sigma > 0 ? sigma : (n/2 – 1)*0.3 + 0.8;

再次不可解。。。乘以0.3还可以接受,加上0.8是为嘛啊?

autopano没有实现这个特性。

GIMP的实现:

/* we want to generate a matrix that goes out a certain radius
* from the center, so we have to go out ceil(rad-0.5) pixels,
* inlcuding the center pixel. Of course, that’s only in one direction,
* so we have to go the same amount in the other direction, but not count
* the center pixel again. So we double the previous result and subtract
* one.
* The radius parameter that is passed to this function is used as
* the standard deviation, and the radius of effect is the
* standard deviation * 2. It’s a little confusing.
*/
radius = fabs (radius) + 1.0;

std_dev = radius;
radius = std_dev * 2;
/* go out ‘radius’ in each direction */
matrix_length = 2 * ceil (radius – 0.5) + 1;

注释讲的很清楚了,基本上就是认为sigma应该等于窗口半径的一半。

看完这三分源码,结论就是,关于sigma和半径,你爱怎么算就怎么算吧,差不多就行。。。(额。。费了半天劲,就得到这么一句废话啊)。

第三个问题是可分离滤波器:

由于高斯函数可以写成可分离的形式,因此可以采用可分离滤波器实现来加速。所谓的可分离滤波器,就是可以把多维的卷积化成多个一维卷积。具体到二维 的高斯滤波,就是指先对行做一维卷积,再对列做一维卷积。这样就可以将计算复杂度从O(M*M*N*N)降到O(2*M*M*N),M,N分别是图像和滤 波器的窗口大小。问题是实现时候怎么计算一维的卷积核呢?

其实很简单,按照前面计算出来的窗口大小,计算所有离散点上一维高斯函数的权值,最后别忘了将权值之和归一化到1.
有码有真相,来自opencv:

for( i = 0; i <= n/2; i++ )
{
double t = fixed_kernel ? (double)fixed_kernel[i] : exp(scale2X*i*i);
if( type == CV_32FC1 )
{
cf[(n/2+i)*step] = (float)t;
sum += cf[(n/2+i)*step]*2;
}
else
{
cd[(n/2+i)*step] = t;
sum += cd[(n/2+i)*step]*2;
}
}

sum = 1./sum;
for( i = 0; i <= n/2; i++ )
{
if( type == CV_32FC1 )
cf[(n/2+i)*step] = cf[(n/2-i)*step] = (float)(cf[(n/2+i)*step]*sum);
else
cd[(n/2+i)*step] = cd[(n/2-i)*step] = cd[(n/2+i)*step]*sum;
}

终于写完了,希望对各位有所帮助。不对之处请指正哈。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

gauss 函数 的相关文章

  • 四边形到矩形变换

    我想将四边形图像转换为我知道这些顶点的矩形图像 例如 在下图中 我知道坐标 X1 Y1 X4 Y4 和 x1 y1 x2 y2 并且我想将其转换为矩形 如何获得与四边形图像中的 X Y 坐标相对应的矩形图像中的 x y 坐标 gt Y gt
  • Golang HTTP Post 错误:连接被拒绝

    我正在尝试向正在运行 PHP 应用程序的端口 8080 上的本地主机发送 post 请求 卷曲效果很好 curl data key asdf http localhost 8080 但在 Go 中我收到以下错误 Post http loca
  • Golang 有 libfaketime 替代品吗?

    我想自动化一些测试 我必须操纵系统时间来检查用 golang 编写的程序的身份验证行为 根据这个帖子 https stackoverflow com questions 36024872 libfaketime doesnt work wi
  • 各向异性扩散二维图像[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我想在二维图像上使用各向异性扩散 我想使用 python 但不介意使用 matlab 或 c 他们有我
  • 为什么结构体的字段是“非名称”[重复]

    这个问题在这里已经有答案了 这段代码不起作用 它抱怨 j Bar 是一个 非名字 package main import fmt import os type foo struct Bar string Baz int func main
  • Matlab:从一定范围内不重复的随机整数

    我想获得一个包含在范围内且不重复的随机整数的数组 我使用了 randperm 15 3 输出是 8 10 12 这个函数不使用范围 我只想从 10 中随机取值 例如 如果您有统计工具箱 则可以使用randsample https www m
  • 如何使用 BLAS 执行向量矩阵乘法?

    BLAS 定义了 GEMV 矩阵向量乘法 2 级运算 如何使用 BLAS 库执行向量矩阵乘法 这可能很明显 但我不知道如何使用 BLAS 运算进行此乘法 我原本期望进行 GEVM 手术 M x N 矩阵与 N x 1 向量的矩阵向量乘法将得
  • 指针和切片引用类型 - 接收器

    我认为一旦向我提出这个问题就会有点明显 但现在以下内容还没有点击 type Stack interface func stack Stack Push x interface stack append stack x 我有一个名为 Stac
  • 在Matlab中,是否可以终止脚本,但将其所有内部变量保存到工作区?

    我正在运行一个脚本 但它花费的时间太长 所以我想终止该脚本 然而 它计算了很多数据 我理想情况下不想扔掉这些数据 有没有替代方案ctrl C用什么将内部函数变量保存到工作区 理想情况下我正在寻找一个Matlab键盘快捷键如ctrl C 但如
  • 在Matlab中,如何改变轴方向?

    我一直在 Matlab 中编写一个脚本来绘制 3D 图像 方法是使用plot3 轴在此区间内运行 x 1 gt 0 y 0 01 gt 0 z 0 gt 1 结果如下图所示 现在我想更改轴的方向 并使用此轴方向重新绘制图形 x 0 gt 1
  • 如何避免 Google App Engine 标准环境中 Gorilla 会话的内存泄漏?

    我正在使用 Gorilla 在 Google App Engine 上启用会话变量 到目前为止 我只导入了 github com gorilla sessions 但 Gorilla 的页面显示 如果您不使用 gorilla mux 则需要
  • 此代码中 Matlab 与 C++ 速度比较

    我编写了简单的 C 代码并在 C 中对其进行了测试 然后我通过以下方式为 MATLAB 调整了相同的代码mex file name cpp并在 MATLAB 中运行相同的代码 该代码使用与 C 相同的编译器 这是代码 int k for i
  • 如何最大限度地减少 Go 中的垃圾收集?

    有时您可能想避免 最小化垃圾收集器 所以我想确定如何做到这一点 我认为下一个是正确的 在函数的开头声明变量 使用数组代替切片 还有吗 为了最大限度地减少 Go 中的垃圾收集 您必须最大限度地减少堆分配 为了最大限度地减少堆分配 您必须了解分
  • 如何将 RGB 图像转换为灰度图像但保留一种颜色?

    我正在尝试创建类似的效果Sin City或其他电影 它们删除图像中除一种颜色之外的所有颜色 我有一个 RGB 图像 我想将其转换为灰度图像 但我想保留一种颜色 这是我的照片 我想保留红色 其余的应该是灰度的 这是我的代码到目前为止输出的内容
  • golang 将 big.Float 转换为 big.Int

    将big Float转换为big Int 我在下面编写代码 但它溢出了uint64 那么将big Float转换为big Int的正确方法是什么 package main import fmt import math big func Fl
  • 在 Go 中传递任意函数作为参数

    我正在尝试扩展我对 Go 函数指针的了解 并且我有一个问题 在 Go 中将函数作为参数传递可以做什么 不可以做什么 假设我想写一个decorator 可以包装任何现有函数的函数 为简单起见 我们将其限制为仅接受一个参数并仅返回一个值的函数
  • 使用指针接收器调用函数的 Go 语法

    在Go中 如果我定义一个带有指针的函数作为接收者 它是否应该只允许从指针调用该函数 为什么从值本身调用这个函数就可以 并且有同样的效果 例如 在以下程序中 m1 reset 和 m2 reset 具有相同的效果 即使 m1 是一个值而 m2
  • 如何在 Matlab 中绘制连通性/邻接矩阵图?

    我想在 MATLAB 中绘制网络 电网 的结构图 我有一个包含每个分支的往返节点的列表 我没有节点的坐标 并且每次模拟的系统拓扑都会发生变化 我还需要能够为各种线路 节点分配不同的颜色 以可视化电压问题或过载等 类似于我使用传记 下面的代码
  • 将数字 1 排列在二维矩阵中

    给定二维矩阵的行数和列数 初始矩阵所有元素均为0 给定每行中应该出现的 1 的数量 给定每列中应该出现的 1 的数量 确定是否可以形成这样的矩阵 例子 Input r 3 c 2 no of rows and columns 2 1 0 n
  • Matlab中带误差条的直方图

    我想将误差条放在条形图中 每个条形上方 我试过 bincentres 85 10 85 nelements 1 4 14 24 46 57 63 63 174 147 69 49 22 9 4 2 1 0 err sqrt nelement

随机推荐

  • 世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换及三维空间的刚体运动

    基本概念 https blog csdn net sunshine zoe article details 73457686 世界坐标系到相机坐标系下的变换 https www jianshu com p 64b4c887c439 通过两个
  • jquery中的伪数组和each和map静态方法区别,以及其他的一些静态方法

    伪数组 1 必须要有length属性 2 如果这个length的属性值是0 那么这个对象有没有元素无所谓 3 如果这个length的属性值不为0 那么这个对象一定头下标为 length 1 的属性值 列如 伪装组 var obj lengt
  • 公有链、联盟链、私有链区别

    1 公有链 公有链是世界上任何人都可以访问读取的 任何人都可以发送交易并且如果交易有效的话可以将之包括到区块中的 以及任何人都能够参与与其共识过程的区块 优点 所有交易数据公开 透明 无法篡改 缺点 低吞吐量 TPS 交易速度慢 2 联盟链
  • java橙色风格小说精品屋小说网站源码

    没有搭建教程 懂的自行下载研究 文件 590m com f 25127180 486121419 fbf84f 访问密码 551685 安装环境 宝塔面板 tomcat8 nginx1 17 mysql5 6 不知道最高支持到多少 打开服务
  • linux netLink检测usb插拔事件

    include
  • 从一到无穷大

    这本书一开始讲数学 后来讲到4围空间 空间压缩 相对论就头疼了 本不想读下去了 后来硬着头皮往下读 发现后面章节讲解生物 化学 天文等等 哈哈 原来是本科普的读物 大概都知道一些 不错 推荐给初高中生来看一看 2013 12 07
  • Linux内核之softirq机制

    中断的上半部执行紧要的任务 下半部则可以处理数据等次要的任务 tasklet也是基于softirq实现的 不同于tasklet的是 softirq是kernel编译时静态分配的 所以如果动态创建softirq或者kill softirqs
  • java 加密知识整理(未完)

    以下为网络转载 如有侵权请告知以便改正 JKS JCEKS PKCS12 BKS UBER 转一篇文章 http hi baidu com beyond456 blog item a3a009d7479b44d9a044df32 html
  • 计算机网络自顶向下WireShark实验:IP

    前言 计算机网络自顶向下WireShark实验记录 可供参考 题目 1 Select the first ICMP Echo Request message sent by your computer and expandthe Inter
  • 第二十六篇 DenseNet实战

    文章目录 摘要 1 项目结构 2 划分训练集和测试集 3 计算mean和Standard 3 1 标准化的作用 3 2 归一化的作用 4 Mixup CutMix CutOut数据集增强 5 训练
  • Windows应用-C#使用命令行执行PowerShell脚本

    前言 类似于bat脚本 能够自动执行一些任务 但是对bat不熟悉 因此选择使用C 来实现 具体是能够通过执行特定的语句实现对文件的读写与执行 代码 using System using System Collections Generic
  • 排序算法-堆排序

    思路 堆排序 Heapsort 是指利用堆积树 堆 这种数据结构所设计的一种排序算法 它是选择排序的一种 它是通过堆 来进行选择数据 需要注意的是排升序要建大堆 排降序建小堆 我们先将要排序的数据建成堆 然后通过下图所示的步骤进行排序 特性
  • 调试经验 - Fat文件打开失败的问题

    问题描述 在M7上调试打开SD卡中的某个文件 并读取内容的过程中 发现在SD卡中存在的一个文件firmware bin 通过open接口访问时 出现访问失败的问题 排查过程 发现f open 中传入的open flag为FA READ FA
  • 算法之拓扑关系

    目录 前言 算法解析 Kahn算法 DFS算法 总结 参考资料 前言 如何确定代码源文件的编译依赖关系 我们知道 一个完整的项目往往会包含很多代码源文件 编译器在编译整个项目的时候 需要按照依赖关系 依次编译每个源文件 比如 A cpp 依
  • Nginx动态负载均衡

    Nginx一般作为反向代理服务器来实现反向代理来转发处理请求 同时也可以作为静态资源服务器来加快静态资源的获取和处理 1 正向代理与反向代理 正向代理 正向代理 是一个位于客户端和原始服务器之间的服务器 为了从原始服务器取得内容 客户端向代
  • Elasticsearch整合springboot

    Elasticsearch 项目整合 Elasticsearch Rest Client 1 通过 9300 TCP spring data elasticsearch transport api jar springboot版本不同 ra
  • 爬虫学习小结

    前几天学习爬虫 总结如下 目录 一 Request 1 get函数初介绍 2 response 对象 3 Request库异常 4 通用代码框架 5 Request库七个主要方法 6 控制访问参数 二 Robots协议 三 beautifu
  • ML算法推导细节08—极端梯度提升XGBoost

    探究算法细节 深入了解算法原理 XGBoost的参考资料 XGBoost A Scalable Tree Boosting System 论文原文 KDD 2016 华盛顿大学 陈天奇博士 XGBoost PPT资料 陈天奇 XGBoost
  • Java 序列化

    Java 序列化 Java 提供了一种对象序列化的机制 该机制中 一个对象可以被表示为一个字节序列 该字节序列包括该对象的数据 有关对象的类型的信息和存储在对象中数据的类型 将序列化对象写入文件之后 可以从文件中读取出来 并且对它进行反序列
  • gauss 函数

    高斯滤波 高斯平滑 是图像处理 计算机视觉里面最常见的操作 平时 我们都是用matlab或者opencv的函数调用 imfilter或者cvSmooth 并不关心底层的实现 然而当开发者要实做高斯滤波的时候 往往就会很迷惘 往往会被以下几个