如何在 python 中使用 Matlab 的 imresize

How to use Matlab's imresize in python

我正在将 Matlab 的 imresize 代码转移到 python。我找到了 scipy 的 imresize,但我从 Matlab 得到了不同的结果。

如何通过python获得与Matlab相同的结果。

Python/scipy imresize

from scipy.misc import imresize
import numpy as np

dtest = np.array(([1,2,3],[4,5,6],[7,8,9]))
scale = 1.4
dim = imresize(dtest,1/scale)

Matlab imresize

dtest = [1,2,3;
         4,5,6;
         7,8,9];
scale = 1.4;
dim = imresize(dtest,1/scale);

这两段代码return不同的结果。

scipy.misc.imresize 函数对我来说有点奇怪。一方面,当我指定您提供给比例为 1.0 的 scipy.misc.imresize 调用的样本 2D 图像时,会发生这种情况。理想情况下,它应该给你相同的图像,但我们得到的是这个(在 IPython 中):

In [35]: from scipy.misc import imresize

In [36]: import numpy as np

In [37]: dtest = np.array(([1,2,3],[4,5,6],[7,8,9]))

In [38]: out = imresize(dtest, 1.0)

In [39]: out
Out[39]: 
array([[  0,  32,  64],
       [ 96, 127, 159],
       [191, 223, 255]], dtype=uint8)

它不仅将输出类型更改为 uint8,而且 缩放 值。一方面,看起来它使图像的最大值等于 255,最小值等于 0。MATLAB 的 imresize 没有这样做,它按照我们期望的方式调整图像的大小:

>> dtest = [1,2,3;4,5,6;7,8,9];
>> out = imresize(dtest, 1)

out =

     1     2     3
     4     5     6
     7     8     9

但是,您需要认识到 MATLAB 执行大小调整 with anti-aliasing enabled by default。我不确定 scipy.misc.resize 在这里做了什么,但我敢打赌没有启用抗锯齿功能。

编辑 - 2016 年 11 月 23 日

正如 Eric 在下面的评论中指出的那样,如果您将图像预转换为所需的类型,您将获得预期的结果:

In [10]: dtest = np.array([[1,2,3],[4,5,6],[7,8,9]], dtype=np.uint8)

In [11]: out = imresize(dtest, 1.0)

In [12]: out
Out[12]: 
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]], dtype=uint8)

我们可以看到图像没有缩放到 [0,255] 范围内。为了最终到达你需要去的地方,我们必须获得图像的浮点表示。 scipy.misc.imresize 有一个名为 'mode' 的附加标志,您可以将其指定为 'F' 以确保输出为浮点数。

In [14]: scale = 1.4

In [15]: out = imresize(dtest, 1/scale, mode='F')

In [16]: out
Out[16]: 
array([[ 2.5 ,  3.75],
       [ 6.25,  7.5 ]], dtype=float32)

您稍后会看到,您在 scipy.misc.resize 中看到的结果与您在 MATLAB 中看到的结果不匹配。

为获得最佳结果,请不要指定比例 - 指定目标输出大小以重现结果。因此,1/scale 在你的情况下接近 2 x 2 大小输出,所以这是你在 MATLAB 中要做的:

>> dtest = [1,2,3;4,5,6;7,8,9];
>> out = imresize(dtest, [2,2], 'bilinear', 'AntiAliasing', false)

out =

    2.0000    3.5000
    6.5000    8.0000

您可以看到矩阵中的某些值与 scipy.misc.resize 不一致。匹配您在 MATLAB 中看到的内容。最接近您想要的是 OpenCV 的 resize function, or scikit-image's resize 函数。这两个都没有抗锯齿。如果想让Python和MATLAB都匹配,就用双线性插值法。 imresize 在 MATLAB 中默认使用双三次插值,我知道 MATLAB 使用自定义内核来执行此操作,因此如果在方法之间使用双三次插值,匹配它们的输出将更加困难。请参阅此 post 以获得更多信息性结果:

MATLAB vs C++ vs OpenCV - imresize

使用 Python OpenCV:

In [93]: import numpy as np

In [94]: import cv2

In [95]: dtest = np.array(([1,2,3],[4,5,6],[7,8,9]), dtype='float')

In [96]: out = cv2.resize(dtest, (2,2))

In [97]: out
Out[97]: 
array([[ 2. ,  3.5],
       [ 6.5,  8. ]])

使用 scikit-image:

In [100]: from skimage.transform import resize

In [101]: dtest = np.array(([1,2,3],[4,5,6],[7,8,9]), dtype='uint8')

In [102]: out = resize(dtest, (2,2), order=1, preserve_range=True)

In [103]: out
Out[103]: 
array([[ 2. ,  3.5],
       [ 6.5,  8. ]])

最后一件有趣的事情是,MATLAB、OpenCV 和 scikit-image 在指定浮点标度时彼此的行为不同。我做了一些实验,通过指定浮点大小,我无法获得匹配的结果。除此之外,scikit-image 不支持采用比例因子,这是明确说明输出大小而不是比例的更多原因。

添加一个我发现的选项,同时探索

scipy.misc.imresize uses PIL (and hence converts the image to scaled integers). But the page links to another function: scipy.ndimage.zoom

>>> from scipy import ndimage
>>> dtest = np.array(([1,2,3],[4,5,6],[7,8,9]), dtype='float')
>>> ndimage.zoom(dtest, 2/3)
array([[ 1.,  3.],
       [ 7.,  9.]])
>>> ndimage.zoom(dtest, 2/3, prefilter=False)
array([[ 2.33333333,  3.66666667],
       [ 6.33333333,  7.66666667]])

它没有给我与 matlab 相同的结果,但它很接近:

>> dtest = [1,2,3;4,5,6;7,8,9];
>> imresize(dtest, [2,2])

ans =
    2.1296    3.5648
    6.4352    7.8704

根据您想要实现的目标,这可能会有用。对我来说,它的优点是不需要在项目中包含另一个包,因为 scipy 已经被使用了。

经过大量挖掘,我发现唯一复制 matlab imresize 和抗锯齿的解决方案是 Alex (fatheral) at https://github.com/fatheral/matlab_imresize 的代码。目前它只使用双三次内核,但可以很容易地扩展到 Matlab 中提供的任何其他内核。