Python 中的 Matlab imgaussfilt 等价物

Matlab's imgaussfilt equivalent in Python

我试图在 Python 中复制 Matlab 的 imgaussfilter 行为,但我一直无法重现结果。文档没有太大帮助,因为没有解释到底做了什么(例如,该函数与 fspecial 有何不同,或者它与 Octave 的 imsmooth(以高斯作为参数)有何不同)。

Matlab代码

imgaussfilt(image,sigma)

有输出

 [[-0.02936392 -0.03168419 -0.0343706  ...  0.03136455  0.02864487
   0.02585145]
 [-0.03212093 -0.0347433  -0.03775943 ...  0.03507484  0.03209807
   0.02906134]
 [-0.03512981 -0.03808864 -0.04147075 ...  0.03873834  0.03549163
   0.03219311]
 ...
 [-0.07713804 -0.08337475 -0.08975262 ... -0.04314206 -0.03945251
  -0.03606256]
 [-0.07145457 -0.07714807 -0.08297654 ... -0.03986635 -0.03641579
  -0.03323718]
 [-0.06605107 -0.07122191 -0.07651892 ... -0.03684535 -0.03362917
  -0.03065128]]

我最接近 Python 的是:

Python

skimage.filters.gaussian(image, sigma=s,mode = 'nearest',truncate=2.0)

有输出

[[-0.02936397 -0.03168425 -0.03437067 ...  0.03136461  0.02864492
   0.0258515 ]
 [-0.03212099 -0.03474336 -0.03775951 ...  0.03507491  0.03209814
   0.0290614 ]
 [-0.03512988 -0.03808872 -0.04147083 ...  0.03873842  0.03549169
   0.03219317]
 ...
 [-0.07713819 -0.08337491 -0.08975279 ... -0.04314214 -0.03945259
  -0.03606263]
 [-0.07145471 -0.07714821 -0.0829767  ... -0.03986643 -0.03641586
  -0.03323725]
 [-0.06605119 -0.07122205 -0.07651907 ... -0.03684542 -0.03362923
  -0.03065134]]

这是相似但不完全相同的结果。有没有更好地近似它的方法?我需要更改其中一个参数吗?

编辑: 如果您正在寻找使用 OpenCV 的近似值,@avisionx 在解决方案中提供了一个很好的起点。

这有多种可能的原因。由于 Matlab 不是开源软件,因此无法知道确切原因,但我们可以进行一些有根据的猜测。

关于什么 Gaussian filtering is doing: it replaces every pixel with a weighted sum of its neighbors. The weighting is determined by the Gaussian probability density function 确切 权重由 sigma 决定,但也由 truncate 参数决定,您可以在 [=11] 中看到=] 文档。这个参数是必需的,因为从技术上讲,高斯函数永远不会衰减到零,它只是随着距离变得无穷大而接近零,所以 "perfect" 高斯模糊需要对无限数量的相邻像素求和,这是不可能的.因此,该函数需要决定距离零有多远才能停止求和。

另一个复杂因素是高斯模糊是 separable, which means that you can do a 2D (or nD) blur by blurring separately along each axis in sequence, which can reduce computing costs. Separability affects the order of computation, and floating point computation is not exact,因此如果 Matlab 和 Python 以不同的顺序执行操作,您会得到略有不同的结果。

即使您以完全相同的顺序过滤轴(您可以通过例如转置 Python 中的图像,过滤,然后将其转回),底层的低级数组计算库可能以不同的顺序对数组求和,这又会改变确切的结果。

简而言之,您所看到的差异的一些可能原因:

  • 截断不同
  • 不同的实现(是否分离过滤器)
  • 轴的不同处理顺序
  • 低级和的不同排序

可能没有办法解决这些问题,最后我的建议反映了 Cris Luengo 的评论:您的结果可能不应该依赖于比六位有效数字更精确的值。 Matlab 和 Python 之间的精确匹配在这里将毫无意义,因为两者都不能保证相对于高斯滤波器的理论值的完美准确性。两者都是近似值,完全匹配仅意味着您在两者中产生相同的近似值误差。

我能够在使用 mode='wrap' 参数调用的 imgaussfilt called with the circular padding option and scipy.ndimage.gaussian_filter 之间获得相对较好的匹配(优于 10e-10 百分比),前提是 imgaussfilt 使用默认过滤器2*ceil(2*sigma)+1gaussian_filter 的大小指定 truncate=np.ceil(2*sigma)/sigma。对于 circular 填充情况,这些设置会导致底层高斯核的半径和总体大小相同。我没有测试其他填充类型。

最近我致力于将 Matlab 代码转换为 python,并在 Internet 和文档中查找相同的函数,发现与 OpenCV 实现的结果完全相同。

% In Matlab
imgaussfilt(image, 100)

相当于

import cv2
# in python
cv2.GaussianBlur(image, ksize=(0, 0), sigmaX=100, borderType=cv2.BORDER_REPLICATE)