Поменять местами подмассивы массива numpy

Сначала немного контекста.

Я пытаюсь рисовать в Gdk (на самом деле pygtk) pixbuf с Cairo (на самом деле pycairo). Мой исходный код выглядел так:

import cairo as C
import gtk.gdk as GG

FMT = C.FORMAT_ARGB32
CSP = GG.COLORSPACE_RGB

st = C.ImageSurface.format_stride_for_width(FMT, zw)
surf = C.ImageSurface(FMT, zw, zh)
c = C.Context(surf)

# draw into c here ...

pixels = surf.get_data()
return GG.pixbuf_new_from_data(pixels, CSP, True, 8, zw, zh, st)

Какое-то время казалось, что это сработает, пока я не попытался рисовать цвета вместо простого черного текста. Оказывается, две библиотеки расходятся в порядке байтов, например:

# !!! FIXME !!! cairo ARGB surfaces and gdk pixbufs disagree on bytesex:
# cairo: LSB --> B G R A <-- MSB
# gdk:   LSB --> R G B A <-- MSB
# !!! WTF !!!

В результате (после переноса из pixbuf на экран) изображение с поменявшимися местами красного и синего каналов :-(

Итак, если я продолжаю использовать pixbufs (как я хочу), мне нужно выполнить постобработку данных, заменяя каждый 1-й байт каждым 3-м. Я могу сделать это на простом питоне:

def changesex(data):
    i0 = 0
    i2 = 2
    l = len(data)
    while i2 < l:
        temp = data[i0]
        data[i0] = data[i2]
        data[i2] = temp
        i0 += 4
        i2 += 4

но я подумал, что использование numpy может быть быстрее, если для этого есть встроенный оператор, написанный на C. Что-то вроде этого:

a = np.frombuffer(data, dtype=np.uint8)
a.shape = (len(data) / 4, 4)
temp = a[:,0]
a[:,0] = a[:,2]
a[:,2] = temp

Я просто мечтаю?


person BehemothTheCat    schedule 02.10.2012    source источник


Ответы (1)


Отметив a ваш начальный массив (N,4) из B,G,R,A, вы можете получить представление (N,4) как R,G,B,A, а просто используя расширенную индексацию:

a = np.frombuffer(data, dtype=np.uint8)
a.shape = (-1, 4)
rearranged = a[:,[2,1,0,3]]
person Pierre GM    schedule 03.10.2012
comment
Да, я нашел это сам, сочетая пробную ошибку и ответы на подобные вопросы здесь. Спасибо хоть! - person BehemothTheCat; 04.10.2012
comment
для меня перестановка = a[:,:,[2,1,0,3]] работала без дополнительной команды shape - person Oliver Zendel; 17.03.2017
comment
Кроме того, rearranged = a[...,[2,1,0,3]] должен работать для любого количества осей (например, для пакетного обучения или чего-то в этом роде). - person Poik; 29.05.2018