Протокол буфера Python нового стиля и массивы numpy

Я пытаюсь написать быстрый интерфейс без копирования для моей привязки python к коммерческой библиотеке обработки изображений. Я реализовал протокол api буфера нового стиля, который выглядит нормально в соответствии с memoryview():

import hirsch as H
import numpy as np

w,h = 7,5
img = H.HImage.GenImageConst('byte',w,h)
m = memoryview(img)
print 'ndim shape=',m.ndim,m.shape
# -> 2 (5L, 7L)

Чего я не понимаю, так это почему numpy не улавливает этот интерфейс?

a = np.array(img)
print 'ndim size shape=',a.ndim,a.size,a.shape
# -> 0 1 ()

Я делаю что-то не так, или я должен просто прибегнуть к использованию интерфейса массива numpy, который работает, хотя и копирует данные?

Обратите внимание, что я использую Python 2.7.


person Dov Grobgeld    schedule 17.08.2014    source источник
comment
Возможно, происходит что-то удивительное --- но трудно сказать, что именно, не зная, что находится в вашей реализации bf_getbuffer и bf_releasebuffer. Предполагается, что новый интерфейс буфера будет работать и на Python 2.x (действительно: np.array(memoryview('asd')) == np.array([ 97, 115, 100], dtype=np.uint8). (Обратите также внимание, что интерфейсу массива Numpy не нужно копировать данные.)   -  person pv.    schedule 17.08.2014


Ответы (2)


Функция np.array ожидает объект подобный массиву, а не буфер:

array(object, dtype=None, copy=True, order=None, subok=False, ndmin=0)

Создайте массив.

object : array_like
Массив, любой объект, предоставляющий интерфейс массива, объект, метод __array__ которого возвращает массив, или любая (вложенная) последовательность.

Если вы хотите создать массив из буфера, вы должны использовать np.frombuffer:

frombuffer(buffer, dtype=float, count=-1, offset=0)

Интерпретируйте буфер как одномерный массив.

buffer : buffer_like
Объект, предоставляющий интерфейс буфера.

В настоящее время ваш объект, что касается numpy, является скаляром:

In [7]: a=np.array(1)

In [8]: a.ndim,a.size,a.shape
Out[8]: (0, 1, ())
person Bakuriu    schedule 17.08.2014
comment
Если новый буфер является стандартным интерфейсом Python, я удивлен, что массив np его не поддерживает! Я выяснил, что для преобразования можно использовать следующую строку: a = np.frombuffer(m.tobytes(),{'i8':'i1'}[m.format]).reshape(m.shape). Но это также включает копирование в m.tobytes(). - person Dov Grobgeld; 17.08.2014
comment
Новый интерфейс буфера поддерживается также в np.array: np.array(memoryview(np.array([1,2,3]))).shape == (3,). Причина различия может заключаться в реализации getbuffer пользовательского объекта... - person pv.; 17.08.2014
comment
Я заставил его работать в конце концов. Одна проблема, которая меня смутила, заключается в том, что вам нужно использовать аргумент copy=False для np.array(), чтобы получить ссылку на ту же память. - person Dov Grobgeld; 25.08.2014

Вы также можете попробовать np.asarray. Мне это удалось, но у меня нет доступа к hirsch, поэтому я не могу его протестировать.

Кстати, Бакуриу прав: вы создаете скалярный массив (ndim 0, размер 1) типа np.object.

person Pierre de Buyl    schedule 17.08.2014