将numpy数组传递给C++

17

我有一些用Python编写的代码,其输出是一个numpy数组,现在我想将该输出发送到C++代码中,在那里将执行大部分计算。

我尝试使用cython的public cdef,但我遇到了一些问题。我会很感激您的帮助!以下是我的代码:

pymodule.pyx:

from pythonmodule import result # result is my numpy array
import numpy as np
cimport numpy as np
cimport cython

@cython.boundscheck(False)
@cython.wraparound(False)
cdef public void cfunc():
    print 'I am in here!!!'
    cdef np.ndarray[np.float64_t, ndim=2, mode='c'] res = result
    print res

完成Cython化后,我调用:

pymain.c

#include <Python.h>
#include <numpy/arrayobject.h>
#include "pymodule.h"

int main() {
  Py_Initialize();
  initpymodule();
  test(2);
  Py_Finalize();
}

int test(int a)
{
    Py_Initialize();
    initpymodule();
    cfunc();
    return 0;
}

我在 C++ 中使用指针定义变量result并通过其他函数进行间接调用,但是该数组仍然无法显示,报告了一个NameError。 我相信答案非常简单,但我就是不明白。感谢您的帮助!


2
请添加错误信息。 - DomTomCat
5
你是想将Python解释器嵌入到C++中,还是只是想传递一个NumPy数组,在Python中进行一些计算,然后继续工作? - Dimitris Fasarakis Hilliard
@DomTomCat 错误是Exception NameError: "name 'result' is not defined" in 'pymodule.cfunc' ignored。 @Jim 我只想传递numpy数组。通常,我有一些在Python上运行的例程很有用,并且希望将结果(通常是numpy数组)传递给更有效的C ++或Fortran代码块,以执行真正需要的计算。一旦这个工作正常,我将编译它成库,在需要时调用它。 - user3225486
1个回答

9

简短回答

NameError 是由于 Python 找不到模块引起的,工作目录并没有自动添加到您的 PYTHONPATH 中。在您的 C/C++ 代码中使用 setenvsetenv("PYTHONPATH", ".", 1); 可以解决这个问题。

详细回答

有一种简单的方法可以解决这个问题。使用一个包含已创建数组的 Python 模块 pythonmodule.py

import numpy as np

result = np.arange(20, dtype=np.float).reshape((2, 10))

您可以使用public关键字来构建您的pymodule.pyx,以导出该数组。通过添加一些辅助函数,通常情况下,您不需要触及Python或Numpy的C-API
from pythonmodule import result
from libc.stdlib cimport malloc
import numpy as np
cimport numpy as np


cdef public np.ndarray getNPArray():
    """ Return array from pythonmodule. """
    return <np.ndarray>result

cdef public int getShape(np.ndarray arr, int shape):
    """ Return Shape of the Array based on shape par value. """
    return <int>arr.shape[1] if shape else <int>arr.shape[0]

cdef public void copyData(float *** dst, np.ndarray src):
    """ Copy data from src numpy array to dst. """
    cdef float **tmp
    cdef int i, j, m = src.shape[0], n=src.shape[1];

    # Allocate initial pointer 
    tmp = <float **>malloc(m * sizeof(float *))
    if not tmp:
        raise MemoryError()

    # Allocate rows
    for j in range(m):
        tmp[j] = <float *>malloc(n * sizeof(float))
        if not tmp[j]:
            raise MemoryError()

    # Copy numpy Array
    for i in range(m):
        for j in range(n):
            tmp[i][j] = src[i, j]

    # Assign pointer to dst
    dst[0] = tmp

函数getNPArraygetShape分别返回数组及其形状。添加了copyData以便只提取ndarray.data并将其复制,因此您可以在不初始化解释器的情况下完成Python工作。

以下是一个示例程序(在C中,C++应该看起来相同):

#include <Python.h>
#include "numpy/arrayobject.h"
#include "pyxmod.h"
#include <stdio.h>

void printArray(float **arr, int m, int n);
void getArray(float ***arr, int * m, int * n);

int main(int argc, char **argv){
    // Holds data and shapes.
    float **data = NULL;
    int m, n;

    // Gets array and then prints it.
    getArray(&data, &m, &n);
    printArray(data, m, n);

    return 0;
}

void getArray(float ***data, int * m, int * n){
    // setenv is important, makes python find 
    // modules in working directory
    setenv("PYTHONPATH", ".", 1);

    // Initialize interpreter and module
    Py_Initialize();
    initpyxmod();

    // Use Cython functions.
    PyArrayObject *arr = getNPArray();
    *m = getShape(arr, 0);
    *n = getShape(arr, 1);

    copyData(data, arr);

    if (data == NULL){  //really redundant.
        fprintf(stderr, "Data is NULL\n");
        return ;
    }

    Py_DECREF(arr);
    Py_Finalize();
}

void printArray(float **arr, int m, int n){
    int i, j;
    for(i=0; i < m; i++){
        for(j=0; j < n; j++)
            printf("%f ", arr[i][j]);

        printf("\n");
    }
}

永远记得进行以下设置:

setenv("PYTHONPATH", ".", 1);

在调用Py_Initialize之前,确保Python可以在工作目录中找到模块。
其余部分相当简单。它可能需要一些额外的错误检查,并且绝对需要一个函数来释放已分配的内存。
没有Cython的替代方法:
以您正在尝试的方式完成此操作比它的价值还麻烦,您最好使用numpy.save将数组保存在一个npy二进制文件中,然后使用一些C++库为您读取该文件

谢谢您提供的想法,@Jim。我看过您建议的教程,尽管它不完全是我想要做的。我希望将numpy数组传递给C++并在C++上继续工作,而不是Python。 - user3225486
我想尝试在C++中嵌入Python。类似于这个。看起来这是最好的方法。 - user3225486
@user3225486 我通过Cython更新了答案并提供了一个可能的解决方案。我认为这样做对你有帮助。 - Dimitris Fasarakis Hilliard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接