Как добавить индексы (x, y) элементов массива (u, v), чтобы получить массив элементов (x,y, u, v)?

#python #arrays #numpy #opticalflow #4d

#python #массивы #numpy #opticalflow #4d

Вопрос:

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

Примеры:

Первый элемент равен [10,11], индекс равен [0,0] -> Становится [0,0,10,11]

Второй элемент равен [12,13], индекс равен [1,0] -> Становится [1,0,12,13]

Как я могу оптимизировать эту функцию? Есть ли более простой способ написать это? Любые улучшения / рекомендации будут оценены!

Мой проект: Я использую Optical Flow для получения массива величин (u, v), которые представляют компоненты вектора оптического потока каждого пикселя. Я хотел бы добавить положение (x, y) пикселей в массив, чтобы я получил массив (x, y, u, v). Примечание: позиция (x, y) совпадает со значением индекса, что немного упрощает задачу.

Вот мой код:

 def vec_4D (mag_2D):
    vec_4D = np.zeros((mag_2D.shape[0],mag_2D.shape[1],4))
    x = 0
    y = 0
    for row in vec_4D:
        for col in row:
            col[0] = x
            col[1] = y
            col[2] = mag_2D[y][x][0]
            col[3] = mag_2D[y][x][1]
            x  = 1
        x=0
        y =1
    return(vec_4D)

mag_2D = np.array([[[10,11], [12,13], [14,15]], [[16,17], [18,19], [20,21]]])
print(vec_4D(mag_2D))
  
 Input array: 

[[[10 11]
  [12 13]
  [14 15]]

 [[16 17]
  [18 19]
  [20 21]]]



Output array: 

[[[ 0.  0. 10. 11.]
  [ 1.  0. 12. 13.]
  [ 2.  0. 14. 15.]]

 [[ 0.  1. 16. 17.]
  [ 1.  1. 18. 19.]
  [ 2.  1. 20. 21.]]]

  

Ответ №1:

Здесь неизбежен один вкладыш.

 >>> np.concatenate([np.moveaxis(np.indices(mag_2D.shape[:-1]), 0, -1)[..., ::-1], mag_2D], -1)
array([[[ 0,  0, 10, 11],
        [ 1,  0, 12, 13],
        [ 2,  0, 14, 15]],

       [[ 0,  1, 16, 17],
        [ 1,  1, 18, 19],
        [ 2,  1, 20, 21]]])
  

Самый простой способ понять это — разбить его:

np.indices создает индексы из формы

 >>> np.indices(mag_2D.shape[:-1])
array([[[0, 0, 0],
        [1, 1, 1]],

       [[0, 1, 2],
        [0, 1, 2]]])
  

Они, однако, отдельные для каждого измерения. Чтобы получить координатные «кортежи», мы должны переместить начальную ось в конец:

 >>> np.moveaxis(np.indices(mag_2D.shape[:-1]), 0, -1)
array([[[0, 0],
        [0, 1],
        [0, 2]],

       [[1, 0],
        [1, 1],
        [1, 2]]])
  

Это y, x , OP хочет x, y

 >>> np.moveaxis(np.indices(mag_2D.shape[:-1]), 0, -1)[..., ::-1]
array([[[0, 0],
        [1, 0],
        [2, 0]],

       [[0, 1],
        [1, 1],
        [2, 1]]])
  

Комментарии:

1. Без объяснения, этот ответ, хотя и работает в этом случае, не имеет возможности для применения к другим проблемам. Однострочники модны, но без объяснения причин теряют свою ценность. Возможно, вы можете добавить несколько слов к своему ответу

2. @Bazingaa Ты действительно смотрел на это? Я бы сказал, что это довольно понятно, почти как обычный английский: «Объединить индексы для mag_2D (с перемещением их начальной оси в конец) с mag_2D самим собой».

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

4. @Bazingaa Хорошо, хорошо. Я добавил несколько строк объяснения.

Ответ №2:

Вот «многострочный», использующий np.indices() , и np.concatenate() :

 y_indices,x_indices = np.indices(mag_2D.shape[0:2])
vec_4D_result = np.concatenate((x_indices[:,:,None], 
                                y_indices[:,:,None], 
                                mag_2D[y_indices,x_indices]), axis = -1)
  

Тестирование:

 import numpy as np

mag_2D = np.array([[[10,11], [12,13], [14,15]], [[16,17], [18,19], [20,21]]])
y_indices,x_indices = np.indices(mag_2D.shape[0:2])
vec_4D_result = np.concatenate((x_indices[:,:,None], 
                                y_indices[:,:,None], 
                                mag_2D[y_indices,x_indices]), axis = -1)
print (vec_4D_result)
  

Вывод:

 [[[ 0  0 10 11]
  [ 1  0 12 13]
  [ 2  0 14 15]]

 [[ 0  1 16 17]
  [ 1  1 18 19]
  [ 2  1 20 21]]]
  

Комментарии:

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

Ответ №3:

Упрощенная версия вашего подхода к заполнению

 In [650]: arr = np.arange(10,22).reshape(2,3,2)  
In [658]: res = np.zeros((arr.shape[0],arr.shape[1],4),arr.dtype)               
In [659]: res[:,:,2:] = arr    
  

Следующий шаг потребовал немного проб и ошибок. Мы заполняем индексы с помощью broadcasting. Нам нужны массивы, которые могут транслировать в (2,3) первые 2 измерения res .

 In [660]: res[:,:,0] = np.arange(arr.shape[1])                                  
In [661]: res[:,:,1] = np.arange(arr.shape[0])[:,None]     # size 2 column                      
In [662]: res                                                                   
Out[662]: 
array([[[ 0,  0, 10, 11],
        [ 1,  0, 12, 13],
        [ 2,  0, 14, 15]],

       [[ 0,  1, 16, 17],
        [ 1,  1, 18, 19],
        [ 2,  1, 20, 21]]])