2016-06-15 10 views
5

Sagen wir, dass ich wünscheIst es möglich, eine Funktion zu vektorisieren, die auf verschiedene Elemente in einem numpy Array zugreift?

den folgenden Code in Python implementieren

Diese Funktion ein Bild als 1-dimensionales Array annimmt, und iteriert über einzelne Elemente in der Anordnung (Pixel in dem Eingangsbild), die eine Ausgangsanordnung betrifft, die ist auch ein Bild als ein 1-dimensionales Array dargestellt

Beispiel: ein einzelnes Pixel in dem Eingangsbild (rot) 8 umgebenden Pixeln in (orange) wirkt example 1

eine grundlegende Implementierung in C ist

/* C version 
* Given an input image create an 
* output image that is shaped by individual pixels 
* of the input image 
*/ 

int image[width * height]; //image retrieved elsewhere 
int output [width * height]; //output image 
int y = 0, x = 0; 
for(y = 1; y < height-1 ; ++ y) { 
    for(x = 1; x < width-1; ++ x) { 
     if (image[y * width + x] > condition) { 
      /* pixel affects the surrounding 8 pixels in the output image */ 

      output[(y-1) * width + x - 1]++; /* upper left */ 
      output[(y-1) * width + x ]++; /* above  */ 
      output[(y-1) * width + x + 1]++; /* upper right */ 
      output[y * width + x + 1 ]++; /* right  */ 
      output[y * width + x - 1 ]++; /* left  */ 
      output[(y+1) * width + x - 1]++; /* lower left */ 
      output[(y+1) * width + x ]++; /* below  */ 
      output[(y+1) * width + x + 1]++; /* lower right */ 


     } 
    } 
} 

würde die naive Ansatz in Python, die genau das gleiche Element weise Zugang zu verwenden, wie unten

#Python version 
input = blah # formed elsewhere 
output = np.zeros(width * height) 
for y in xrange(1, height-1): 
    for x in xrange(1, width-1): 
     if input[y * width + x] > condition: 
      output[(y-1) * width + x - 1]+= 1; # upper left 
      output[(y-1) * width + x ]+= 1; # above  
      output[(y-1) * width + x + 1]+= 1; # upper right 
      output[y * width + x + 1 ]+= 1; # right  
      output[y * width + x - 1 ]+= 1; # left   
      output[(y+1) * width + x - 1]+= 1; # lower left 
      output[(y+1) * width + x ]+= 1; # below  
      output[(y+1) * width + x + 1]+= 1; # lower right 

gezeigt gibt es einen besseren Weg, dies zu implementieren? Ist es möglich, diese Funktion zu vektorisieren?

Antwort

0

Nehmen wir an, arr repräsentiert das Eingangsarray und thresh ist die Schwelle, die mit jedem der Eingangselemente verglichen werden soll. Jetzt können wir das Eingangsarray gegen den gegebenen Schwellenwert schwenken, was uns ein Masken/Boolesches Array gibt. Dann können wir eine 2D-Faltung durchführen und davon 1s subtrahieren, wobei wir True Werte für das thresholdierte Array hatten.

Somit würde die Umsetzung in etwa so aussehen -

from scipy.signal import convolve2d 

# Get thresholded mask as int array & set first, last cols and rows as 0s 
mask = (arr > thresh).astype(int) 
mask[[0,-1]] = 0 
mask[:,[0,-1]] = 0 

# Perform 2D convolution and subtract 1s corresponding to True elems in mask 
out = convolve2d(mask,np.ones((3,3),dtype=int),'same') - mask 
5

Wenn ich die Frage richtig verstanden hat, dann kann der Ansatz des Kopf gestellt werden: Wenn ein Pixel hat in seiner Nachbarschaft Pixeln, die die Bedingung erfüllen, Erhöhen Sie es für jedes Spiel um eins. Tun Sie dies für alle Pixel. Scipy (unter anderem) bietet Werkzeuge für filtering images:

In [51]: import scipy.ndimage 

Erstellen Sie das Beispielbild aus dem 1-dimensionalen Array. Reshape schafft eine Ansicht anstelle des Kopierens:

In [62]: I1d 
Out[62]: 
array([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
     0, 0, 0, 0, 0, 129, 0, 129, 129, 0, 0, 0, 0, 
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 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, 129]) 

In [63]: height 
Out[63]: 8 

In [64]: width 
Out[64]: 8 

In [65]: I = I1d.reshape((height, width)) 

In [66]: I 
Out[66]: 
array([[ 0, 0, 0, 0, 0, 0, 0, 0], 
     [ 0, 0, 0, 0, 0, 0, 0, 0], 
     [ 0, 0, 129, 0, 129, 129, 0, 0], 
     [ 0, 0, 0, 0, 0, 0, 0, 0], 
     [ 0, 0, 0, 0, 129, 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, 129]]) 

Verwendung Faltung ein Bild erzeugen, die die Inkremente zu jedem Pixel in dem Original aus einer binären Maske aus Pixeln, die den Zustand (128 hier) nicht überschreiten gilt:

In [67]: scipy.ndimage.filters.convolve(
    (I > 128).astype(np.int), # conditioned binary image 
    weights=np.array([[1, 1, 1], # each match weighted as 1 
         [1, 0, 1], 
         [1, 1, 1]]), 
    mode='constant', cval=0) # Use zeros as constant fill values on edges 
