将1D numpy数组传递给Cython函数

时间:2023-02-04 21:19:56

I have the following Cython function

我有以下Cython功能

def detect(width, height, np.ndarray[np.uint8_t, ndim=1] frame):
    cdef detection_payload* detection = scan_frame(width, height, frame)
    return DetectionPayload()._setup(detection)

This is the signature of scan_frame

这是scan_frame的签名

cdef extern from "tag36h11_detector/tag36h11_detector.h":
    cdef struct detection_payload:
        int size
        apriltag_detection_t* detections
    ctypedef detection_payload detection_payload_t
    detection_payload* scan_frame(int width, int height, uint8_t* data)

This is how I'm trying to pass an array into detect

这就是我试图将数组传递给detect的方法

// test.py
from tag36h11_detector import detect
import numpy as np

a = np.array([1,2,3], dtype=np.uint8)

detect(4, 5, a)

This is the error I get...

这是我得到的错误......

Traceback (most recent call last): File "test.py", line 6, in detect(4, 5, a) File "tag36h11_detector.pyx", line 67, in tag36h11_detector.detect cdef detection_payload* detection = scan_frame(width, height, frame) TypeError: expected bytes, numpy.ndarray found

回溯(最近一次调用最后一次):文件“test.py”,第6行,检测(4,5,a)文件“tag36h11_detector.pyx”,第67行,在tag36h11_detector.detect cdef detection_payload * detection = scan_frame(width,高度,框架)TypeError:预期字节,找到numpy.ndarray

2 个解决方案

#1


1  

While the internal data of your NumPy array is of type uint8_t, the array itself is not a pointer, so it does not match the type uint8_t*. You will need to make a pointer to the NumPy array along the lines of &frame[0] (the [0] indicates the 0th element of the array and the & creates a pointer to it) depending on the internal data structure of the array. Also make sure that the array is C-contiguous by using numpy.asarray or the like.

虽然NumPy数组的内部数据类型为uint8_t,但数组本身不是指针,因此它与uint8_t *类型不匹配。您需要根据数组的内部数据结构,沿&frame [0]([0]指示数组的第0个元素,并创建指向它的指针)的行创建一个指向NumPy数组的指针。还要确保使用numpy.asarray之类的数组是C连续的。

Example

cdef detection_payload* detection = scan_frame(width, height, &frame[0])

#2


0  

It is possible to use the method proposed by Capow, but I would advocate to replace the numpy arrays by memoryviews in the cython code, that has the following advantages:

可以使用Capow提出的方法,但我主张用cython代码中的memoryviews替换numpy数组,它具有以下优点:

  1. The function can be used without numpy and with other classes, which support memory views
  2. 该函数可以在没有numpy的情况下使用,也可以与支持内存视图的其他类一起使用

  3. you can ensure, that the memory is continuous
  4. 你可以确保,记忆是连续的

  5. your cython module does not depend on numpy at all
  6. 你的cython模块根本不依赖于numpy

That means:

def detect(width, height, unsigned int[::1] frame not None):
    cdef detection_payload* detection = scan_frame(width, height, &frame[0])
    ...

We still use &frame[0] to get the pointer.

我们仍然使用&frame [0]来获取指针。

#1


1  

While the internal data of your NumPy array is of type uint8_t, the array itself is not a pointer, so it does not match the type uint8_t*. You will need to make a pointer to the NumPy array along the lines of &frame[0] (the [0] indicates the 0th element of the array and the & creates a pointer to it) depending on the internal data structure of the array. Also make sure that the array is C-contiguous by using numpy.asarray or the like.

虽然NumPy数组的内部数据类型为uint8_t,但数组本身不是指针,因此它与uint8_t *类型不匹配。您需要根据数组的内部数据结构,沿&frame [0]([0]指示数组的第0个元素,并创建指向它的指针)的行创建一个指向NumPy数组的指针。还要确保使用numpy.asarray之类的数组是C连续的。

Example

cdef detection_payload* detection = scan_frame(width, height, &frame[0])

#2


0  

It is possible to use the method proposed by Capow, but I would advocate to replace the numpy arrays by memoryviews in the cython code, that has the following advantages:

可以使用Capow提出的方法,但我主张用cython代码中的memoryviews替换numpy数组,它具有以下优点:

  1. The function can be used without numpy and with other classes, which support memory views
  2. 该函数可以在没有numpy的情况下使用,也可以与支持内存视图的其他类一起使用

  3. you can ensure, that the memory is continuous
  4. 你可以确保,记忆是连续的

  5. your cython module does not depend on numpy at all
  6. 你的cython模块根本不依赖于numpy

That means:

def detect(width, height, unsigned int[::1] frame not None):
    cdef detection_payload* detection = scan_frame(width, height, &frame[0])
    ...

We still use &frame[0] to get the pointer.

我们仍然使用&frame [0]来获取指针。