Большое спасибо за этот пост и за то, что следил за ним.Я основательно основываюсь на вашей векторизации, чтобы повысить скорость (по крайней мере, с данными, с которыми я работаю)!
Я работаю с корреляцией изображений, и поэтому я интерполирую множество наборовразличных координат в одном и том же input_array .
К сожалению, я сделал это немного сложнее, но если я смогу объяснить, что я сделал, дополнительное усложнение должно а) оправдать себя и b) стало ясно.Ваша последняя строка ( output = ) по-прежнему требует значительного количества поиска в непоследовательных местах в input_array , что делает ее относительно медленной.
Предположим, мой 3Dданные имеют длину NxMxP.Я решил сделать следующее: если я могу получить (8 x (NxMxP)) матрицу предварительно вычисленных значений серого для точки и ее ближайших соседей, и я также могу вычислить ((NxMxP) X 8) матрицукоэффициенты (ваш первый коэффициент в приведенном выше примере равен (x-1) (y-1) (z-1)), тогда я могу просто умножить их вместе и остаться дома бесплатно!
Хороший бонус для меня - эточто я могу предварительно рассчитать серую матрицу и переработать ее!
Вот пример кода (вставленный из двух разных функций, поэтому может не работать из коробки, но должен послужить хорошим источником вдохновения):
def trilinear_interpolator_speedup( input_array, coords ):
input_array_precut_2x2x2 = numpy.zeros( (input_array.shape[0]-1, input_array.shape[1]-1, input_array.shape[2]-1, 8 ), dtype=DATA_DTYPE )
input_array_precut_2x2x2[ :, :, :, 0 ] = input_array[ 0:new_dimension-1, 0:new_dimension-1, 0:new_dimension-1 ]
input_array_precut_2x2x2[ :, :, :, 1 ] = input_array[ 1:new_dimension , 0:new_dimension-1, 0:new_dimension-1 ]
input_array_precut_2x2x2[ :, :, :, 2 ] = input_array[ 0:new_dimension-1, 1:new_dimension , 0:new_dimension-1 ]
input_array_precut_2x2x2[ :, :, :, 3 ] = input_array[ 0:new_dimension-1, 0:new_dimension-1, 1:new_dimension ]
input_array_precut_2x2x2[ :, :, :, 4 ] = input_array[ 1:new_dimension , 0:new_dimension-1, 1:new_dimension ]
input_array_precut_2x2x2[ :, :, :, 5 ] = input_array[ 0:new_dimension-1, 1:new_dimension , 1:new_dimension ]
input_array_precut_2x2x2[ :, :, :, 6 ] = input_array[ 1:new_dimension , 1:new_dimension , 0:new_dimension-1 ]
input_array_precut_2x2x2[ :, :, :, 7 ] = input_array[ 1:new_dimension , 1:new_dimension , 1:new_dimension ]
# adapted from from /5259470/3d-interpolyatsiya-massivov-numpy-bez-scipy
# 2012.03.02 - heavy modifications, to vectorise the final calculation... it is now superfast.
# - the checks are now removed in order to go faster...
# IMPORTANT: Input array is a pre-split, 8xNxMxO array.
# input coords could contain indexes at non-integer values (it's kind of the idea), whereas the coords_0 and coords_1 are integer values.
if coords.max() > min(input_array.shape[0:3])-1 or coords.min() < 0:
# do some checks to bring back the extremeties
# Could check each parameter in x y and z separately, but I know I get cubic data...
coords[numpy.where(coords>min(input_array.shape[0:3])-1)] = min(input_array.shape[0:3])-1
coords[numpy.where(coords<0 )] = 0
# for NxNxN data, coords[0].shape = N^3
output_array = numpy.zeros( coords[0].shape, dtype=DATA_DTYPE )
# a big array to hold all the coefficients for the trilinear interpolation
all_coeffs = numpy.zeros( (8,coords.shape[1]), dtype=DATA_DTYPE )
# the "floored" coordinates x, y, z
coords_0 = coords.astype(numpy.integer)
# all the above + 1 - these define the top left and bottom right (highest and lowest coordinates)
coords_1 = coords_0 + 1
# make the input coordinates "local"
coords = coords - coords_0
# Calculate one minus these values, in order to be able to do a one-shot calculation
# of the coefficients.
one_minus_coords = 1 - coords
# calculate those coefficients.
all_coeffs[0] = (one_minus_coords[0])*(one_minus_coords[1])*(one_minus_coords[2])
all_coeffs[1] = (coords[0]) *(one_minus_coords[1])*(one_minus_coords[2])
all_coeffs[2] = (one_minus_coords[0])* (coords[1]) *(one_minus_coords[2])
all_coeffs[3] = (one_minus_coords[0])*(one_minus_coords[1])* (coords[2])
all_coeffs[4] = (coords[0]) *(one_minus_coords[1])* (coords[2])
all_coeffs[5] = (one_minus_coords[0])* (coords[1]) * (coords[2])
all_coeffs[6] = (coords[0]) * (coords[1]) *(one_minus_coords[2])
all_coeffs[7] = (coords[0]) * (coords[1]) * (coords[2])
# multiply 8 greyscale values * 8 coefficients, and sum them across the "8 coefficients" direction
output_array = ( input_array[ coords_0[0], coords_0[1], coords_0[2] ].T * all_coeffs ).sum( axis=0 )
# and return it...
return output_array
Я не разделял координаты xy и z, как указано выше, потому что не представляется полезным их впоследствии объединять.В приведенном выше коде может быть что-то, что предполагает кубические данные (N = M = P), но я так не думаю ...
Дайте мне знать, что вы думаете!