【问题标题】:Cython: Pass a 2D array from Python to a C and retrieve itCython:将二维数组从 Python 传递到 C 并检索它
【发布时间】:2017-07-12 17:43:33
【问题描述】:

我正在尝试使用 Cython 以书面 C 语言为相机驱动程序构建一个包装器。我是 Cython 的新手(2 周前开始)。经过一番努力,我可以成功地为结构、一维数组开发包装器,但现在我被二维数组困住了。

其中一个相机的 C API 将 2D 数组指针作为输入并将捕获的图像分配给它。此函数需要从 Python 调用,并且输出图像需要在 Python 中处理/显示。在浏览了 Cython 文档和有关 stack-overflow 的各种帖子之后,我最终感到更加困惑。我不知道如何在 Python 和 C 之间传递二维数组。驱动程序 api 看起来(有点)像这样:

驱动程序.h

void assign_values2D(double **matrix, unsigned int row_size, unsigned int column_size);

c_driver.pyd

cdef extern from "driver.h":
    void assign_values2D(double **matrix, unsigned int row_size, unsigned int column_size)

test.pyx

from c_driver import assign_values2D
import numpy as np
cimport numpy as np
cimport cython
from libc.stdlib cimport malloc, free
import ctypes

@cython.boundscheck(False)
@cython.wraparound(False)
def assignValues2D(self, np.ndarray[np.double_t,ndim=2,mode='c']mat):
    row_size,column_size = np.shape(mat)
    cdef np.ndarray[double, ndim=2, mode="c"] temp_mat = np.ascontiguousarray(mat, dtype = ctypes.c_double)
    cdef double ** mat_pointer = <double **>malloc(column_size * sizeof(double*))
    if not mat_pointer:
        raise MemoryError
    try:
        for i in range(row_size):
            mat_pointer[i] = &temp_mat[i, 0]

        assign_values2D(<double **> &mat_pointer[0], row_size, column_size)
        return np.array(mat)
    finally:
        free(mat_pointer)

test_camera.py

b = np.zeros((5,5), dtype=np.float) # sample code
print "B Before = "
print b
assignValues2D(b)
print "B After = "
print b

编译的时候报错:

Error compiling Cython file:
------------------------------------------------------------
...
    if not mat_pointer:
        raise MemoryError
    try:
        for i in range(row_size):
            mat_pointer[i] = &temp_mat[i, 0]
                ^
 ------------------------------------------------------------
 test.pyx:120:21: Cannot take address of Python variable

事实上,上面的代码取自堆栈溢出post。我尝试了其他几种方法,但都没有奏效。请让我知道如何将 2D 图像导入 Python。提前致谢。

【问题讨论】:

  • 我的猜测是,这可能不是编译给出的第一个错误消息,而早期的错误消息可能会提供更多信息。
  • 但问题可能在于tmp_mat 被定义为np.ndarray[double... 而不是np.ndarray[np.double_t...
  • 感谢@DavidW 的快速响应。没有早期的编译器错误。
  • 我试过np.ndarray[np.double_t...],它给出了相同的编译器错误信息
  • 我的猜测(没有尝试代码)是错误的。现在找到真正的问题...

标签: python multidimensional-array cython wrapper


【解决方案1】:

你需要输入i:

cdef int i

(或者你可以输入row_size,它也可以)

一旦它知道iint,那么它就可以计算出索引tmp_map 给出的类型,因此&amp; 运算符可以工作。


通常,弄清楚i 之类的循环变量的类型非常好,但我认为问题在于它无法推断出row_size 的类型,因此它决定无法推断出@ 的类型987654330@,因为它是从range(row_size) 推导出来的。因此无法推断出temp_mat[i,0]的类型。


我怀疑你也想将 return 语句更改为 return np.array(temp_mat) - 你拥有的代码可能大部分时间都可以工作,但偶尔 np.ascontinuousarray 必须复制,mat 不会改变了。

【讨论】:

  • 太棒了!!!这是工作!!!。我刚刚将row_size 定义为int,它就开始工作了。在过去的 1 周里,我一直在努力解决这个问题。可能,以我目前在 Cython 方面的经验水平,我需要数年时间才能弄清楚这个问题。非常感谢@DavidW 的解决方案和解释。
  • 根据您的解释,您不认为 Cython 编译器应该指出需要定义变量吗?如果编译器指出这一点,这根本不会成为问题。
  • 这肯定会有所帮助。有时您确实想使用 Python 变量(例如元组)进行索引,因此如何生成警告并不是 100% 显而易见的。让我解释一下我的逻辑,以便您将来可以使用它:我们从错误消息中知道 temp_mat[i,0] 正在提供一个 Python 对象。最初我以为你没有输入temp_mat。一旦我消除了这一点,i 就是该行中唯一的其他选项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-30
  • 1970-01-01
  • 1970-01-01
  • 2013-02-19
  • 2020-03-02
  • 2018-07-28
  • 2015-04-18
相关资源
最近更新 更多