Поменять подмассивы массива 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]]