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つのコードは、異なる結果を返します。
scipy.misc.imresize
関数は私には少し奇妙です。一つには、これは、この画像のscipy.misc.imresize
呼び出しに提供したサンプルの2D画像を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
に変更するだけでなく、値もスケールします。 1つには、画像の最大値が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
が何をするかはわかりませんが、アンチエイリアシングが有効になっていないことは間違いありません。
以下のコメントでエリックが指摘しているように、画像を目的のタイプにプレキャストすると、期待どおりの結果が得られます。
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はスケールファクターの取り込みをサポートしていません。これは、スケールではなく出力サイズを明示的に示す理由です。
@ rayryengによる優れた回答 を調べているときに見つけたオプションをもう1つ追加します。
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がすでに使用されているため、プロジェクトに別のパッケージを含める必要がないという利点があります。
たくさん掘り下げた後、アンチエイリアシングでmatlabのサイズ変更を複製する唯一の解決策は、 Alex(fatheral) at https://github.com/fatheral/ matlab_imresize 。現在、バイキュービックカーネルのみを使用していますが、Matlabで提供されている他のカーネルに簡単に拡張できます。