简体   繁体   中英

Passing 1D numpy array to Cython function

I have the following Cython function

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

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

// 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

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.

Example

cdef detection_payload* detection = scan_frame(width, height, &frame[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:

  1. The function can be used without numpy and with other classes, which support memory views
  2. you can ensure, that the memory is continuous
  3. your cython module does not depend on numpy at all

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM