2011-12-27 9 views
29

que tiene una matriz de esta manera:¿Cómo aplicar una máscara en forma de disco a una matriz numpy?

>>> np.ones((8,8)) 
array([[ 1., 1., 1., 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1., 1., 1., 1.]]) 

estoy creando una máscara en forma de disco con un radio de 3 así:

y,x = np.ogrid[-3: 3+1, -3: 3+1] 
mask = x**2+y**2 <= 3**2 

Esto da:

>> mask 
array([[False, False, False, True, False, False, False], 
     [False, True, True, True, True, True, False], 
     [False, True, True, True, True, True, False], 
     [ True, True, True, True, True, True, True], 
     [False, True, True, True, True, True, False], 
     [False, True, True, True, True, True, False], 
     [False, False, False, True, False, False, False]], dtype=bool) 

Ahora, quiero para poder aplicar esta máscara a mi matriz, usando cualquier elemento como punto central. Así, por ejemplo, con el punto central al (1,1), quiero conseguir una matriz como:

>>> new_arr 
array([[ True, True, True, True, 1., 1., 1., 1.], 
     [ True, True, True, True, True, 1., 1., 1.], 
     [ True, True, True, True, 1., 1., 1., 1.], 
     [ True, True, True, True, 1., 1., 1., 1.], 
     [ 1., True, 1., 1., 1., 1., 1., 1.], 
     [ 1.,  1., 1., 1., 1., 1., 1., 1.], 
     [ 1.,  1., 1., 1., 1., 1., 1., 1.], 
     [ 1.,  1., 1., 1., 1., 1., 1., 1.]]) 

¿Hay una manera fácil de aplicar esta máscara?

Editar: No debería haber mezclado booleanos y flotadores - fue engañoso.

>>> new_arr 
array([[ 255., 255., 255., 255., 1., 1., 1., 1.], 
     [ 255., 255., 255., 255., 255., 1., 1., 1.], 
     [ 255., 255., 255., 255., 1., 1., 1., 1.], 
     [ 255., 255., 255., 255., 1., 1., 1., 1.], 
     [ 1., 255., 1., 1., 1., 1., 1., 1.], 
     [ 1.,  1., 1., 1., 1., 1., 1., 1.], 
     [ 1.,  1., 1., 1., 1., 1., 1., 1.], 
     [ 1.,  1., 1., 1., 1., 1., 1., 1.]]) 

Esto es más el resultado que requiero.

array [máscara] = 255

enmascararán la matriz mediante punto central (0 + radio, 0 + radio).

Sin embargo, me gustaría poder colocar cualquier máscara de tamaño en cualquier punto (y, x) y hacer que se recorte automáticamente para que quepa.

Respuesta

44

lo haría como este, donde (a, b) es el centro de su máscara:

import numpy as np 

a, b = 1, 1 
n = 7 
r = 3 

y,x = np.ogrid[-a:n-a, -b:n-b] 
mask = x*x + y*y <= r*r 

array = np.ones((n, n)) 
array[mask] = 255 
0

para obtener el mismo resultado que en el ejemplo, se puede hacer algo como esto:

>>> new_arr = np.array(ones, dtype=object) 
>>> new_arr[mask[2:, 2:]] = True 
>>> print new_arr 
array([[True, True, True, True, 1.0, 1.0, 1.0, 1.0], 
     [True, True, True, True, True, 1.0, 1.0, 1.0], 
     [True, True, True, True, 1.0, 1.0, 1.0, 1.0], 
     [True, True, True, True, 1.0, 1.0, 1.0, 1.0], 
     [1.0, True, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], 
     [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], 
     [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], 
     [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]], dtype=object) 
+0

Funciona ... pero es bastante complicado, con la duplicación de arreglos y cambiando el tipo de letra ... La multiplicación por 0/1 es la manera canónica sugerida por @ 9000. – mac

+0

@mac Sí, estoy de acuerdo. Esperaba obtener algunos comentarios del OP para descubrir qué es lo que realmente está buscando. – jcollado

+0

Lo siento por ser engañoso. Aclaré mi pregunta en mi publicación. Lo que quiero es una forma de obtener los elementos en la matriz original que están cubiertos por la máscara, dado un punto central (y, x) para la máscara. Entonces puedo manipularlos según sea necesario. – user816555

2

