Cómo usar el imresize de Matlab en python

Estoy transfiriendo el código imresize de Matlab a python. Encontré el tamaño de la imresize , pero obtengo resultados diferentes de Matlab.

Cómo obtener los mismos resultados que Matlab by python.

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); 

Estas dos piezas de código devuelven resultados diferentes.

La función scipy.misc.imresize es un poco extraña para mí. Por un lado, esto es lo que sucede cuando especifico la imagen 2D de muestra que proporcionó a una llamada scipy.misc.imresize en esta imagen con una escala de 1.0. Idealmente, debería darle la misma imagen, pero lo que obtenemos es esto (en 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) 

No solo cambia el tipo de salida a uint8 , sino que también escala los valores. Por un lado, parece que hace que el valor máximo de la imagen sea igual a 255 y el valor mínimo igual a 0. El imresize de MATLAB no hace esto y cambia el tamaño de una imagen de la forma que esperamos:

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

Sin embargo, debe tener en cuenta que MATLAB realiza el cambio de tamaño con el suavizado habilitado de forma predeterminada . No estoy seguro de qué hace scipy.misc.resize aquí, pero apuesto a que no está habilitado el suavizado.

Edición – 23 de noviembre de 2016

Como señaló Eric en sus comentarios a continuación, si emite la imagen al tipo deseado, obtendrá los resultados esperados:

 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) 

Podemos ver que la imagen no está escalada al rango [0,255] . Para finalmente llegar a donde necesita ir, debemos obtener una representación de punto flotante de la imagen. scipy.misc.imresize tiene un indicador adicional llamado 'mode' y puede especificarlo como 'F' para garantizar que la salida sea de punto flotante.

 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) 

Como verá más adelante, los resultados que ve con scipy.misc.resize no coinciden con lo que ve en MATLAB.

Para obtener los mejores resultados, no especifique una escala: especifique un tamaño de salida objective para reproducir los resultados. Como tal, 1/scale en su caso es similar a una salida de tamaño 2 x 2 , y esto es lo que haría en 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 

Puede ver que algunos de los valores de la matriz no se alinean con scipy.misc.resize . Para que coincida con lo que ves en MATLAB. Lo más parecido a lo que desea es la función de cambio de resize de OpenCV o la función de cambio de resize scikit-image. Ambos de estos no tienen anti-aliasing. Si desea que Python y MATLAB coincidan, utilice el método de interpolación bilineal. imresize en MATLAB usa la interpolación bicúbica por defecto y sé a imresize cierta que MATLAB usa núcleos personalizados para hacerlo, por lo que será mucho más difícil hacer coincidir sus resultados si utiliza la interpolación bicúbica entre los métodos. Vea este post para algunos resultados más informativos:

MATLAB vs C ++ vs OpenCV – imresize

Con 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. ]]) 

Con 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. ]]) 

Una última cosa interesante a tener en cuenta es que MATLAB, OpenCV y scikit-image cuando especifican una escala de punto flotante actúan de manera diferente entre sí. Hice algunos experimentos y al especificar un tamaño de punto flotante, no pude hacer coincidir los resultados. Además, scikit-image no admite la toma de un factor de escala, lo cual es una razón más para establecer explícitamente un tamaño de salida en lugar de una escala.

Para agregar una opción más encontré, mientras exploraba la excelente respuesta de @rayryeng .

El scipy.misc.imresize usa PIL (y por lo tanto convierte la imagen en enteros escalados). Pero la página enlaza con otra función: 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]]) 

No me da el mismo resultado que matlab, pero se acerca:

 >> dtest = [1,2,3;4,5,6;7,8,9]; >> imresize(dtest, [2,2]) ans = 2.1296 3.5648 6.4352 7.8704 

Dependiendo de lo que quieras lograr, esto podría ser útil. Para mí, tiene la ventaja de no necesitar incluir otro paquete en el proyecto, ya que scipy ya está en uso.

Después de mucho excavar, la única solución que encontré que reproduce el imresize de matlab con anti-aliasing es el código de Alex (paternal) en https://github.com/fatheral/matlab_imresize . Actualmente solo utiliza el kernel bicúbico, pero se puede expandir fácilmente a cualquier otro kernel provisto en Matlab.