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

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

Я пытаюсь нарисовать в GDK (на самом деле pygtk) pixbuf с Каиром (на самом деле 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-й. Я могу сделать это в простом Python:

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

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

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]]
Другие вопросы по тегам