如何在Python中使用Matlab的imresize函数

10

我正在将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);

这两段代码返回不同的结果。


2
你能展示两个输出吗? - Julien Spronck
3个回答

16

scipy.misc.imresize函数对我来说有点奇怪。一方面,当我将您提供的示例2D图像指定为scipy.misc.imresize调用中的图像,并将其缩放比例设置为1.0时,会发生以下情况。理想情况下,它应该给出相同的图像,但我们得到的是这样的(在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默认启用抗锯齿功能进行调整大小(即平滑边缘)。我不确定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函数或者scikit-image的resize函数。这两个函数都没有反锯齿处理。如果您想让Python和MATLAB彼此匹配,请使用双线性插值方法。在MATLAB中,imresize默认使用双三次插值,我知道MATLAB使用自定义内核来实现,因此如果在方法之间使用双三次插值,将更加困难地匹配它们的输出。请参考此帖子以获得更多有用的结果:

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不支持输入比例因子,这更加需要明确地指定输出大小而不是比例。


2
非常有趣的背景信息! - sco1
3
我使用了你提供的方法,得到了相同的输出。非常感谢。 - user3960019
1
完全没有问题。祝你好运! - rayryeng
1
@excaza - 谢谢 :) 这需要数小时的摸索和实验...还有StackOverflow的阅读。如果不是上面链接帖子中的chappjc和Amro,我就不可能知道MATLAB的imresize的这些内容。 - rayryeng
1
如果您在第一个示例(In [37])中修改dtest的dtype为dtype ='uint8',则将从scipy的imresize获得预期结果。使用您的示例,dtest的默认类型为int64。scipy将默认'mode'指定为None,但没有解释这意味着什么。深入研究pilutil.py显示None对应于字节流(uint8)。pilutil.py似乎不支持64位数字类型,但如果指定mode ='F',则将获得预期结果。 - eric
@alanwsx 谢谢!你也可以给我的答案点赞 :) - rayryeng

3

为了补充更多选项,我在探索@rayryeng的优秀答案时找到了一个。

scipy.misc.imresize 使用PIL(因此将图像转换为比例整数)。但该页面链接到另一个函数: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。


1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接