Comment appliquer un masque en forme de disque à un tableau numpy?
J'ai un tableau comme ceci:
>>> 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.]])
Je crée un masque en forme de disque avec Rayon 3 ainsi:
y,x = np.ogrid[-3: 3+1, -3: 3+1]
mask = x**2+y**2 <= 3**2
Cela donne:
>> 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)
Maintenant, je veux pouvoir appliquer ce masque à mon tableau, en utilisant n'importe quel élément comme point central. Ainsi, par exemple, avec le point central à (1,1), je veux obtenir un tableau comme:
>>> 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.]])
Est-il un moyen facile d'appliquer ce masque?
Edit: Je n'aurais pas dû mélanger les booléens et les flotteurs - c'était trompeur.
>>> 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.]])
C'est plus le résultat que j'ai besoin.
Tableau[masque] = 255
Masquera le tableau en utilisant le point central (0 + rayon, 0 + rayon).
Cependant, j'aimerais pouvoir placer n'importe quel masque de taille à n'importe quel point (y,x) et l'avoir automatiquement coupé pour s'adapter.
6 réponses
Je le ferais comme ceci, où (a, b) est le centre de votre masque:
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
Je voulais juste partager avec tout le monde une application un peu plus avancée de cette technique que je devais juste faire face.
Mon problème était d'appliquer ce noyau circulaire pour calculer la moyenne de toutes les valeurs entourant chaque point dans une matrice 2D. Le noyau généré peut être passé au filtre générique de scipy de la manière suivante:
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)
Espérons que cela aide!
Pour le mettre une fonction pratique:
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]))
Renvoie la somme des pixels dans le rayon, ou return (array[mask] = 2) pour n'importe quel besoin.
Vous pouvez utiliser la fonction convolve de scipy, qui a l'avantage de vous permettre de placer n'importe quel masque particulier, alias noyau, sur n'importe quel nombre de coordonnées données dans votre tableau, tout à la fois:
import numpy as np
from scipy.ndimage.filters import convolve
Créez D'abord un tableau de coordonnées avec la coordonnée de l'endroit où vous voulez que le masque (noyau) soit centré marqué comme 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.]]
Créez votre masque:
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 les deux images:
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.]]
Notez que les entrées de la fonction convolve ne commutent pas, c'est à dire de convolution(a,b) != convolution(b,a)
Notez également que si votre point est proche d'un bord, l'algo ne reproduit pas le noyau à la coordonnée. Pour contourner cela, vous pouvez pad l'arrière-plan par le plus grand axe de votre noyau, appliquer la convolution, puis supprimer le remplissage.
Maintenant, vous pouvez mapper n'importe quel noyau de n'importe quel nombre de points dans un tableau, mais notez que si deux noyaux se chevauchent, ils ajoutent à la chevaucher. Vous pouvez le seuil si vous avez besoin.
Avez-vous essayé de créer un masque ou des zéros et des uns, puis d'utiliser une multiplication de tableau par élément? C'est la voie canonique, plus ou moins.
Aussi, êtes-vous certains vous voulez un mélange de chiffres et de booléens dans un numpy tableau? NumPy, comme son nom l'indique, fonctionne mieux avec les nombres.
Pour obtenir le même résultat que dans votre exemple, vous pouvez faire quelque chose comme ceci:
>>> 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)