Out[67]: 
array([[0, 0, 0, 0, 0, 0, 0, 0], 
     [0, 1, 1, 2, 2, 2, 1, 0], 
     [0, 1, 0, 2, 1, 1, 1, 0], 
     [0, 1, 1, 3, 3, 3, 1, 0], 
     [0, 0, 0, 1, 0, 1, 0, 0], 
     [0, 0, 0, 1, 1, 1, 0, 0], 
     [0, 0, 0, 0, 0, 0, 1, 1], 
     [0, 0, 0, 0, 0, 0, 1, 0]]) 

In [68]: conv = _ 

Wenn das letzte Ziel ist das Original und die Inkremente hinzuzufügen:

In [69]: I + conv 
Out[69]: 
array([[ 0, 0, 0, 0, 0, 0, 0, 0], 
     [ 0, 1, 1, 2, 2, 2, 1, 0], 
     [ 0, 1, 129, 2, 130, 130, 1, 0], 
     [ 0, 1, 1, 3, 3, 3, 1, 0], 
     [ 0, 0, 0, 1, 129, 1, 0, 0], 
     [ 0, 0, 0, 1, 1, 1, 0, 0], 
     [ 0, 0, 0, 0, 0, 0, 1, 1], 
     [ 0, 0, 0, 0, 0, 0, 1, 129]]) 

zur Ausgabe einer 1-dimensionale Arrays als w verwenden Sie entweder ravel() oder flatten(). Die frühere schafft eine 1-dimensionale Ansicht auf den ursprünglichen 2-dimensionalen Array, wobei letztere eine abgeflachte Kopie erstellt:

In [70]: conv.ravel() 
Out[70]: 
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 1, 0, 0, 1, 0, 2, 1, 1, 1, 
     0, 0, 1, 1, 3, 3, 3, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 
     0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0]) 
3

Ich denke, was Sie versuchen, mit 2D-Array-Indizierung zu tun, ist am einfachsten. Sie können Arrays einfach mit numpy umformen. Es werden keine Daten kopiert. Das neue 2D-Array bietet nur eine bequeme Möglichkeit zum Indizieren der gleichen Werte, die im ursprünglichen Array gespeichert sind. Hier ist ein Beispielcode.

#imports 
import numpy as np 


# Setup 
Nx = 5 
Ny = 7 
cutoff = 3.0 
arr_input = np.array([[0, 0, 0, 0, 0, 0, 9], 
         [0, 4, 0, 0, 0, 0, 0], 
         [0, 0, 0, 0, 0, 3, 0], 
         [0, 2, 0, 0, 0, 0, 1], 
         [0, 0, 0, 0, 5, 0, 0]]).flatten() 

# Make an array of center locations with input value bigger than the cutoff value 
centers_array_2d = np.where(arr_input>=cutoff, 1.0, 0.0) 

# Initialize the output array 
arr_output = np.zeros_like(centers_array_2d) 

# Reshape the arrays to use 2D indexing 
ai = centers_array_2d.reshape(Nx, Ny) 
ao = arr_output.reshape(Nx, Ny) 

# Do the neighbor calculation with numpy indexing rules 
ao[:-1, :-1] += ai[1:, 1:]    # lower left 
ao[:, :-1] += ai[:, 1:]     # lower center 
ao[1:, :-1] += ai[:-1, 1:]    # lower right 
ao[:-1, :] += ai[1:, :]     # middle left 
# ao[:, :] += ai[:, :]     # middle center 
ao[1:, :] += ai[:-1, :]     # middle right 
ao[:-1, 1:] += ai[1:, :-1]    # top left 
ao[:, 1:] += ai[:, :-1]     # top center 
ao[1:, 1:] += ai[:-1, :-1]    # top right 

# Reshape the output array to return a 1D array like the input 
arr_output = ao.flatten() 

# Print the results 
print('input1d: \n{}\n'.format(arr_input)) 
print("2D array 'ai':\n{}\n".format(ai)) 
print("2D array 'ao':\n{}\n".format(ao)) 
print('output1d: \n{}\n'.format(arr_output)) 

Die Arrays sind wie folgt.

input1d: 
[0 0 0 0 0 0 9 0 4 0 0 0 0 0 0 0 0 0 0 3 0 0 2 0 0 0 0 1 0 0 0 0 5 0 0] 

2D array 'ai': 
[[ 0. 0. 0. 0. 0. 0. 1.] 
[ 0. 1. 0. 0. 0. 0. 0.] 
[ 0. 0. 0. 0. 0. 1. 0.] 
[ 0. 0. 0. 0. 0. 0. 0.] 
[ 0. 0. 0. 0. 1. 0. 0.]] 

2D array 'ao': 
[[ 1. 1. 1. 0. 0. 1. 0.] 
[ 1. 0. 1. 0. 1. 2. 2.] 
[ 1. 1. 1. 0. 1. 0. 1.] 
[ 0. 0. 0. 1. 2. 2. 1.] 
[ 0. 0. 0. 1. 0. 1. 0.]] 

output1d: 
[ 1. 1. 1. 0. 0. 1. 0. 1. 0. 1. 0. 1. 2. 2. 1. 1. 1. 0. 1. 0. 1. 0. 0. 0. 1. 2. 2. 1. 0. 0. 0. 1. 0. 1. 0.] 

Ist dies die Berechnung, nach der Sie gesucht haben? Dies würde ich als Vektorisierung des von Ihnen angegebenen Codes interpretieren. Sie können auch eine Liste von Indizes für die 1D-Arrays erstellen, die jedem Nachbarn entsprechen. Dies ist im Wesentlichen der Fall, wenn ich 2D-Schicht-Indizes für den Zugriff auf Elemente der 2D-Arrays verwende.

Verwandte Themen