Python + C / C ++ embedded programming (1): a multidimensional array Numpy.Array () delivery issues between Python and C / C ++ files

Transfer from https://blog.csdn.net/stu_csdn/article/details/69488385 .

Python provides a rich C API function, we use the C API function can be a function of Python files, etc. call in C / C ++ file, so that we can easily use Python code to help us achieve some additional requirements (eg: embedded neural network model).

Internet has been a lot of how to embed Python to C / C ++ blog, here is no longer tired. Here mainly describes how to implement a multidimensional array mutual transfer files between Python and C / C ++ files, namely how to return an array from Numpy Python file has been how to deliver a multidimensional array to Python files from the C / C ++ files. In the process of dealing with this, we encountered many difficulties, access to many websites and found that Chinese blog in this presentation are not many believe, it is hereby write this paper (first post, no detailed local hope in the comments section He pointed out that there are problems also welcome advice in the comments).

Bowen catalog :

  • List returns an array of functions from Python file
  • List returns an array containing Numpy Array from a Python file function
  • List array passed to the Python file function
  • Transfer Numpy Array Array functions to the Python file

List returns an array of functions from Python file:

If we call in C / C ++ file Python function returns a List array, then we are here mainly used in the List Object Python C API to process the returned data, the main use of these functions List Object inside:

  • int PyList_Check (PyObject * list) function to determine a pointer to an object is not a PyObject List object;
  • Py_ssize_t PyList_Size (PyObject * list) function computes the size of a List;
  • PyObject * PyList_GetItem (PyObject * list, Py_ssize_t index) function returns a pointer to the List object PyObject index th element.

Example: Suppose we have such a Python function:

def IntegerListReturn():

    IntegerList = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

    return IntegerList
  •  

When we call the Python function in C / C ++ file will be returned List object, then we will receive as follows in C / C ++ file:

 // some code omitted...
 cout<<"Integer List Show:"<<endl;
 PyObject *pFuncTwo     = PyDict_GetItemString(pDict, "IntegerListReturn");
 PyObject *FuncTwoBack  = PyObject_CallObject (pFuncTwo, nullptr);//返回List对象

 if(PyList_Check(FuncTwoBack)){ //检查是否为List对象

     int SizeOfList = PyList_Size(FuncTwoBack);//List对象的大小,这里SizeOfList = 3
     for(Index_i = 0; Index_i < SizeOfList; Index_i++){

         PyObject *ListItem = PyList_GetItem(FuncTwoBack, Index_i);//获取List对象中的每一个元素

         int NumOfItems = PyList_Size(ListItem);//List对象子元素的大小,这里NumOfItems = 3

         for(Index_k = 0; Index_k < NumOfItems; Index_k++){

             PyObject *Item = PyList_GetItem(ListItem, Index_k);//遍历List对象中子元素中的每个元素

             cout << PyInt_AsLong(Item) <<" "; //输出元素

             Py_DECREF(Item); //释放空间
         }

         Py_DECREF(ListItem); //释放空间
     }
     cout<<endl;

 }else{

     cout<<"Not a List"<<endl;
 }
 // some code omitted...
  • 1

List returns an array containing Numpy Array from a Python file function

List Numpy Array array with, in addition to the operation Object List function mentioned above, there is also the need to use PyArrayObject Numpy Array object to handle the return. First introduce PyArrayObject, the C API modules from Numpy Module, the so before using the C API module requires some initialization:

// some code omitted...
#include <numpy/arrayobject.h> //包含 numpy 中的头文件arrayobject.h
using namespace std;

