Буферен протокол на 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