-->

如何通过一个numpy的阵列到CFFI功能以及如何一回呢?(How to pass a Numpy

2019-09-01 08:21发布

我正在开发使用Python和NumPy的音频算法。 现在,我想加快通过实施它在C.一部分。在过去那种算法, 我已经做到了这一点用用Cython 。 现在我想用新的做同样的事情CFFI 。

出于测试目的,我写了一个简单的C函数:

void copy(float *in, float *out, int len) {
    for (int i=0; i<len; i++) {
        out[i] = in[i];
    }
}

现在我想创建两个numpy的阵列和那些有此功能进行处理。 我想出了一个办法做到这一点:

import numpy as np
from cffi import FFI

ffi = FFI()
ffi.cdef("void copy(float *in, float *out, int len);")
C = ffi.dlopen("/path/to/copy.dll")

float_in = ffi.new("float[16]")
float_out = ffi.new("float[16]")

arr_in = 42*np.ones(16, dtype=np.float32)

float_in[0:16] = arr_in[0:16]
C.copy(float_in, float_out, 16)
arr_out = np.frombuffer(ffi.buffer(float_out, 16*4), dtype=np.float32)

不过,我想提高这个代码:

  1. 有没有办法直接访问numpy的阵列的基本浮动缓冲区无需将其复制?
  2. ffi.buffer是快速转换为C数组的内容到一个numpy的阵列很方便。 是否有快速转换numpy的阵列到C数组不复制单个元素的等价方式?
  3. 对于一些应用, float_in[0:16] = arr_in[0:16]是访问数据的一种方便的方式。 相反, arr_out[0:16] = float_out[0:16]不然而工作。 为什么不?

Answer 1:

所述ctypes ndarray的属性可以与ctypes的模块进行交互,例如, ndarray.ctypes.data是阵列的数据地址,就可以将它转换为一个float *指针,然后传递指针C函数。

import numpy as np
from cffi import FFI

ffi = FFI()
ffi.cdef("void copy(float *in, float *out, int len);")
C = ffi.dlopen("ccode.dll")

a = 42*np.ones(16, dtype=np.float32)
b = np.zeros_like(a)
pa = ffi.cast("float *", a.ctypes.data)
pb = ffi.cast("float *", b.ctypes.data)

C.copy(pa, pb, len(a))
print b

对于你的问题3:

我认为FFI阵列不提供numpy的必要的信息来访问它的内部缓冲。 因此numpy的尝试将其转换到失败的浮点数。

我认为最好的办法是将其转换第一个列表:

float_in[0:16] = list(arr_in[0:16])


Answer 2:

可以通过它来访问在numpy的数组中的数据的阵列接口:

import numpy as np
import cffi
ffi = cffi.FFI()

a = np.zeros(42)
data = a.__array_interface__['data'][0]
cptr = ffi.cast ( "double*" , data )

现在你有一个CFFI指针类型,您可以通过您的副本程序。 注意,这是一个基本的方法; numpy的阵列可能不包含其平面内存数据,因此,如果您ndarray的结构,你将不得不考虑它的形状和进步。 如果这一切都平平,不过,这已经足够了。



Answer 3:

的更新这样的:CFFI现代版本具有ffi.from_buffer()其中将任何缓冲对象(如numpy的阵列),以一个char * FFI指针。 现在,您可以直接做:

cptr = ffi.cast("float *", ffi.from_buffer(my_np_array))

或者直接作为参数传递给该呼叫(该char *自动浇铸到float * ):

C.copy(ffi.from_buffer(arr_in), ffi.from_buffer(arr_out), 16)


Answer 4:

之后你从CFFI平坦的结果数组,你也可以重塑通过这样numpy的进步给予了数组:

a=np.ones(24); a.shape = (2, 3, 4)

要么

a=np.ones(24); b = a.reshape(2, 3, 4)

例如,这是有益的,如果你想有嵌套的列表进行进一步蟒蛇处理(如在搅拌机sverchok插件)

更复杂的例子:

假设你想有顶点的名单,每3个漂浮的列表,并创建了一个CDATA float数组是这样的:

 cverts = ffi.new("float [][3]", nverts * num)

作为函数的输出参数,如:

lib.myfunction(... other input...., num, nverts, cverts)

切割绿党的这份名单为nverts绿党每个你可以做作为NUM子列表如下,则:

flat_size = 4 * 3 * nverts * num
verts = np.frombuffer(ffi.buffer(cverts, flat_size), dtype=np.float32)
verts.shape = (num, nverts, 3)
verts = verts.tolist()

绿党应该寻找例如像[[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]]然后。



文章来源: How to pass a Numpy array into a cffi function and how to get one back out?