将 numpy 数组传递给 C++

Posted

技术标签:

【中文标题】将 numpy 数组传递给 C++【英文标题】:Passing a numpy array to C++ 【发布时间】:2016-06-04 08:36:30 【问题描述】:

我有一些用 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

一旦这被cythonized,我打电话:

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。我尝试用指针定义它并从其他函数间接调用它,但数组仍然不可见。我很确定答案很简单,但我就是不明白。感谢您的帮助!

【问题讨论】:

请添加错误信息 您真的想在C++ 中嵌入Python 解释器,还是只想传递一个numpy 数组,进行一些计算,然后继续在Python 中工作? @DomTomCat 错误是Exception NameError: "name 'result' is not defined" in 'pymodule.cfunc' ignored。 @Jim 我只想传递 numpy 数组。通常,我在 python 上运行了一些有用的例程,并且希望将结果(通常是 numpy 数组)传递给更高效的代码块,用 C++ 或 Fortran 执行,执行真正苛刻的计算。一旦这个工作,我会将它编译到一个库中,以便在需要时调用它。 【参考方案1】:

简答

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 并工作。

示例程序(CC++ 应该看起来相同)如下所示:

#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++ library that reads that file for you

【讨论】:

感谢@Jim 的想法。我已经看过你建议的教程,虽然这不是我想要做的。我想将 numpy 数组传递给 C++ 并继续使用 C++,而不是 python。 我想我会尝试在 C++ 中嵌入 Python。也许像this 这样的东西。似乎是最好的方法。 @user3225486 我通过 Cython 用可能的解决方案更新了答案。我认为这样对你有用。

以上是关于将 numpy 数组传递给 C++的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 cython 将 numpy 数组列表传递给 c++

使用 SWIG 将 numpy 数组元素(int)传递给 c++ int

将 2d numpy 数组传递给 C++ 时出现 TypeError

尝试将自定义 C++ 矩阵传递给 numpy 数组

使用 c++ Eigen 库处理 numpy 数组后,输出错误

将 numpy 指针 (dtype=np.bool) 传递给 C++