void init_numpy(){//初始化 numpy 执行环境,主要是导入包,python2.7用void返回类型,python3.0以上用int返回类型

    import_array();
}
int main()
{

    Py_Initialize();
    init_numpy();
    // some code omitted...
  • 1

After initialization done, we can use PyArrayObject object. First of PyArrayObject objects to make a brief introduction. PyArrayObject actually a structure, the structure comprising four elements in vivo, to access the data in Numpy Array:

  1. int nd: Dimensions Numpy Array array.
  2. int * dimensions: Numpy Array Array the number of each dimension of the data.
  3. int * strides: Numpy Array Array step size for each dimension.
  4. char * data: Numpy Array head pointer pointing to the data.

So when we want to access the data PyArrayObject object, they are:

 //对于二维 Numpy Array 数组,我们访问[i, j]位置处的元素的值
 PyArrayObject *array
 array->data + i*array->strides[0] + j*array->strides[1]
  • 1

PyArrayObject know how to access the data object, the simple example given here:

#假设我们有这么一段 python 代码:
def ArrayListReturn():

    ArrList = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

    Array_A  = np.asarray(ArrList, dtype='float' )
    Array_B  = np.asarray(ArrList, dtype='double')

    return [Array_A, Array_B]
  • 1

So we make the following visits in C / C ++ in:

/*Return the List which contains Numpy Array*/
PyObject *pFuncOne    = PyDict_GetItemString(pDict, "ArrayListReturn");

PyObject *FuncOneBack = PyObject_CallObject(pFuncOne, nullptr);

int Index_i = 0, Index_k = 0, Index_m = 0, Index_n = 0;
if(PyList_Check(FuncOneBack)){

    int SizeOfList = PyList_Size(FuncOneBack);

    for(Index_i = 0; Index_i < SizeOfList; Index_i++){

        PyArrayObject *ListItem = (PyArrayObject *)PyList_GetItem(FuncOneBack, Index_i);//读取List中的PyArrayObject对象,这里需要进行强制转换。

        int Rows = ListItem->dimensions[0], columns = ListItem->dimensions[1];
        cout<<"The "<<Index_i<<"th Array is:"<<endl;
        for(Index_m = 0; Index_m < Rows; Index_m++){

            for(Index_n = 0; Index_n < columns; Index_n++){

                cout<<*(double *)(ListItem->data + Index_m * ListItem->strides[0] + Index_n * ListItem->strides[1])<<" ";//访问数据,Index_m 和 Index_n 分别是数组元素的坐标,乘上相应维度的步长,即可以访问数组元素
            }
            cout<<endl;
        }

        Py_DECREF(ListItem);
    }
}else{

    cout<<"Not a List"<<endl;
}
  • 1

List array passed to the Python file function

Now we demand is that we want an array of C / C ++ file is passed to a function Python file, then we will help and Tuple Object List Object to encapsulate our data to be passed to functions Python file.

#假设现在我们有这样一个Python函数,其功能是接受一个由 C/C++ 文件传递的List数组,并打印出来
def PassListFromCToPython(List):

    PyList = List
    print (PyList)
  • 1

So in C / C ++ file end, we need to do the following treatment:

/*Pass by List: Transform an C Array to Python List*/

    double CArray[] = {1.2, 4.5, 6.7, 8.9, 1.5, 0.5};

    PyObject *PyList  = PyList_New(6);//定义一个与数组等长的PyList对象数组
    PyObject *ArgList = PyTuple_New(1);//定义一个Tuple对象,Tuple对象的长度与Python函数参数个数一直,上面Python参数个数为1,所以这里给的长度为1
    for(Index_i = 0; Index_i < PyList_Size(PyList); Index_i++){

        PyList_SetItem(PyList, Index_i, PyFloat_FromDouble(CArray[Index_i]));//给PyList对象的每个元素赋值
    }

    PyObject *pFuncFour = PyDict_GetItemString(pDict, "PassListFromCToPython");
    cout<<"C Array Pass Into The Python List:"<<endl;
    PyTuple_SetItem(ArgList, 0, PyList);//将PyList对象放入PyTuple对象中
    PyObject_CallObject(pFuncFour, ArgList);//调用函数,完成传递
  • 1

Transfer Numpy Array Array functions to the Python file

When we need to pass a multidimensional array to Python file, this time we are more appropriate means of PyArrayObject and PyTuple will.

#假设现在我们的Python函数是接受一个 Numpy Array 数组进行处理
def PassArrayFromCToPython(Array):

    print "Shape Of Array:", Array.shape

    print Array
  • 1

Then we need to do the following processing in C / C ++ file:

double CArrays[3][3] = {{1.3, 2.4, 5.6}, {4.5, 7.8, 8.9}, {1.7, 0.4, 0.8}}; //定义一个3 X 3的数组

    npy_intp Dims[2] = {3, 3}; //给定维度信息

    PyObject *PyArray  = PyArray_SimpleNewFromData(2, Dims, NPY_DOUBLE, CArrays); //生成包含这个多维数组的PyObject对象,使用PyArray_SimpleNewFromData函数,第一个参数2表示维度,第二个为维度数组Dims,第三个参数指出数组的类型,第四个参数为数组
    PyObject *ArgArray = PyTuple_New(1);
    PyTuple_SetItem(ArgArray, 0, PyArray); //同样定义大小与Python函数参数个数一致的PyTuple对象

    PyObject *pFuncFive = PyDict_GetItemString(pDict, "PassArrayFromCToPython");
    PyObject_CallObject(pFuncFive, ArgArray);//调用函数,传入Numpy Array 对象。
  • 1

Block

Complete code example given below:

#ModuleOne.py文件
def ArrayListReturn():

    ArrList = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

    Array_A  = np.asarray(ArrList, dtype='float' )
    Array_B  = np.asarray(ArrList, dtype='double')

    return [Array_A, Array_B]

def IntegerListReturn():

    IntegerList = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

    return IntegerList

def FloatListReturn():

    FloatList = [[1.2, 2.3, 3.5], [0.5, 5.2, 6.5], [7.2, 8.8, 9.3]]

    return FloatList

def PassListFromCToPython(List):

    PyList = List
    print (PyList)

def PassArrayFromCToPython(Array):

    print "Shape Of Array:", Array.shape

    print Array
  • 1

C / C ++ file:

#include <iostream>
#include <Python.h>
#include <numpy/arrayobject.h>
using namespace std;

void init_numpy(){

    import_array();
}
int main()
{

    Py_Initialize();
    init_numpy();

    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('/home/liaojian/Documents/Programming/PythonWorkSpace/CalledByCplusplus/')");

    PyObject *pModule  = nullptr;
    PyObject *pDict    = nullptr;

    pModule  = PyImport_ImportModule("ModuleOne");
    pDict    = PyModule_GetDict(pModule);

    /*Return the List which contains Numpy Array*/
    PyObject *pFuncOne    = PyDict_GetItemString(pDict, "ArrayListReturn");

    PyObject *FuncOneBack = PyObject_CallObject(pFuncOne, nullptr);

    int Index_i = 0, Index_k = 0, Index_m = 0, Index_n = 0;
    if(PyList_Check(FuncOneBack)){

        int SizeOfList = PyList_Size(FuncOneBack);

        for(Index_i = 0; Index_i < SizeOfList; Index_i++){

            PyArrayObject *ListItem = (PyArrayObject *)PyList_GetItem(FuncOneBack, Index_i);

            int Rows = ListItem->dimensions[0], columns = ListItem->dimensions[1];
            cout<<"The "<<Index_i<<"th Array is:"<<endl;
            for(Index_m = 0; Index_m < Rows; Index_m++){

                for(Index_n = 0; Index_n < columns; Index_n++){

                    cout<<*(double *)(ListItem->data + Index_m * ListItem->strides[0] + Index_n * ListItem->strides[1])<<" ";
                }
                cout<<endl;
            }

            Py_DECREF(ListItem);
        }
    }else{

        cout<<"Not a List"<<endl;
    }

    /*Return Integer List and Access to Each Items*/

    cout<<"Integer List Show:"<<endl;
    PyObject *pFuncTwo     = PyDict_GetItemString(pDict, "IntegerListReturn");
    PyObject *FuncTwoBack  = PyObject_CallObject (pFuncTwo, nullptr);

    if(PyList_Check(FuncTwoBack)){

        int SizeOfList = PyList_Size(FuncTwoBack);
        for(Index_i = 0; Index_i < SizeOfList; Index_i++){

            PyObject *ListItem = PyList_GetItem(FuncTwoBack, Index_i);

            int NumOfItems = PyList_Size(ListItem);

            for(Index_k = 0; Index_k < NumOfItems; Index_k++){

                PyObject *Item = PyList_GetItem(ListItem, Index_k);

                cout << PyInt_AsLong(Item) <<" ";

                Py_DECREF(Item);
            }

            Py_DECREF(ListItem);
        }
        cout<<endl;


    }else{

        cout<<"Not a List"<<endl;
    }

    /*Return Float List and Access to Each Items*/

    cout<<"Double List Show:"<<endl;
    PyObject *pFunThree     = PyDict_GetItemString(pDict, "FloatListReturn");
    PyObject *FuncThreeBack = PyObject_CallObject  (pFunThree, nullptr);

    if(PyList_Check(FuncThreeBack)){

        int SizeOfList = PyList_Size(FuncThreeBack);
        for(Index_i = 0; Index_i < SizeOfList; Index_i ++){

            PyObject *ListItem = PyList_GetItem(FuncThreeBack, Index_i);
            int NumOfItems = PyList_Size(ListItem);

            for(Index_k = 0; Index_k < NumOfItems; Index_k++){

                PyObject *Item  = PyList_GetItem(ListItem, Index_k);

                cout<< PyFloat_AsDouble(Item) << " ";

                Py_DECREF(Item);
            }

            Py_DECREF(ListItem);
        }
        cout<<endl;


    }else{

        cout<<"Not a List"<<endl;
    }

    /*Pass by List: Transform an C Array to Python List*/

    double CArray[] = {1.2, 4.5, 6.7, 8.9, 1.5, 0.5};

    PyObject *PyList  = PyList_New(6);
    PyObject *ArgList = PyTuple_New(1);
    for(Index_i = 0; Index_i < PyList_Size(PyList); Index_i++){

        PyList_SetItem(PyList, Index_i, PyFloat_FromDouble(CArray[Index_i]));
    }

    PyObject *pFuncFour = PyDict_GetItemString(pDict, "PassListFromCToPython");
    cout<<"C Array Pass Into The Python List:"<<endl;
    PyTuple_SetItem(ArgList, 0, PyList);
    PyObject_CallObject(pFuncFour, ArgList);

    /*Pass by Python Array: Transform an C Array to Python Array*/

    double CArrays[3][3] = {{1.3, 2.4, 5.6}, {4.5, 7.8, 8.9}, {1.7, 0.4, 0.8}};

    npy_intp Dims[2] = {3, 3};

    PyObject *PyArray  = PyArray_SimpleNewFromData(2, Dims, NPY_DOUBLE, CArrays);
    PyObject *ArgArray = PyTuple_New(1);
    PyTuple_SetItem(ArgArray, 0, PyArray);

    PyObject *pFuncFive = PyDict_GetItemString(pDict, "PassArrayFromCToPython");
    PyObject_CallObject(pFuncFive, ArgArray);



    //Release

    Py_DECREF(pModule);
    Py_DECREF(pDict);
    Py_DECREF(FuncOneBack);
    Py_DECREF(FuncTwoBack);
    Py_DECREF(FuncThreeBack);
    Py_DECREF(PyList);
    Py_DECREF(ArgList);
    Py_DECREF(PyArray);
    Py_DECREF(ArgArray);
    return 0;
}
  • 1

Results of the:
This is the result of the implementation of C / C ++ files obtained


Reference website:

  1. List Object Object Description: https://docs.python.org/2.7/c-api/list.html?highlight=pylist_new#c.PyList_New
  2. Tuple Object Object Description: https://docs.python.org/2.7/c-api/tuple.html?highlight=pytuple_new
  3. PyArrayObject Object Description: https://docs.scipy.org/doc/numpy-1.10.0/reference/c-api.array.html#c.import_array
  4. PyArrayObject object using the introduction: http://folk.uio.no/hpl/scripting/doc/python/NumPy/Numeric/numpy-13.html
  5. Python and C / C ++ embedded programming: https://www.codeproject.com/Articles/11805/Embedding-Python-in-CC-Part-I

Guess you like

Origin blog.csdn.net/qq_38446366/article/details/87934308
Recommended