Максимум среза массива, который зависит от индекса предыдущей оси

Итак, у меня есть большой 2D-массив, полученный из изображения в формате TIFF, в котором я хочу вычислить центр масс. Для этого я использую индексы изображения (в качестве координат) и среднюю функцию:

from PIL import Image
from numpy import *

Im    = Image.open("32bit_grayscale.tif")
imArr = array(Im, dtype='float32')
indx  = indices(imArr.shape)

cenMassX = average(indx[0,:,:],weights=imArr[:,:])
cenMassY = average(indx[1,:,:],weights=imArr[:,:])

На некоторых других подобных изображениях есть два отдельных центра масс, которые я хочу рассчитать. Обе области расчета разделены прямой наклонной линией, уравнение которой у меня есть.

Я хотел бы снова использовать метод average, так как он очень эффективен, но мне нужно было бы установить максимум среза второй оси массива indx в функцию текущего значения первой оси. Если бы строка была чем-то вроде y=slope*x+interY, мне нужно было бы что-то вроде этого:

cenMassX_A = average(indx[0,:,:slope*row+interY],weights=imArr[:,:slope*row+interY])
cenMassY_A = average(indx[1,:,:slope*row+interY],weights=imArr[:,:slope*row+interY])
cenMassX_B = average(indx[0,:,slope*row+interY:],weights=imArr[:,slope*row+interY:])
cenMassY_B = average(indx[1,:,slope*row+interY:],weights=imArr[:,slope*row+interY:])

Где row представляет текущее значение индекса первой оси (ось «x»). Не обращайте внимания на тот факт, что я могу выйти за пределы массива в зависимости от уравнения.

Я могу сделать это, используя циклы for, но это очень неэффективно (в 20 раз) и не очень "питоново":

cenMassX_A = 0
cenMassY_A = 0
cumSum     = 0
for row in range(0,imArr.shape[0]):
    for col in range(0,int(round(slope*row+interY))):
        cenMassX_A += row*imArr[row,col]
        cenMassY_A += col*imArr[row,col]
        cumSum     += imArr[row,col]
cenMassX_A /= cumSum
cenMassY_A /= cumSum

cenMassX_B = 0
cenMassY_B = 0
cumSum     = 0
for row in range(0,imArr.shape[0]):
    for col in range(int(round(slope*row+interY)),imArr.shape[1]):
        cenMassX_B += row*imArr[row,col]
        cenMassY_B += col*imArr[row,col]
        cumSum     += imArr[row,col]
cenMassX_B /= cumSum
cenMassY_B /= cumSum

Итак, есть ли способ сделать это, или я застрял с for циклами? Я читал о масках и скользящих окнах, но до сих пор не могу найти решение. Заранее спасибо!


person viloflo    schedule 06.03.2014    source источник


Ответы (2)


Что произойдет, если вы установите imArr[i,j]=0 для всех точек с одной или другой стороны вашей линии? Это самый простой способ маскировки.

I = indx[0,...]*slope + indx[1,...]>=M
imArr1 = imArr.copy()
imArr1[I]=0
print np.average(indx[0,...],weights=imArr1)
print np.average(indx[1,...],weights=imArr1)

imArr1 = imArr.copy()
imArr1[~I]=0

print np.average(indx[0,...],weights=imArr1)
print np.average(indx[1,...],weights=imArr1)

Это отлично работает, если я беру простое «изображение» и соединяю его с собой (по горизонтали или диагонали).

person hpaulj    schedule 06.03.2014
comment
Проверил, это было отлично и очень быстро, в 40 раз. Это была одна из моих идей, но я не смог понять, как работают маски. Однако я считаю, что в определении I должно быть изменение знака, а также, для согласованности, M равно interY, поэтому: I = -indx[0,...]*slope + indx[1,...]>=interY. Я отредактирую ваш пост. - person viloflo; 07.03.2014

Почему бы вам не использовать код, который вы написали:

cenMassX_A = average(indx[0,:,:slope*row+interY],weights=inArr[:,:slope*row+interY])
cenMassY_A = average(indx[1,:,:slope*row+interY],weights=inArr[:,:slope*row+interY])

и применить его построчно?

Сохраните циклы for над строками, но замените циклы col этим кодом (изменив индекс строки со всех строк на только один в цикле for). И, конечно, вам еще нужно сложить результаты из строк вместе.

person w-m    schedule 06.03.2014
comment
Это работает и повышает производительность, но я все еще хочу избавиться от всех циклов for - person viloflo; 07.03.2014