Best way to wrap a C program for a Python interface with conversion between a data buffer in a C array and NumPy?

We have pre-exisitng a large image library written in C / C ++ with a pre-created image type. We would like to associate it with Python. We know how to do most things using SWIG, for example, but we would like our interface to use NumPy instead of the home type to store our images.

Does anyone have an example on how to do this? There are examples on the Internet in which the NumPy interface is displayed as pointers. How do we bind NumPy to an existing type C structure like this:

typedef struct xvimage { int nx, ny, nz, nt ; // dimensions enum {PIX_UINT8, PIX_INT16, PIX_UINT16, PIX_INT32, PIX_FLOAT, PIX_DOUBLE} ; // type void *data; } xvimage; 
+5
source share
1 answer

There are three ways:

  • Copy the image from the buffer to the NumPy array and vice versa. When a C / C ++ image is specified, create a NumPy array and copy the data; when a NumPy array is specified, create a C / C ++ image and copy the data.

  • The NumPy array as a wrapper around the data pointer C. Create a NumPy array, but with the specified data pointer. Make sure that the C / C ++ image containing the data pointer lives longer than the NumPy array. The NumPy array may live shorter, because in this case it will not try to delete the data.

  • C / C ++ image buffer as a wrapper around a pointer to a NumPy array. Create a NumPy array and retrieve the data pointer, and then use it to manupilate the NumPy array in place. Make sure the NumPy array lives long enough by holding the Python link.

Each of them can be implemented in a printed SWIG card.

In any case, you will need to convert the types of your types to NumPy types (NPY_UINT8, ..) and save the image size in npy_intp * .

To create a NumPy array, use PyArray_New or PyArray_SimpleNew or PyArray_SimpleNewFromData ( Array API ) and specify the necessary flags, such as Fortran-type adjacent or whatever is convenient for you. You can specify your own data pointer PyArray_New and PyArray_SimpleNewFromData .

The return value is PyObject* , which can be safely distinguished to PyArrayObject* (or run PyArray_Check earlier), and the data pointer is retrieved PyArray_DATA ( Array API ), which returns void * , which can then be applied to your desired type. You can then either make a copy or do the on-site modification.

To add a reference to a Python object, use Py_INCREF and Py_DECREF ( doc ) if you want to avoid the NumPy array for premature deletion.

If you want to be notified when a Python object is about to garbage, use a weak link through PyWeakref_NewRef ( doc ).

0
source

Source: https://habr.com/ru/post/1246725/


All Articles