Инвертированная структура массива

#python #arrays #numpy #numpy-ndarray

Вопрос:

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

Так что для двух кадров видео 2х2 я бы хотел

 [
  [
    [a1, a2, a3], [b1, b2, b3]
  ],
  [
    [c1, c2, c3], [d1, d2, d3]
  ]
]
 

стать

 [
 [
  [a1, b1],
  [c1, d1]
 ],
 [
  [a2, b2],
  [c2, d2]
 ],
 [
  [a3, b3],
  [c3, d3]
 ],
]
 

Моя текущая реализация заключается в следующем:

 def remap_image(seq):
    # seq = np.array(seq)
    s = seq.shape
    a = np.zeros((s[2], s[0], s[1]))

    for x, px in enumerate(tqdm(seq)):
        for y, py in enumerate(px):
            for p_counter, value in enumerate(py):
                a[p_counter][x][y] = value/100.
    return a
 

Это работает как задумано, однако этот подход невероятно медленный. Есть ли какой-нибудь более быстрый способ сделать это?

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

1. Похоже, у вас есть (2,2,3) форма, и вы хотите перенести ее в (3,2,2)

2. seq.transpose(2, 0, 1)

3. @MateenUlhaq работает отлично, спасибо!

Ответ №1:

Вы можете использовать einops с лучшей семантикой. В вашем случае работает следующий простой код.

 from einops import rearrange

def remap_image(seq):
    return rearrange(seq, 'w h t -> t w h')
 

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

1. Классная упаковка. Очевидно, я снимался в ней, но после этого никогда не использовал ее. В конце концов, это дополнительная зависимость.

Ответ №2:

Следуя тому, что сказал Матин Ульхак, просто

 def remap_image(seq):
    return seq.transpose(2, 0, 1)
    
 

Ответ №3:

Я не уверен, что это будет намного быстрее, но вы могли бы использовать zip():

 a = [
  [
    ["a1", "a2", "a3"], ["b1", "b2", "b3"]
  ],
  [
    ["c1", "c2", "c3"], ["d1", "d2", "d3"]
  ]
]

b = (list(map(list,zip(*r))) for r in a)
b = list(map(list,zip(*b)))

print(b)

[
 [
    ['a1', 'b1'],
    ['c1', 'd1']
 ],
 [
    ['a2', 'b2'],
    ['c2', 'd2']
 ],
 [
    ['a3', 'b3'],
    ['c3', 'd3']
 ]
]
 

Если ваши данные находятся в массиве numpy, то b = np.transpose(a,axes=(2,0,1)) сделайте это напрямую и очень быстро.