2012-06-05 25 views
5

Tengo una imagen.Encuentra una ventana deslizante 3x3 sobre una imagen

Quiero obtener una ventana de 3x3 (píxeles vecinos) para cada píxel de la imagen.

que tienen el código Python:

for x in range(2,r-1,1): 
    for y in range(2,c-1,1): 
     mask5=numpy.array([cv.Get2D(copy_img,x-1,y-1),cv.Get2D(copy_img,x-1,y),cv.Get2D(copy_img,x-1,y+1),cv.Get2D(copy_img,x,y-1),cv.Get2D(copy_img,x,y),cv.Get2D(copy_img,x,y+1),cv.Get2D(copy_img,x+1,y-1),cv.Get2D(copy_img,x+1,y),cv.Get2D(copy_img,x+1,y+1)]) 
     cent=[cv.Get2D(copy_img,x,y)] 

mask5 es la ventana de 3x3. ciento es el píxel central.

¿Hay alguna manera más eficiente de hacerlo, es decir, usar mapas, iteradores, cualquier cosa que no sean los dos bucles anidados que he usado?

+0

¿Cuál es su intención? ¿Probablemente quieres realizar una convolución? Cuéntanos qué vas a hacer con 'mask5', entonces podemos ayudarte mejor, ¡salud! – fraxel

+0

@fraxel: Después de obtener la ventana, necesito ordenar los píxeles en la ventana de 3x3 por intensidad, y crear otra ventana deslizante (unidimensional) sobre esta lista, y basada en una condición compleja en el medio de los píxeles en estas diapositivas (1-d) modifican el píxel central original en consecuencia. –

+0

