Tengo una matriz numpy 2D que representa una imagen monocroma de un CCD que se ha agrupado 3x3 (es decir, cada valor en la matriz representa 9 píxeles (3x3) en el CCD físico).

Quiero reescalarlo para que coincida con el diseño CCD original (para poder superponerlo fácilmente con una imagen no agrupada del mismo CCD).

Vi Volver a muestrear una matriz numpy que representa una imagen, pero eso no ' Parece que hago lo que quiero.

Supongamos que tengo una matriz g:

import numpy as np
import scipy.ndimage

 g = np.array([[0, 1, 2],
               [3, 4, 5],
               [6, 7, 8]])

Cuando trato de escalarlo por un factor de 2:

o = scipy.ndimage.zoom(g, 2, order=0)

Obtengo exactamente lo que esperaba: cada valor ahora es 2x2 valores idénticos:

array([[0, 0, 1, 1, 2, 2],
       [0, 0, 1, 1, 2, 2],
       [3, 3, 4, 4, 5, 5],
       [3, 3, 4, 4, 5, 5],
       [6, 6, 7, 7, 8, 8],
       [6, 6, 7, 7, 8, 8]])

Pero cuando trato de escalar por un factor de 3, obtengo esto:

o = scipy.ndimage.zoom(g, 3, order=0)

Me da

array([[0, 0, 1, 1, 1, 1, 2, 2, 2],
       [0, 0, 1, 1, 1, 1, 2, 2, 2],
       [3, 3, 4, 4, 4, 4, 5, 5, 5],
       [3, 3, 4, 4, 4, 4, 5, 5, 5],
       [3, 3, 4, 4, 4, 4, 5, 5, 5],
       [3, 3, 4, 4, 4, 4, 5, 5, 5],
       [6, 6, 7, 7, 7, 7, 8, 8, 8],
       [6, 6, 7, 7, 7, 7, 8, 8, 8],
       [6, 6, 7, 7, 7, 7, 8, 8, 8]])

Quería que cada valor en la matriz original se convirtiera en un conjunto de valores 3x3 ... eso no es lo que obtengo.

¿Cómo puedo hacerlo? (¿Y por qué obtengo este resultado poco intuitivo?)

7
nerdfever.com 5 sep. 2014 a las 02:58

2 respuestas

La mejor respuesta

Puede usar np.kron:

In [16]: g
Out[16]: 
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

In [17]: np.kron(g, np.ones((3,3), dtype=int))
Out[17]: 
array([[0, 0, 0, 1, 1, 1, 2, 2, 2],
       [0, 0, 0, 1, 1, 1, 2, 2, 2],
       [0, 0, 0, 1, 1, 1, 2, 2, 2],
       [3, 3, 3, 4, 4, 4, 5, 5, 5],
       [3, 3, 3, 4, 4, 4, 5, 5, 5],
       [3, 3, 3, 4, 4, 4, 5, 5, 5],
       [6, 6, 6, 7, 7, 7, 8, 8, 8],
       [6, 6, 6, 7, 7, 7, 8, 8, 8],
       [6, 6, 6, 7, 7, 7, 8, 8, 8]])

La salida de zoom(g, 3, order=0) es un poco sorprendente. Considere la primera fila: [0, 0, 1, 1, 1, 1, 2, 2, 2]. ¿Por qué hay cuatro 1 s?

Cuando order=0 zoom (en efecto) calcula np.linspace(0, 2, 9), que parece

In [80]: np.linspace(0, 2, 9)
Out[80]: array([ 0.  ,  0.25,  0.5 ,  0.75,  1.  ,  1.25,  1.5 ,  1.75,  2.  ])

Y luego redondea los valores. Si usa np.round(), obtiene:

In [71]: np.round(np.linspace(0, 2, 9)).astype(int)
Out[71]: array([0, 0, 0, 1, 1, 1, 2, 2, 2])

Tenga en cuenta que np.round(0.5) da 0, pero np.round(1.5) da 2. np.round() utiliza la "media vuelta para igualar" la regla de desempate. Aparentemente, el redondeo realizado en el código zoom usa la regla "redondear medio abajo" : redondea 0.5 a 0 y 1.5 a 1, como en el siguiente

In [81]: [int(round(x)) for x in np.linspace(0, 2, 9)]
Out[81]: [0, 0, 1, 1, 1, 1, 2, 2, 2]

Y es por eso que hay cuatro 1 s allí.

9
Warren Weckesser 5 sep. 2014 a las 02:28

¿Y por qué obtengo este resultado poco intuitivo?

Porque zoom es una función de interpolación spline. En otras palabras, dibuja una spline cúbica desde el punto medio de ese 1 hasta el punto medio de ese 0, y los valores intermedios obtienen los valores de la spline en la ubicación adecuada.

Si desea la interpolación más cercana, lineal o cuadrática en lugar de cúbica, puede usar el argumento order=0 o order=1 o order=2. Pero si no desea la interpolación en absoluto, lo cual no desea, no use una función de interpolación. Esto es como preguntar por qué usar [int(i*2.3) for i in range(10)] para obtener números pares del 0 al 20 le da algunos números impares. No es una función obtener números pares del 0 al 20, por lo que no hace eso, pero hace exactamente lo que le pediste.


¿Cómo puedo hacerlo?

Nuevamente, si desea una escala no interpolada, no use una función de interpolación. Probablemente, la forma más sencilla es utilizar np.kron , para Kroenecker, multiplique su matriz con np.ones((scale, scale)).

2
abarnert 4 sep. 2014 a las 23:10