Эффективный метод интерполяции тепловой карты

Я пишу программу, которая создает визуальное представление температуры. В сетке размещено 200 точек данных, и я использую интерполяцию, чтобы заполнить пиксели между этими точками.

Я написал программу, которая выводит нужные мне данные, используя обратное взвешивание по расстоянию (в данном случае модифицированный метод Шепарда), получая изображение, подобное показанному ниже:

тепловая карта

После вырезания всего ненужного (например, библиотеки изображений) код для его создания показан ниже:

Сначала рассчитываются все расстояния и суммарные расстояния от каждой точки до каждой трубы (поскольку они инвариантны). В этом фрагменте меня не особенно беспокоит время, потому что это делается только один раз, но я включаю код, чтобы вы могли видеть, как хранятся значения.

#set_tubes creates an array of tubes (which is the data I'm working on)
#each tube has an x position in pixels, a y position in pixels and a temperature

self.set_tubes()
self.dists = []
for x in range(1,BASE_WIDTH-1):
    self.summed_dists.append([])
    self.dists.append([])
    for y in range(1,BASE_HEIGHT-1):
        self.summed_dists[x-1].append([])
        self.dists[x-1].append([])
        self.summed_dists[x-1][y-1]=0
        for row in range(10):
            self.dists[x-1][y-1].append([])
            for tube in range(20):
                dist = np.sqrt((x-self.tubes[row][tube].xPos)**2+(y-self.tubes[row][tube].yPos)**2)+0.1
                #The -3 in the next two lines is simply a weighting factor
                self.dists[x-1][y-1][row].append(dist**(-3))
                self.summed_dists[x-1][y-1] = self.summed_dists[x-1][y-1] + dist**(-3)

Затем выполняется интерполяция (это делается неоднократно при изменении температуры). Это тот момент, когда имеет значение затраченное время.

def other_proc_calc_temp(ret_queue, dists, tubes,summed_dists):
    heat_values = list()
    for x in range (BASE_WIDTH):
        heat_values.append([])
        for y in range(BASE_HEIGHT):
            summed = 0
            for row in range(10):
                for tube in range(20):
                    dist = dists[x][y][row][tube]
                    temp = tubes[row][tube].temp
                    summed = summed + temp* dist/summed_dists[x-1][y-1]
            heat_values[x].append(summed)

Моя проблема связана со скоростью, для изображения размером 200 * 200 пикселей это занимает примерно 30 секунд, чтобы выполнить вторую часть кода на моем компьютере. Есть ли более быстрый способ получить такой же или похожий эффект или какую-то вопиющую неэффективность в моем коде?

Я пробовал билинейную и бикубическую интерполяцию, но не был особенно удовлетворен полученным изображением.

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

Спасибо за любую помощь, которую вы можете дать.


person MDT    schedule 19.01.2012    source источник
comment
Лучше всего посмотреть, можете ли вы использовать numpy для этого. В противном случае загляните в cython   -  person John La Rooy    schedule 19.01.2012


Ответы (1)


Есть одно изменение, которое может быть улучшением:

Попробуйте переместить dists[x][y] и tubes[row] за пределы самого внутреннего цикла. Это может выполнять несколько операций поиска индекса массива за внутреннюю итерацию (это зависит от того, насколько умен интерпретатор Python):

def other_proc_calc_temp(ret_queue, dists, tubes,summed_dists):
    heat_values = list()
    for x in range (BASE_WIDTH):
        heat_values.append([])
        for y in range(BASE_HEIGHT):
            outer_dist = dists[x][y]
            summed = 0
            for row in range(10):
                inner_dist = outer_dist[row]
                inner_tube = tubes[row]
                for tube in range(20):
                    dist = inner_dist[tube]
                    temp = inner_tubes[tube].temp
                    summed = summed + temp* dist/summed_dists[x-1][y-1]
            heat_values[x].append(summed)

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

Раньше у меня был абзац об установке размера массивов заранее, а не об увеличении их с помощью .append(). gnibbler говорит, что .append() является амортизируемой операцией O(1)< /a> что означает, что здесь, вероятно, мало оптимизации. Посмотрите историю изменений, если вам интересно, что я написал.

person sarnold    schedule 19.01.2012
comment
list.append() — амортизируемая операция O(1) - person John La Rooy; 19.01.2012
comment
@gnibbler: Спасибо. Я бы хотел, чтобы документация API для большего количества языков сделала эту информацию легкодоступной. Длинный и явно бессмысленный абзац удален. :) - person sarnold; 20.01.2012