Encuentra una ventana deslizante de 3×3 sobre una imagen

Tengo una imagen

Quiero obtener una ventana de 3×3 (píxeles adyacentes) para cada píxel en la imagen.

Tengo este código de 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 3×3. cent es el píxel central.

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

Esto se puede hacer más rápido, cambiando de forma y cambiando los ejes, y luego repitiendo sobre todos los elementos del núcleo, como esto:

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

Esto le da una serie de 3 * 3 azulejos que tessalates a través de 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 los mosaicos superpuestos necesitamos repetir esto 8 veces más, pero “envolviendo” la matriz, usando una combinación de vstack y column_stack . Tenga en cuenta que las matrices de azulejos derecho e inferior se envuelven (lo que puede o no ser lo que usted desea, dependiendo de cómo esté tratando las condiciones del 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]]]] 

Al hacerlo de esta manera, terminas con 9 conjuntos de arreglos, por lo que luego debes volver a unirlos. Esto, y todos los cambios de forma generalizan a esto (para 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 new función con un bucle a través de todos los segmentos (a continuación), usando timeit , es aproximadamente 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 

Creo que lo siguiente hace lo que buscas. El bucle es sólo sobre 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))) 

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