python 为什么cv2和skimage之间的高斯滤波器不同?

vm0i2vca  于 2022-10-30  发布在  Python
关注(0)|答案(5)|浏览(167)

我使用cv2.GaussianBlurskimage.gaussian_filter库对一张图像应用高斯模糊,但得到的结果却截然不同。我很好奇为什么,以及如何才能使skimage看起来更像cv2。我知道skimage.gaussian_filterscipy.scipy.ndimage.filters.gaussian_filter的 Package 器。为了清楚地说明这个问题,为什么这两种功能不同?2怎样做才能使它们更相似?
下面是我的测试图像:

下面是cv2版本(看起来比较模糊):

以下是skimage/scipy版本(看起来更清晰):

详细信息:
skimage_response = skimage.filters.gaussian_filter(im, 2, multichannel=True, mode='reflect')
cv2_response = cv2.GaussianBlur(im, (33, 33), 2)
因此sigma=2,滤波器的大小足够大,不会产生差异,Imagemagick covnert -gaussian-blur 0x2在视觉上与cv2一致。
版本:cv2 =2.4.10,skimage =0.11.3,scipy =0.13.3

u3r8eeie

u3r8eeie1#

如果有人想知道如何使skimage.gaussian_filter()与Matlab的imgaussfilt()相匹配(这也是我提出这个问题的原因),请将参数'truncate=2'传递给skimage.gaussian_filter()。skimage和Matlab都将内核大小作为sigma的函数来计算。Matlab的默认值是2。Skimage的默认值是4,默认情况下会产生一个明显更大的内核。

wr98u20j

wr98u20j2#

对于GaussianBlur,您使用了一个相当大的内核(大小=33),这会导致大量的平滑。平滑将在很大程度上取决于您的内核大小。使用您的参数,每个新的像素值将在一个33*33像素的“窗口”中“平均”。
有关cv2.GaussianBlur的定义,请访问http://docs.opencv.org/3.1.0/d4/d13/tutorial_py_filtering.html#gsc.tab=0
相比之下,skimage.filters.gaussian似乎可以在更小的内核上工作。在skimage中,“大小”由sigma定义,sigma与内核大小相关,如下所述:https://en.wikipedia.org/wiki/Gaussian_filter
定义可在此处找到:http://scikit-image.org/docs/dev/api/skimage.filters.html#skimage.filters.gaussian
为了获得相应的结果,您必须使用较小的OpenCV内核。
此外,对于这两个库,我强烈建议使用最新的库版本。

zpgglvta

zpgglvta3#

这两者是相等的:

gau_img = cv2.GaussianBlur(img, (5,5), 10.0) # 5*5 kernal, 2 on each side. 2 = 1/5 * 10 = 1/5 * sigma
gau_img = skimage.filters.gaussian(img, sigma=10, truncate=1/5)

整个高斯核只由sigma定义,但是你用高斯核的哪一部分来模糊图像是由truncate(在skimage中)还是ksize(在opencv中)定义。

but5z9lq

but5z9lq4#

根据[Scipy0.15.1 API][1]

scipy.ndimage.filters(img, sigma=sigma, truncate = 4.0)

它将高斯滤波器的核大小设置为truncate * sigma。在这种理解下,下面两个函数将在灰度图像上给予相同的结果:

trunc_val = 3
sigma_val = 3
k_size = int(sigma_val * trunc_val)
gau_img1 = cv2.GaussianBlur(img, (k_size,k_size), sigma_val)
gau_img2 = gaussian_filter(img, sigma = sigma_val, truncate = trunc_val) 

cv2.imshow("cv2 res", gau_img1)
cv2.imshow("scipy res", gau_img2)
cv2.waitKey(-1)

部分测试结果:截断瓦尔= 3;西格玛瓦尔= 3 x1c 0d1x
截断瓦尔= 3;西格玛瓦尔= 1

截断瓦尔= 3;西格玛值= 9

qaxu7uf2

qaxu7uf25#

opencvscipy都允许指定sigma,它在两个库中具有相同的含义。内核大小的确定方式不同:

  • scipy中,它是从truncate参数派生的,即int(truncate * sigma + 0.5)
  • opencv中,它可以独立于sigma指定(如果省略,它的计算方式与sigma = 0.3*((ksize-1)*0.5 - 1) + 0.8不同。

因此,要获得相同的结果,您需要显式指定内核大小和sigma:

import cv2
from skimage.filters import gaussian
import matplotlib.pyplot as plt

img = cv2.imread('bg4dZ.png', cv2.IMREAD_GRAYSCALE)

truncate = 4
sigma = 2
radius = int(truncate * sigma + 0.5)
ksize = 2 * radius + 1

opencv = cv2.GaussianBlur(img, (ksize, ksize), sigma, borderType=cv2.BORDER_REFLECT)
scipy = gaussian(img, sigma, truncate=truncate, preserve_range=True, mode='reflect')

fig, axs = plt.subplots(ncols=4, layout='constrained', figsize=(16, 4))
axs[0].imshow(img, cmap='gray')
axs[1].imshow(opencv, cmap='gray')
axs[2].imshow(scipy, cmap='gray')
diff = opencv - scipy
diff = axs[3].imshow(diff, cmap='seismic', vmin=diff.min(), vmax=-diff.min())
fig.colorbar(diff, shrink=.95)
for ax in axs:
    ax.set_axis_off()

其余差异(参见第4个图)是由浮点计算和不同的结果数据类型(uint8float64)引起的。

相关问题