【问题标题】:Matlab's imgaussfilt equivalent in PythonPython中的Matlab imgaussfilt等价物
【发布时间】:2020-02-13 11:18:09
【问题描述】:

我试图在 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 在解决方案中提供了一个很好的起点。

【问题讨论】:

  • 您可以查看scipy 版本,请参阅here
  • 我会看看OpenCV的高斯模糊
  • @MrFuppes 我刚试了一下,好像scipy版本和skimage版本一样。
  • 您得到相同的值,最多 6 位十进制数字。考虑到输入图像中的噪声和量化误差,您确定差异很重要吗?
  • @CrisLuengo 是的。我正在尝试尽可能地复制

标签: python python-3.x image matlab scikit-image


【解决方案1】:

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

关于Gaussian filtering 在做什么:它将每个像素替换为其相邻像素的加权和。权重由Gaussian probability density function 确定,精确 权重由 sigma 确定,还由truncate 参数确定,您可以在scipy.ndimage.gaussian_filter 文档中看到。这个参数是必需的,因为从技术上讲,高斯函数永远不会衰减到零,它只是在距离无穷大时接近零,因此“完美”的高斯模糊需要对无限数量的相邻像素求和,这是不可能的。因此,该函数需要确定您离零有多远才能停止求和。

另一个复杂的因素是高斯模糊是separable,这意味着您可以通过依次沿每个轴单独模糊来进行2D(或nD)模糊,这可以降低计算成本。可分离性会影响计算顺序,而浮点计算是not exact,所以如果Matlab 和Python 以不同的顺序进行运算,你会期望得到略微不同的结果。

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

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

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

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

【讨论】:

  • 不错的总结。还要补充一点:MATLAB 使用可分离或傅立叶域实现,具体取决于 sigma。也有递归过滤器,但不知道 OP 的方法有没有用到。
  • 哦,是的,我完全忘记了傅立叶卷积! ?‍♂️
  • 非常感谢胡安的回答。我知道试图从两种语言中产生相同的结果并不是通常执行或可取的事情。坚持近似是好的。但是,numpy 和其他图像处理库在许多情况下都尝试模拟 Matlab 结果,所以我希望找到一种方法来重现确切的结果。毕竟,这可能是一件事。我仍然会尝试将问题保持开放一段时间,看看是否有人有办法解决它,否则,我会选择你的作为答案,因为它是这个问题的一个很好的答案。
【解决方案2】:

如果imgaussfilt 使用 imgaussfilt 使用2*ceil(2*sigma)+1gaussian_filter 的默认过滤器大小指定 truncate=np.ceil(2*sigma)/sigma。对于circular 填充情况,这些设置导致底层高斯内核的半径和整体大小相同。我还没有测试过其他填充类型。

【讨论】:

    【解决方案3】:

    最近我正在研究将 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)
    

    【讨论】:

    • 与相同的浮点值一样吗?这是极不可能的。即使是不同版本的 MATLAB,也可能不会产生数值相同的输出。此外,该代码中的 OpenCV 可能会产生整数输出,而不是 OP 的浮点输出。
    • 我认为这种尝试值得称赞,因为它是对潜在精确解决方案的近似。我已经投票了 - 并在我最初的问题上强调了它 - 因为我认为希望在未来解决这个问题的人可能会考虑这种方法。然而,正如@Cris Luengo 所说,正确答案仍然存在:没有将 Matlab 结果完美复制到 Python 中。
    • @CrisLuengo 确切地说,我可以在 Matlab 和 python 中得到相似/最接近的结果,显然每个库中的舍入和算法如何编写会影响输出,但我的主要观点是 borderType=cv2.BORDER_REPLICATE 是需要更改的东西,因为默认输出不会相同
    • @avisionx:OP 已经有最多 6 位十进制数字相同的结果,并且答案显示最多 10 位十进制数字相等。他们显然想出了如何使边界条件匹配。这个答案只是显示了视觉上相似的结果,我看不出它是如何增加任何价值的。
    猜你喜欢
    • 2021-11-02
    • 2016-09-18
    • 2018-05-29
    • 2015-07-17
    • 1970-01-01
    • 1970-01-01
    • 2021-03-13
    • 2019-11-30
    • 2017-11-17
    相关资源
    最近更新 更多