¿Usted intentó hacer una máscara o ceros y unos y luego usar per-elemento de la matriz de multiplicación? Esta es la manera canónica, más o menos.

Además, está usted seguro desea una mezcla de números y booleanos en una numpy matriz? NumPy, como su nombre lo indica, funciona mejor con números.

+0

Disculpa la confusión con respecto a la combinación número/booleanos. Esperemos que la pregunta ya no sea tan engañosa. ¿Podría explicar más su primera oración? – user816555

7

solo quería compartir con todos una aplicación un poco más avanzada de esta técnica que sólo tenía enfrentar.

Mi problema fue aplicar este núcleo circular para calcular la media de todos los valores que rodean cada punto en una matriz 2D. El núcleo generada se puede pasar a SciPy de filtro genérico de la siguiente manera:

import numpy as np 
from scipy.ndimage.filters import generic_filter as gf 

kernel = np.zeros((2*radius+1, 2*radius+1)) 
y,x = np.ogrid[-radius:radius+1, -radius:radius+1] 
mask = x**2 + y**2 <= radius**2 
kernel[mask] = 1 
circular_mean = gf(data, np.mean, footprint=kernel) 

Espero que esto ayude!

3

por decirlo de alguna función útil:

def cmask(index,radius,array): 
    a,b = index 
    nx,ny = array.shape 
    y,x = np.ogrid[-a:nx-a,-b:ny-b] 
    mask = x*x + y*y <= radius*radius 

    return(sum(array[mask])) 

devuelve la suma de píxeles dentro un radio, o de retorno (array [máscara] = 2) por cualquier necesidad.

3

Se puede utilizar la función de convolución de scipy, que tiene la ventaja de que le permite colocar cualquier máscara especial, también conocido como núcleo, en cualquier número de coordenadas dadas en su conjunto, todo a la vez:

import numpy as np 
from scipy.ndimage.filters import convolve 

En primer lugar crear una coordenada array con las coordenadas del lugar donde desea la máscara (núcleo) que se centra marcados como 2

background = np.ones((10,10)) 
background[5,5] = 2 
print(background) 

[[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 
[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 
[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 
[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 
[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 
[ 1. 1. 1. 1. 1. 2. 1. 1. 1. 1.] 
[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 
[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 
[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 
[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]] 

Cree su máscara:

y,x = np.ogrid[-3: 3+1, -3: 3+1] 
mask = x**2+y**2 <= 3**2 
mask = 254*mask.astype(float) 
print(mask) 

[[ 0. 0. 0. 254. 0. 0. 0.] 
[ 0. 254. 254. 254. 254. 254. 0.] 
[ 0. 254. 254. 254. 254. 254. 0.] 
[ 254. 254. 254. 254. 254. 254. 254.] 
[ 0. 254. 254. 254. 254. 254. 0.] 
[ 0. 254. 254. 254. 254. 254. 0.] 
[ 0. 0. 0. 254. 0. 0. 0.]] 

Convolve las dos imágenes:!

b = convolve(background, mask)-sum(sum(mask))+1 
print(b) 

[[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 
[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 
[ 1. 1. 1. 1. 1. 255. 1. 1. 1. 1.] 
[ 1. 1. 1. 255. 255. 255. 255. 255. 1. 1.] 
[ 1. 1. 1. 255. 255. 255. 255. 255. 1. 1.] 
[ 1. 1. 255. 255. 255. 255. 255. 255. 255. 1.] 
[ 1. 1. 1. 255. 255. 255. 255. 255. 1. 1.] 
[ 1. 1. 1. 255. 255. 255. 255. 255. 1. 1.] 
[ 1. 1. 1. 1. 1. 255. 1. 1. 1. 1.] 
[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]] 

Tenga en cuenta que las entradas de la función de convolución no conmutan, es decir convolución (a, b) = convolución (b, a)

Tenga en cuenta también que si su el punto está cerca de un borde, el algo no reproduce el núcleo en la coordenada. Para evitar esto, puede rellenar el fondo con el eje más grande de su kernel, aplicar la convolución y luego eliminar el relleno.

Ahora, puede asignar cualquier kernel a cualquier número de puntos en una matriz, pero tenga en cuenta que si se superponen dos núcleos, se agregan en la superposición. Puede limitar esto si lo necesita.

Cuestiones relacionadas