Pixel vecinos en 2d array (imagen) usando Python

Tengo una matriz numpy como esta:

x = np.array([[1,2,3],[4,5,6],[7,8,9]]) 

Necesito crear una función, llamémosla “vecinos” con el siguiente parámetro de entrada:

  • x: una matriz 2d numpy
  • (i, j): el índice de un elemento en una matriz 2d
  • d: radio del barrio

Como salida quiero obtener los vecinos de la celda i,j con una distancia dada d . Así que si corro

 neighbors(im, i, j, d=1) with i = 1 and j = 1 (element value = 5) 

Debería obtener los índices de los siguientes valores: [1,2,3,4,6,7,8,9] . Espero dejarlo claro. ¿Hay alguna biblioteca como Scipy que se ocupan de esto?

He hecho algo trabajando pero es una solución difícil.

 def pixel_neighbours(self, p): rows, cols = self.im.shape i, j = p[0], p[1] rmin = i - 1 if i - 1 >= 0 else 0 rmax = i + 1 if i + 1 = 0 else 0 cmax = j + 1 if j + 1 < cols else j neighbours = [] for x in xrange(rmin, rmax + 1): for y in xrange(cmin, cmax + 1): neighbours.append([x, y]) neighbours.remove([p[0], p[1]]) return neighbours 

¿Cómo puedo mejorar esto?

EDIT : ah mierda, mi respuesta es simplemente escribiendo im[id:i+d+1, jd:j+d+1].flatten() pero escrito de una manera incomprensible 🙂


El buen viejo truco de la ventana deslizante puede ayudar aquí:

 import numpy as np from numpy.lib.stride_tricks import as_strided def sliding_window(arr, window_size): """ Construct a sliding window view of the array""" arr = np.asarray(arr) window_size = int(window_size) if arr.ndim != 2: raise ValueError("need 2-D input") if not (window_size > 0): raise ValueError("need a positive window size") shape = (arr.shape[0] - window_size + 1, arr.shape[1] - window_size + 1, window_size, window_size) if shape[0] <= 0: shape = (1, shape[1], arr.shape[0], shape[3]) if shape[1] <= 0: shape = (shape[0], 1, shape[2], arr.shape[1]) strides = (arr.shape[1]*arr.itemsize, arr.itemsize, arr.shape[1]*arr.itemsize, arr.itemsize) return as_strided(arr, shape=shape, strides=strides) def cell_neighbors(arr, i, j, d): """Return d-th neighbors of cell (i, j)""" w = sliding_window(arr, 2*d+1) ix = np.clip(i - d, 0, w.shape[0]-1) jx = np.clip(j - d, 0, w.shape[1]-1) i0 = max(0, i - d - ix) j0 = max(0, j - d - jx) i1 = w.shape[2] - max(0, d - i + ix) j1 = w.shape[3] - max(0, d - j + jx) return w[ix, jx][i0:i1,j0:j1].ravel() x = np.arange(8*8).reshape(8, 8) print x for d in [1, 2]: for p in [(0,0), (0,1), (6,6), (8,8)]: print "-- d=%d, %r" % (d, p) print cell_neighbors(x, p[0], p[1], d=d) 

No hice ningún tiempo aquí, pero es posible que esta versión tenga un rendimiento razonable.

Para obtener más información, busque en la red las frases "número de ventana móvil" o "número de ventana deslizante".

Echa un vistazo a scipy.ndimage.generic_filter .

Como ejemplo:

 import numpy as np import scipy.ndimage as ndimage def test_func(values): print values return values.sum() x = np.array([[1,2,3],[4,5,6],[7,8,9]]) footprint = np.array([[1,1,1], [1,0,1], [1,1,1]]) results = ndimage.generic_filter(x, test_func, footprint=footprint) 

Por defecto, “reflejará” los valores en los límites. Puede controlar esto con el argumento de la palabra clave de mode .

Sin embargo, si desea hacer algo como esto, hay una buena posibilidad de que pueda express su problema como una especie de convolución. Si es así, será mucho más rápido scipy.ndimage en pasos convolucionales y utilizar funciones más optimizadas (por ejemplo, la mayoría de scipy.ndimage ).

No conozco ninguna función de biblioteca para esto, pero usted puede escribir algo como esto usando la gran funcionalidad de corte de números:

 import numpy as np def neighbors(im, i, j, d=1): n = im[id:i+d+1, jd:j+d+1].flatten() # remove the element (i,j) n = np.hstack((b[:len(b)//2],b[len(b)//2+1:] )) return n 

Por supuesto, debe hacer algunas verificaciones de rango para evitar el acceso fuera de los límites.

Estoy de acuerdo con la respuesta de Joe Kington, solo un agregado a las huellas

 import numpy as np from scipy.ndimage import generate_binary_structure from scipy.ndimage import iterate_structure foot = np.array(generate_binary_structure(2, 1),dtype=int) 

o para huellas más grandes / diferentes por ej.

 np.array(iterate_structure(foot , 2),dtype=int) 

Posiblemente use un KDTree en SciPy ?