2011-11-09 15 views
10

Estoy tratando de usar numpy.lib.stride_tricks.as_strided para iterar sobre bloques no superpuestos de una matriz, pero tengo problemas para encontrar la documentación de los parámetros, por lo que Solo he podido superponer bloques.Usando Numpy stride_tricks para obtener bloques de matriz que no se superpongan

Por ejemplo, tengo una matriz de 4x5 de la que me gustaría obtener 4 bloques de 2x2. Estoy de acuerdo con que se excluyan las celdas adicionales en el borde derecho e inferior.

Hasta ahora, mi código es:

import sys 
import numpy as np 

a = np.array([ 
[1,2,3,4,5], 
[6,7,8,9,10], 
[11,12,13,14,15], 
[16,17,18,19,20], 
]) 

sz = a.itemsize 
h,w = a.shape 
bh,bw = 2,2 

shape = (h/bh, w/bw, bh, bw) 
strides = (w*sz, sz, w*sz, sz) 
blocks = np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides) 

print blocks[0][0] 
assert blocks[0][0].tolist() == [[1, 2], [6,7]] 
print blocks[0][1] 
assert blocks[0][1].tolist() == [[3,4], [8,9]] 
print blocks[1][0] 
assert blocks[1][0].tolist() == [[11, 12], [16, 17]] 

La forma de la matriz de bloques resultante parece ser correcta, pero los dos últimos afirma fallan, presumiblemente debido a mi forma o zancadas parámetros son incorrectos. ¿Qué valores debo configurar para obtener bloques no superpuestos?

Respuesta

12
import numpy as np 
n=4 
m=5 
a = np.arange(1,n*m+1).reshape(n,m) 
print(a) 
# [[ 1 2 3 4 5] 
# [ 6 7 8 9 10] 
# [11 12 13 14 15] 
# [16 17 18 19 20]] 
sz = a.itemsize 
h,w = a.shape 
bh,bw = 2,2 
shape = (h/bh, w/bw, bh, bw) 
print(shape) 
# (2, 2, 2, 2) 

strides = sz*np.array([w*bh,bw,w,1]) 
print(strides) 
# [40 8 20 4] 

blocks=np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides) 
print(blocks) 
# [[[[ 1 2] 
# [ 6 7]] 
# [[ 3 4] 
# [ 8 9]]] 
# [[[11 12] 
# [16 17]] 
# [[13 14] 
# [18 19]]]] 

A partir de la 1 en a (es decir blocks[0,0,0,0]), para llegar a la 2 (es decir blocks[0,0,0,1]) es un elemento de distancia. Dado que (en mi máquina) el a.itemsize tiene 4 bytes, la zancada es 1 * 4 = 4. Esto nos da el último valor en strides = (10,2,5,1)*a.itemsize = (40,8,20,4).

Comenzando en el 1 de nuevo, para llegar a la 6 (es decir blocks[0,0,1,0]), es de 5 (es decir w) artículos de distancia, por lo que el paso es 5 * 4 = 20. Esto explica el segundo al último valor en strides.

Comenzando en el 1 una vez más, para llegar a la 3 (es decir blocks[0,1,0,0]), es 2 (es decir bw) artículos de distancia, por lo que el paso es 2 * 4 = 8. Esto explica el segundo valor en strides.

Por último, a partir de la 1, para llegar a 11 (es decir blocks[1,0,0,0]), es de 10 (es decir w*bh) artículos de distancia, por lo que el paso es de 10 * 4 = 40. Así strides = (40,8,20,4).

+1

Gracias. Parece que nuestro a.itemsize difiere (el mío es 8). Refactoreé tu código para usar una fórmula (según tu explicación) para definir los avances, de modo que funcionará para todos. – Cerin

5

Utilizando la respuesta de @ unutbu como ejemplo, escribí una función que implementa este truco de mosaico para cualquier matriz ND. Vea a continuación el enlace a la fuente.

>>> a = numpy.arange(1,21).reshape(4,5) 

>>> print a 
[[ 1 2 3 4 5] 
[ 6 7 8 9 10] 
[11 12 13 14 15] 
[16 17 18 19 20]] 

>>> blocks = blockwise_view(a, blockshape=(2,2), require_aligned_blocks=False) 

>>> print blocks 
[[[[ 1 2] 
    [ 6 7]] 

    [[ 3 4] 
    [ 8 9]]] 


[[[11 12] 
    [16 17]] 

    [[13 14] 
    [18 19]]]] 

[blockwise_view.py][test_blockwise_view.py]

1

scikit-image tiene una función llamada view_as_blocks() que hace casi lo que necesita. El único problema es que tiene un extra assert que prohíbe su caso de uso, ya que sus bloques no se dividen de manera uniforme en la forma de su matriz. Pero en su caso, el assert no es necesario, por lo que puede copiar el function source code y eliminar con seguridad el molesto afirmarse usted mismo.

Cuestiones relacionadas