2013-08-15 2 views
2

Я ищу эффективный способ выполнения операций надматрицы над большей матрицей, не прибегая к циклам.Операции с подматрицей Numpy

Я в настоящее время делают операцию (для окна 3х3):

newMatrix = numpy.zeros([numRows, numCols]) 
for i in range(1, numRows-1): 
    for j in range(1, numCols-1): 
     sub = matrix[i-1:i+2, j-1:j+2] 
     newMatrix[i][j] = ... #do things with sub matrix 

Это значительно медленнее, чем обычные операции с Numpy матрицами. Есть ли что-нибудь, что может предложить numpy, чтобы решить это, или это слишком много надеется?

Edit: Конкретный пример

xWeight = numpy.array([[-1./8, 0, 1./8], [-2./8, 0, 2./8], [-1./8, 0, 1./8]]) 
yWeight = numpy.array([[1./8, 2./8, 1./8], [0, 0, 0], [-1./8, -2./8, -1./8]]) 

Внутри цикла:

 dz_dx = numpy.sum(xWeight * sub) 
     dz_dy = numpy.sum(yWeight * sub) 
+2

Вы пытаетесь выполнить обработку изображений с помощью numpy? – Jiminion

+0

Является ли это 'matrix' на строке 4, которая должна быть' newMatrix'? – Brionius

+3

Что именно вы делаете в «делать вещи с подматрицей»? Если вы не укажете, что вы делаете, мы не сможем вам векторизовать ваш код. –

ответ

2

Мне кажется, что вы пытаетесь сделать простую свертку?

def do(m): 
    rows, cols = m.shape 
    newMatrix = np.zeros_like(m) 
    for i in range(1, rows-1): 
     for j in range(1, cols-1): 
      sub = matrix[i-1:i+2, j-1:j+2] 
      newMatrix[i][j] = numpy.sum(xWeight * sub) 
    return newMatrix[1:-1, 1:-1] 
>>> res1 = do(matrix) 
>>> res2 = scipy.signal.convolve2d(matrix, xWeight)[2:-2,2:-2] 
>>> np.allclose(np.abs(res1), np.abs(res2)) 
True 

Не вдавался в подробности о знаке, но это, надеюсь, положит вас на правильный путь.

+0

Это похоже на более аккуратное решение для этой конкретной проблемы. –

0

Кажется, вы можете использовать np.ix_, см. этот пример е from the documentation:

a = np.arange(10).reshape(2, 5) 
#array([[0, 1, 2, 3, 4], 
#  [5, 6, 7, 8, 9]]) 

ixgrid = np.ix_([0,1], [2,4]) 

a[ixgrid] 
#array([[2, 4], 
#  [7, 9]]) 
2

Я нашел решение в numpy.lib.stride_tricks

from numpy.lib.stride_tricks import as_strided 

В методе:

expansion = stride.as_strided(matrix, shape = (numRows-2, numCols-2, 3, 3), strides = matrix.strides * 2) 
    xWeight = numpy.array([[-1./8, 0, 1./8], [-2./8, 0, 2./8], [-1./8, 0, 1./8]]) 
    yWeight = numpy.array([[1./8, 2./8, 1./8], [0, 0, 0], [-1./8, -2./8, -1./8]]) 

    dx = xWeight * expansion 
    dy = yWeight * expansion 

    dx = numpy.sum(numpy.sum(dx, axis=3), axis=2) 
    dy = numpy.sum(numpy.sum(dy, axis=3), axis=2) 

Там вполне может быть лучшим решением, но это достаточно простой и общей цели для меня. Это проходило через матрицу 1600x1200 за 3,41 секунды, а за 188,47 секунды - для циклов.

(Вы можете предложить сказал лучшее решение, если есть)