самый быстрый способ получить индексы таблицы поиска с помощью numpy

Этот вопрос следует за этим другим и целями при ускорении следующего кода. Я создал (с помощью) некоторый код, который берет значения пикселей из m x n x 3 numpy.ndarray (изображение RGB), сравнивает значения пикселей со значениями (позиционного ) таблицы поиска и выводит значения пикселей индексы таблицы поиска следующим образом:

img = np.random.randint(0, 9 , (3, 3, 3))
lut2 = img[0,0:2,:]

output = []
for x in xrange(lut2.shape[0]):
    if lut2[x] in img:
            output.append(np.concatenate(np.where( (img == lut2[x]).sum(axis=2) == 3 )))

print np.array(output)

выход :

[[0 0]
 [0 1]]

ошибка: не будет правильно выводиться, если вы получаете lut[x] более чем в одном месте в img. Возможно, лучшей стратегией было бы отформатировать вывод как вложенный список, так как подойдет все, что можно индексировать. Например:

[[x_px1, y_px1], [[x_px2a, y_px2a], [x_px2b, y_px2b]]]

где px2a и px2b — отдельные пиксели в img, имеющие одинаковое значение цвета.

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

Может ли кто-нибудь указать мне более быстрое решение?


Изменить: краткое изложение алгоритма идеального будущего, к которому я стремлюсь:

  an image               all pixels replaced          all indices are
  (here, single ----->   by index in lut     ----->   reused in digital_scale
  black pixel)           (here, first pixel)          to output an array of scalars

  [[[0, 0, 0]]]          [[[0, 0]]]                   [[0]]

  array shape:           array shape:                 array shape:

  m X n X 3              m X n X 2                    m X n

Последний массив m X n будет использоваться для двух вещей:

  • отображать данные на другом временном интервале, сохраняя массивы в базе данных.
  • сделать статистический анализ изменений в массиве из-за каких-то внешних событий

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


Некоторые (необязательные) запрошенные точности в отношении цели моего кода:

Таблица поиска обычно основана на значениях пикселей, а не на положении. В этом случае, однако, позиция была бы лучше (я думаю). Массив lut в приведенном выше коде является фиктивным для линейной цветовой шкалы, представляющей скорость, которую мне нужно оцифровать, как показано ниже:

линейная цветовая шкала

Поскольку каждый уровень шкалы представляет собой однородный цвет, шкалу фактически можно свести к массиву размерностей 1 X height X 3 (для RGB, HSV и т. д.). На самом деле я могу отбросить первое измерение и перебрать массив из height X 3. Вещи, которые я использую для оцифровки масштаба:

  • он сосредоточен вокруг нуля
  • это симметрично
  • это линейно
  • известны максимальное и минимальное значения

Следовательно, цифровое представление этой шкалы будет:

digital_scale = np.linspace(-max_speed, max_speed, lut.shape[0])

Мне нужно только получить индекс y значения пикселя, которое я ищу в lut, а затем yth элемент digital_scale для вывода нужного мне значения (скаляр, см. сводку алгоритма выше).


person Raoul    schedule 03.08.2014    source источник
comment
Каков фактический результат, который вы хотите (то есть, конечно, вы хотите получить данные в каком-то формате массива, а не распечатывать их)? Что именно ты пытаешься сделать? LUT обычно является функцией значений изображения, а не индексов.   -  person YXD    schedule 04.08.2014
comment
Вам нужен конечный вывод в виде ndarray, может что-то другое? Если для уровня LUT более одного пикселя, как выглядит этот вывод? В целях тестирования вы можете использовать np.random.seed(1); img = np.random.randint(0, 9 , (3, 3, 3)); img[1, 0, :] = img[0,0,:].   -  person wwii    schedule 04.08.2014
comment
@wwii Спасибо за интерес. Вывод в виде ndarray был бы предпочтительнее, но я мог обойтись чем угодно, что я мог проиндексировать, например, списком. Причина этого в том, что я хочу использовать индекс для получения соответствующего элемента digital_scale, который будет моим окончательным результатом (см. правки выше). Да, может быть более 1 пикселя для любого уровня LUT (вещь, на которой мой код терпит неудачу, см. ошибку, упомянутую выше, и я хотел бы, чтобы вывод был вложенным списком или массивом для таких случаев.   -  person Raoul    schedule 04.08.2014


Ответы (1)


Вы можете использовать Kd-tree, вот демо:

import numpy as np
from scipy import spatial

H, W = 200, 100

np.random.seed(1)
a = np.random.randint(0, 20, (H, W, 3))
b = np.random.randint(0, 20, (20, 3))
tree = spatial.cKDTree(a.reshape(-1, 3))
res = tree.query_ball_point(b, 0.5, p=1)
print res

вывод:

[[] [577, 17471] [14636, 4515, 13693, 10988, 15013] [16935, 8576, 13286]
 [2443] [7743, 5914] [] [7469, 19736, 13395, 14992, 9083, 15514]
 [1167, 11416] [3903, 4968] [16504, 2996, 10805, 2264] [] [6725]
 [14437, 5888] [17667] [4681, 2545, 6442] [15067, 4533]
 [7876, 2235, 10152, 3288] [15404, 5691, 17216]
 [15586, 9916, 16938, 15931, 4828, 4069]]

проверить результат индекса 2:

rows, cols = np.where(np.all(a == b[None, None, 2], axis=-1))
assert np.all(rows * W + cols == sorted(res[2]))
person HYRY    schedule 04.08.2014
comment
То, что это делает, кажется чрезвычайно сложным. Я понимаю результат, но не внутренности, даже при чтении документации. Я попробую это как можно скорее (все еще на этой неделе)! Спасибо за ваш ответ :-) - person Raoul; 04.08.2014