2015-08-06 17 views
13

Mam rastrowe siedliska ekologiczne, które przekonwertowałem na dwuwymiarową tablicę Python numpy (tablica przykładowa poniżej). Mam również tablicę zawierającą regiony "seed" z unikalnymi wartościami (seed_array poniżej), które chciałbym użyć do klasyfikacji moich regionów habitatu. Chciałbym, aby "wyhodował" moje regiony nasienne "na" moje regiony siedliskowe, tak aby siedliska miały przypisany identyfikator najbliższego obszaru nasiennego, mierzony "przez" rejony siedlisk. Na przykładKlasyfikowanie tablicy Pythona według najbliższego regionu "seed"?

Image of arrays

My najlepsze podejście użyto funkcji ndimage.distance_transform_edt utworzyć tablicę przedstawiających najbliższe „ziarno” region każdej komórki do zbioru danych, który następnie podstawiony powrót do tablicy siedliska. To nie działa szczególnie dobrze, jednak, jak ta funkcja nie mierzyć odległości „do” moich regionach siedlisk, na przykład, poniżej, gdzie czerwony okrąg reprezentuje nieprawidłowo sklasyfikowany komórek:

Incorrect output using ndimage

Poniżej przedstawiamy przykładowy tablice dla moich danych dotyczących siedlisk i nasion oraz przykład tego, czego szukam. Moje rzeczywiste zbiory danych są znacznie większe - ponad milion siedlisk/regionów nasion. Każda pomoc będzie doceniona!

import numpy as np 
import scipy.ndimage as ndimage 
import matplotlib.pyplot as plt 

# Sample study area array 
example_array = np.array([[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], 
          [0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1], 
          [0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1], 
          [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0], 
          [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1], 
          [1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1], 
          [1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1], 
          [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], 
          [1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0], 
          [1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], 
          [1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], 
          [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) 

# Plot example array 
plt.imshow(example_array, cmap="spectral", interpolation='nearest') 

seed_array = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
         [0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0], 
         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0], 
         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
         [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
         [0, 1, 1, 1, 0, 0, 2, 2, 0, 0, 0, 0], 
         [0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], 
         [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], 
         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) 

# Plot seeds 
plt.imshow(seed_array, cmap="spectral", interpolation='nearest') 

desired_output = np.array([[0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0], 
          [0, 0, 0, 4, 4, 4, 0, 0, 0, 3, 3, 3], 
          [0, 0, 0, 0, 4, 4, 0, 0, 0, 3, 3, 3], 
          [0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0], 
          [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 3, 3], 
          [1, 1, 0, 1, 0, 0, 0, 0, 2, 2, 3, 3], 
          [1, 1, 1, 1, 0, 0, 2, 2, 2, 0, 0, 3], 
          [1, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0], 
          [1, 1, 1, 1, 0, 0, 2, 2, 2, 0, 0, 0], 
          [1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], 
          [1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], 
          [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) 

# Plot desired output 
plt.imshow(desired_output, cmap="spectral", interpolation='nearest') 
+1

Czy próbowałeś zastosować iteracyjne podejście, w którym stopniowo powiększasz każdy obszar nasienny, przesuwając o jeden kwadrat "na zewnątrz" od centrum naraz i zatrzymując się, gdy napotkasz już przypisane komórki? – BrenBarn

+0

Myślałem o próbowaniu czegoś podobnego, ale myślę, że może to być trudne podejście, biorąc pod uwagę, że moje zbiory danych są bardzo duże - ponad milion siedlisk łatek/regionów nasion. Odpowiednio zaktualizowałem pytanie. –

Odpowiedz

11

Można użyć watershed segmentation z scikits-image:

  • Odległość przekształcić

    from scipy import ndimage as nd 
    distance = nd.distance_transform_edt(example_array) 
    
  • Watershed segmentacji

    from skimage.morphology import watershed, square 
    result = watershed(-distance, seed_array, mask=example_array, \ 
            connectivity=square(3)) 
    
  • Rezultat

    subplot(1,2,1) 
    imshow(-distance, 'spectral', interpolation='none') 
    subplot(1,2,2) 
    imshow(result, 'spectral', interpolation='none') 
    

enter image description here


W innym wariancie, a po początkowej podejście, można użyć przełom znaleźć podłączonych sąsiadów do najbliższej nasion.Jak wspomniano w pytaniu:

  • obliczyć odległość do nasion:

    distance = nd.distance_transform_edt(seed_array == 0) 
    
  • Oblicz przełomowym w przestrzeni odległość:

    result = watershed(distance, seed_array, mask=example_array, \ 
            connectivity=square(3)) 
    
  • wynik działki:

    figure(figsize=(9,3)) 
    subplot(1,3,1) 
    imshow(distance, 'jet', interpolation='none') 
    subplot(1,3,2) 
    imshow(np.ma.masked_where(example_array==0, distance), 'jet', interpolation='none') 
    subplot(1,3,3) 
    imshow(result, 'spectral', interpolation='none') 
    

enter image description here


Dalsze omówienie: sposób Watershed próbuje rosnąć regionów z zaszczepionych szczytów przepływające przez przez gradientu obrazu. Ponieważ twój obraz jest binarny, regiony rozszerzają się jednakowo we wszystkich kierunkach od wysianych punktów, a tym samym dają punkt pomiędzy dwoma regionami. Więcej informacji na temat działu wodnego można znaleźć pod adresem wikipedia.

W pierwszym przykładzie, transformacja odległości jest obliczana na oryginalnym obrazie, a zatem obszary rozszerzają się równomiernie od nasion, aż osiągną punkt podziału w środku.

W drugim przykładzie przekształcenie odległości jest obliczane ze wszystkich pikseli do dowolnego z posianych punktów, a następnie stosowanie przełomu w tym obszarze. Usługa Watershed zasadniczo przypisuje każdy piksel do najbliższego źródła, ale dodaje ograniczenie łączności.

UWAGA Różnica znaków na mapach odległości zarówno w wykreślaniu, jak i podczas nawadniania.

UWAGA W mapach odległości (lewy obraz na obu poletkach) niebieski oznacza miejsce, w którym czerwony oznacza daleko.

+0

Wspaniała odpowiedź! zasłużyłeś na niezłe popisy! –

+1

@Robbi Bishop-Taylor Uaktualniłem swoją odpowiedź wiele razy, aby ulepszyć fabułę. Spójrz jeszcze raz, myślę, że na drugim wykresie jest to pożądane wyjście. –

+0

@imaluengo Tak, właśnie widziałem zmiany po opublikowaniu mojego komentarza. Teraz robi dokładnie to, czego bym się spodziewał. Dzięki za fantastyczną odpowiedź! –

Powiązane problemy