2011-12-27 8 views
29

Mam tablicę takiego:Jak zastosować maskę w kształcie dysku do tablicy 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.]]) 

tworzę płytę w kształcie maski o promieniu 3 tak:

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

Daje:

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

Teraz chcę aby móc zastosować tę maskę do mojej tablicy, używając dowolnego elementu jako punktu centralnego. Tak więc, na przykład, z punktem środkowym punkcie (1,1), chcę uzyskać tablicę jak:

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

Czy istnieje prosty sposób zastosować tę maskę?

Edytuj: Nie powinienem mieszać booleans i floats - to było mylące.

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

Jest to bardziej wynik, którego wymagam.

tablica [maska] = 255

maskuje tablicy za pomocą punktu środkowego (0 + promień 0 + promień).

Chciałbym jednak móc umieścić dowolną wielkość maski w dowolnym punkcie (y, x) i automatycznie dopasować ją do rozmiaru.

Odpowiedz

44

chciałbym zrobić to w ten sposób, gdzie (a, b) jest ośrodkiem maskę:

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

Aby uzyskać taki sam wynik jak w przykładzie, można zrobić coś takiego:

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

To działa ... ale to dość hack, z duplikacją macierzy i zmianą typu dtype ... Mnożenie przez 0/1 jest kanonicznym sposobem sugerowanym przez @ 9000. – mac

+0

@mac Tak, zgadzam się. Spodziewałem się uzyskać informacje zwrotne z PO, aby dowiedzieć się, czego tak naprawdę szuka. – jcollado

+0

Przykro mi, że wprowadzam w błąd. Wyjaśniłem moje pytanie w moim poście. To, czego chcę, to sposób na uzyskanie elementów w oryginalnej macierzy, które są pokryte przez maskę, biorąc pod uwagę punkt środkowy (y, x) maski. Wtedy będę mógł nimi manipulować zgodnie z wymaganiami. – user816555

2

Czy spróbuj maska ​​lub zer i jedynek, a następnie przy użyciu per-elementowa tablica mnożenia? To jest sposób kanoniczny, mniej więcej.

Również jesteś pewien chcesz mieszankę cyfr i logicznych w numpy tablicy? NumPy, jak sama nazwa wskazuje, działa najlepiej z liczbami.

+0

Przykro mi z powodu zamieszania związanego z mieszanką liczb/boolean. Mam nadzieję, że pytanie nie jest już tak mylące. Czy możesz wyjaśnić swoje zdanie pierwsze więcej? – user816555

7

Chciałem tylko podzielić się ze wszystkimi nieco bardziej zaawansowane stosowanie tej techniki, że miałem tylko do twarzy.

Moim problemem było zastosowanie tego okrągłego jądra do obliczenia średniej wszystkich wartości otaczających każdy punkt w matrycy 2D. Generowane jądro można przekazać do generycznego filtra scipy w następujący sposób:

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) 

Mam nadzieję, że to pomoże!

3

Mówiąc jednym dogodnym funkcję:

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

Zwraca sumę piksela w promieniu lub zwrotu (tablica [maska] = 2) dla jakiejkolwiek potrzeby.

3

Można użyć funkcji convolve scipy, która ma tę zaletę, że pozwala na umieszczenie żadnej konkretnej maski, aka jądra, na dowolnej liczbie podanych współrzędnych w swojej tablicy, wszystko na raz:

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

Najpierw utwórz tablicę z współrzędna gdzie chcesz maska ​​(jądro) koordynuje się koncentrować oznaczony jako 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.]] 

Tworzenie maski:

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 dwa obrazy:

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

Należy zauważyć, że wpisy funkcyjne convolve nie dojeżdża, tj convolve (a, b) = convolve (b, a)

Należy również zauważyć, że jeśli punkt jest blisko krawędzi, algo nie odtwarza jądra we współrzędnych. Aby obejść ten problem, możesz umieścić tło za pomocą największej osi jądra, zastosować splot, a następnie usunąć wypełnienie.

Teraz możesz mapować dowolne jądro do dowolnej liczby punktów w tablicy, ale pamiętaj, że jeśli dwa jądra nakładają się, dodają się w zakładce. Możesz to próg, jeśli potrzebujesz.

Powiązane problemy