2012-02-23 4 views
9

Я попытался воспроизвести основное узкое место в одной из моих программ.Ускорение линейной интерполяции многих местоположений пикселей в NumPy

Я хочу получить значения linearly (or rather bilinearly) interpolated нескольких нецелых значений пикселей одновременно. Это не случай, когда каждая пиксельная координата возмущена таким же образом. Ниже приведен полный/минимальный сценарий вместе с комментариями, которые демонстрируют проблему. Как я могу ускорить вычисление result?

import numpy as np 
import time 

im = np.random.rand(640,480,3) # my "image" 
xx, yy = np.meshgrid(np.arange(im.shape[1]), np.arange(im.shape[0])) 
print "Check these are the right indices:",np.sum(im - im[yy,xx,:]) 

# perturb the indices slightly 
# I want to calculate the interpolated 
# values of "im" at these locations 
xx = xx + np.random.normal(size=im.shape[:2]) 
yy = yy + np.random.normal(size=im.shape[:2]) 

# integer value/pixel locations 
x_0 = np.int_(np.modf(xx)[1]) 
y_0 = np.int_(np.modf(yy)[1]) 
x_1, y_1 = x_0 + 1, y_0 + 1 

# the real-valued offsets/coefficients pixels 
a = np.modf(xx)[0][:,:,np.newaxis] 
b = np.modf(yy)[0][:,:,np.newaxis] 

# make sure we don't go out of bounds at edge pixels 
np.clip(x_0,0,im.shape[1]-1,out=x_0) 
np.clip(x_1,0,im.shape[1]-1,out=x_1) 
np.clip(y_0,0,im.shape[0]-1,out=y_0) 
np.clip(y_1,0,im.shape[0]-1,out=y_1) 

# now perform linear interpolation: THIS IS THE BOTTLENECK! 
tic = time.time() 
result = ((1-a) * (1-b) * im[y_0, x_0, :] + 
      a * (1-b) * im[y_1, x_0, :] + 
      (1-a) * b * im[y_0, x_1, :] + 
      a * b * im[y_1, x_1, :]) 
toc = time.time() 

print "interpolation time:",toc-tic 
+2

Любая причина, почему вы избегаете 'scipy.ndimage.map_coordinates'? (Например, желая избежать зависимости от scipy.ndimage?) Если нет, это функция, которую вы хотите. –

+0

@JoeKington Я не знал об этом - позвольте мне посмотреть, могу ли я использовать эту функцию, и если она быстрее. Благодарю. – YXD

ответ

4

Спасибо @JoeKington за предложение. Вот лучшее, что я могу придумать с помощью scipy.ndimage.map_coordinates

# rest as before 
from scipy import ndimage 
tic = time.time() 
new_result = np.zeros(im.shape) 
coords = np.array([yy,xx,np.zeros(im.shape[:2])]) 
for d in range(im.shape[2]): 
    new_result[:,:,d] = ndimage.map_coordinates(im,coords,order=1) 
    coords[2] += 1 
toc = time.time() 
print "interpolation time:",toc-tic 

Update: Добавлены твики предложенные в комментариях и попробовал одну или две другие вещи. Это самый быстрый вариант:

tic = time.time() 
new_result = np.zeros(im.shape) 
coords = np.array([yy,xx]) 
for d in range(im.shape[2]): 
    ndimage.map_coordinates(im[:,:,d], 
          coords,order=1, 
          prefilter=False, 
          output=new_result[:,:,d]) 
toc = time.time() 

print "interpolation time:",toc-tic 

Пример Время работы:

original version: 0.463063955307 
    better version: 0.204537153244 
    best version: 0.121845006943 
+0

Извините, я не опубликовал пример раньше. Вовремя бежал. Рад, что вы поняли! Вы можете сделать это одним вызовом 'map_coordinates', но в зависимости от размера вашего изображения повторение через каждую группу, вероятно, является лучшим вариантом. Хранение временного 3D-массива координат съедает много барана. Вы можете немного ускорить работу, если вы только проходите в одной группе за раз, чтобы «map_coordinates». Это также позволило бы пропустить массив нулей в 'coords'. –

+1

Кроме того, в случае билинейной интерполяции вы можете немного сохранить память и немного ускорить работу, если вы укажете 'prefilter = False'. С небольшим изображением вы не заметите разницы, но с большими изображениями он избегает создания дополнительной копии в памяти. –

Смежные вопросы