Parece que está intentando hacer [umbral adaptativo] (http://opencv.willowgarage.com/documentation/python/imgproc_miscellaneous_image_transformations.html?highlight=adaptivethreshold#AdaptiveThreshold)? Echa un vistazo a eso, puede hacer lo que quieras. – fraxel

Respuesta

2

Esto se puede hacer más rápido, mediante la remodelación y el intercambio de ejes, y luego repetir sobre todos los elementos del núcleo, así:

im = np.arange(81).reshape(9,9) 
print np.swapaxes(im.reshape(3,3,3,-1),1,2) 

Esto le da una gran variedad de 3 * 3 fichas que tessalates través la superficie:

[[[[ 0 1 2] [[ 3 4 5] [[ 6 7 8] 
    [ 9 10 11] [12 13 14] [15 16 17] 
    [18 19 20]] [21 22 23]] [24 25 26]]] 

[[[27 28 29] [[30 31 32] [[33 34 35] 
    [36 37 38] [39 40 41] [42 43 44] 
    [45 46 47]] [48 49 50]] [51 52 53]]] 

[[[54 55 56] [[57 58 59] [[60 61 62] 
    [63 64 65] [66 67 68] [69 70 71] 
    [72 73 74]] [75 76 77]] [78 79 80]]]] 

para obtener las baldosas superpuestas que tenga que repetir este 8 más veces, pero 'envoltura' la matriz, mediante el uso de una combinación de vstack y column_stack. Tenga en cuenta que el derecho y teja inferior matrices se envuelven alrededor (que puede o no ser lo que quiera, dependiendo de cómo esté el tratamiento de condiciones de borde):

im = np.vstack((im[1:],im[0])) 
im = np.column_stack((im[:,1:],im[:,0])) 
print np.swapaxes(im.reshape(3,3,3,-1),1,2) 

#Output: 
[[[[10 11 12] [[13 14 15] [[16 17 9] 
    [19 20 21] [22 23 24] [25 26 18] 
    [28 29 30]] [31 32 33]] [34 35 27]]] 

[[[37 38 39] [[40 41 42] [[43 44 36] 
    [46 47 48] [49 50 51] [52 53 45] 
    [55 56 57]] [58 59 60]] [61 62 54]]] 

[[[64 65 66] [[67 68 69] [[70 71 63] 
    [73 74 75] [76 77 78] [79 80 72] 
    [ 1 2 3]] [ 4 5 6]] [ 7 8 0]]]] 

Hacerlo de esta manera que terminan con 9 juegos de matrices , entonces debes volver a unirlos. Esto, y toda la remodelación generaliza a esto (para las matrices donde las dimensiones son divisibles por 3):

def new(im): 
    rows,cols = im.shape 
    final = np.zeros((rows, cols, 3, 3)) 
    for x in (0,1,2): 
     for y in (0,1,2): 
      im1 = np.vstack((im[x:],im[:x])) 
      im1 = np.column_stack((im1[:,y:],im1[:,:y])) 
      final[x::3,y::3] = np.swapaxes(im1.reshape(rows/3,3,cols/3,-1),1,2) 
    return final 

Comparando esta función new a bucle a través de todas las rebanadas (abajo), usando timeit, está a unos 4 veces más rápido , para una matriz de 300 * 300.

def old(im): 
    rows,cols = im.shape 
    s = [] 
    for x in xrange(1,rows): 
     for y in xrange(1,cols): 
      s.append(im[x-1:x+2,y-1:y+2]) 
    return s 
+0

Gracias. Logré reducir todo esto a una sola línea corta de código, lamentablemente, en MATLAB (función im2col). ¿Esta función tiene un equivalente directo en Python? –

+0

@VelvetGhost im2col es solo una función que envuelve una implementación [como la mía] (http://stackoverflow.com/a/10900022/709852) o la anterior (aunque con un poco más de brillo). La implementación de MATLAB no elimina mágicamente el código. Si puede usar su propia función, tanto mejor, ya que no depende de una costosa caja de herramientas para que funcione (tal es la alegría de MATLAB). Además, no asuma que porque está en una caja de herramientas, es rápido o eficiente. –

+0

@HenryGomersall: ¡Gracias! Sí, sí sé que MATLAB no elimina mágicamente el código. Lo encontré más fácil y rápido al escribir código en un plazo. Muchas gracias por la implementación de Python. Me ayudará a aprender más sobre Python cuando tenga algo de tiempo. –

1

Creo que lo siguiente es lo que buscas. El ciclo solo supera los 9 elementos. Estoy seguro de que hay una forma de vectorizarlo, pero probablemente no valga la pena el esfuerzo.

import numpy 

im = numpy.random.randint(0,50,(5,7)) 

# idx_2d contains the indices of each position in the array 
idx_2d = numpy.mgrid[0:im.shape[0],0:im.shape[1]] 

# We break that into 2 sub arrays 
x_idx = idx_2d[1] 
y_idx = idx_2d[0] 

# The mask is used to ignore the edge values (or indeed any values). 
mask = numpy.ones(im.shape, dtype='bool') 
mask[0, :] = False 
mask[:, 0] = False 
mask[im.shape[0] - 1, :] = False 
mask[:, im.shape[1] - 1] = False 

# We create and fill an array that contains the lookup for every 
# possible 3x3 array. 
idx_array = numpy.zeros((im[mask].size, 3, 3), dtype='int64') 

# Compute the flattened indices for each position in the 3x3 grid 
for n in range(0, 3): 
    for m in range(0, 3): 
     # Compute the flattened indices for each position in the 
     # 3x3 grid 
     idx = (x_idx + (n-1)) + (y_idx + (m-1)) * im.shape[1] 

     # mask it, and write it to the big array 
     idx_array[:, m, n] = idx[mask] 


# sub_images contains every valid 3x3 sub image 
sub_images = im.ravel()[idx_array] 

# Finally, we can flatten and sort each sub array quickly 
sorted_sub_images = numpy.sort(sub_images.reshape((idx[mask].size, 9))) 
1

Prueba el siguiente código como función MATLAB im2col (...)

import numpy as np 

def im2col(Im, block, style='sliding'): 
    """block = (patchsize, patchsize) 
     first do sliding 
    """ 
    bx, by = block 
    Imx, Imy = Im.shape 
    Imcol = [] 
    for j in range(0, Imy): 
     for i in range(0, Imx): 
      if (i+bx <= Imx) and (j+by <= Imy): 
       Imcol.append(Im[i:i+bx, j:j+by].T.reshape(bx*by)) 
      else: 
       break 
    return np.asarray(Imcol).T 

if __name__ == '__main__': 
    Im = np.reshape(range(6*6), (6,6)) 
    patchsize = 3 
    print Im 
    out = im2col(Im, (patchsize, patchsize)) 
    print out 
    print out.shape 
    print len(out) 
Cuestiones relacionadas