How to pass a Numpy array into a cffi function and how to get one back out?

你离开我真会死。 提交于 2019-11-28 19:14:24

The ctypes attribute of ndarray can interact with the ctypes module, for example, ndarray.ctypes.data is the data address of the array, you can cast it to a float * pointer, and then pass the pointer to the C function.

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

For your question 3:

I think ffi array doesn't provide numpy the necessary information to access it's inner buffer. So numpy try to convert it to a float number which failed.

The best solution I can thinks is convert it to list first:

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

the data in a numpy array can be accessed via it's array interface:

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

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

now you have a cffi pointer type, which you can pass to your copy routine. note that this is a basic approach; numpy arrays may not contain their data in flat memory, so if your ndarray is structured, you will have to consider it's shape and strides. If it's all flat, though, this is sufficient.

An update to this: modern versions of CFFI have ffi.from_buffer(), which turns any buffer object (like a numpy array) to a char * FFI pointer. You can now do directly:

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

or directly as arguments to the call (the char * is casted automatically to float *):

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

After you got a flat result array from cffi, you also could reshape the array with given strides via numpy like this:

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

or

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

This is for example helpful if you want to have nested lists for further python processing (like in blenders sverchok addon)

More complex example:

Say you want to have a list of lists of vertices with 3 floats each, and have created a cdata float array like this:

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

as output parameter for a function like:

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

Cutting this list of verts into num sub-lists of nverts verts each you could do as follows then:

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()

verts should look for example like [[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]] then.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!