How to convert pointer to c array to python array

前端 未结 1 1400
面向向阳花
面向向阳花 2020-12-02 15:01

I have a C++ callback function that calls into Python using ctypes. This function\'s parameters are a pointer to an array of double and the number of elements.

Ther

相关标签:
1条回答
  • 2020-12-02 15:36

    If Data were (c_double*DataLength.value) array then you could:

    a = np.frombuffer(Data) # no copy. Changes in `a` are reflected in `Data`
    

    If Data is a POINTER(c_double) you could get numpy array using numpy.fromiter(). It is the same loop as in your question but faster:

    a = np.fromiter(Data, dtype=np.float, count=DataLength.value) # copy
    

    To create a numpy array from POINTER(c_double) instance without copying you could use .from_address() method:

    ArrayType = ctypes.c_double*DataLength.value
    addr = ctypes.addressof(Data.contents)
    a = np.frombuffer(ArrayType.from_address(addr))
    

    Or

    array_pointer = ctypes.cast(Data, ctypes.POINTER(ArrayType))
    a = np.frombuffer(array_pointer.contents)
    

    Both methods convert POINTER(c_double) instance to (c_double*DataLength) before passing it to numpy.frombuffer().

    Cython-based solution

    Is there anyway to load the data from the C++ array and then convert it to an array fit for scipy?

    Here's C extension module for Python (written in Cython) that provide as C API the conversion function:

    cimport numpy as np
    np.import_array() # initialize C API to call PyArray_SimpleNewFromData
    
    cdef public api tonumpyarray(double* data, long long size) with gil:
        if not (data and size >= 0): raise ValueError
        cdef np.npy_intp dims = size
        #NOTE: it doesn't take ownership of `data`. You must free `data` yourself
        return np.PyArray_SimpleNewFromData(1, &dims, np.NPY_DOUBLE, <void*>data)
    

    It could be used with ctypes as follows:

    from ctypes import (PYFUNCTYPE, py_object, POINTER, c_double, c_longlong,
                        pydll, CFUNCTYPE, c_bool, cdll)
    
    import pointer2ndarray
    tonumpyarray = PYFUNCTYPE(py_object, POINTER(c_double), c_longlong)(
        ("tonumpyarray", pydll.LoadLibrary(pointer2ndarray.__file__)))
    
    @CFUNCTYPE(c_bool, POINTER(c_double), c_longlong)
    def callback(data, size):
        a = tonumpyarray(data, size)
        # call scipy functions on the `a` array here
        return True
    
    cpplib = cdll.LoadLibrary("call_callback.so") # your C++ lib goes here
    cpplib.call_callback(callback)
    

    Where call_callback is: void call_callback(bool (*)(double *, long long)).

    0 讨论(0)
提交回复
热议问题