I'm trying to return an array of structs in Cython.
// .pyx
from libc.stdint cimport uint8_t
cdef extern from "<apriltag.h>":
cdef struct apriltag_detection:
int id
double c[2]
double p[4][2]
ctypedef apriltag_detection apriltag_detection_t
cdef extern from "tag36h11_detector/tag36h11_detector.h":
apriltag_detection_t* scan_frame(int width, int height, uint8_t* data);
cdef class Detection:
# how do I "link" this to the struct defined above?
def __cinit__(self):
pass
def __dealloc__(self):
pass
def detect(width, height, frame):
return scan_frame(width, height, frame)
Ideally, I would like to call the detect
function in Python code, and get a list of Detection
objects where Detection
is a wrapper class for the C struct apriltag_detection
which is typedef'd to apriltag_detection_t
.
I'm getting the following compilation error:
tag36h11_detector.pyx:22:21: Cannot convert 'apriltag_detection_t *' to Python object
I can't find a reference to returning a pointer to a struct, or an array of structs, anywhere in the documentation.
UPDATE 3
// .h
typedef struct detection_payload {
int size;
apriltag_detection_t** detections;
} detection_payload_t;
I'm trying to convert the above struct into a Python object that holds size
and a Python list that holds apriltag_detection_t
objects.
// .pyx
cdef extern from "<apriltag.h>":
cdef struct apriltag_detection:
int id
double c[2]
double p[4][2]
ctypedef apriltag_detection apriltag_detection_t
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)
...
cdef class Detection:
cdef apriltag_detection* _d
def __cinit__(self):
self._d = NULL
cdef _setup(self, apriltag_detection* d):
self._d = d
def __dealloc__(self):
self._d = NULL
property id:
def __get__(self):
return self._d.id
property c:
def __get__(self):
return self._d.c
property p:
def __get__(self):
return self._d.p
cdef Detection_create(apriltag_detection_t* d):
return Detection()._setup(d)
cdef class DetectionPayload:
cdef detection_payload* _p
def __cinit__(self):
self._p = NULL
cdef _setup(self, detection_payload* p):
self._p = p
self.size = p.size
self.detections = []
for i in range(0, self.size):
apriltag_detection_t* detection = self._p.detections[i]
d = Detection_create(detection)
self.detections+=[d]
def __dealloc__(self):
_p = NULL
property size:
def __get__(self):
return self.size
property detections:
def __get__(self):
return self.detections
I'm getting several syntax errors on the line:
apriltag_detection_t* detection = self._p.detections[I]
Specifically, on the pointer apriltag_detection_t*
UPDATE 2
This compiles and imports fine now. Still no progress on arrays
from libc.stdint cimport uint8_t
cdef extern from "<apriltag.h>":
cdef struct apriltag_detection:
int id
double c[2]
double p[4][2]
ctypedef apriltag_detection apriltag_detection_t
cdef extern from "tag36h11_detector/tag36h11_detector.h":
apriltag_detection_t* scan_frame(int width, int height, uint8_t* data);
cdef class Detection:
cdef apriltag_detection* _d
def __cinit__(self):
self._d = NULL
cdef _setup(self, apriltag_detection* d):
self._d = d
def __dealloc__(self):
self._d = NULL
property id:
def __get__(self):
return self._d.id
property c:
def __get__(self):
return self._d.c
property p:
def __get__(self):
return self._d.p
cdef Detection_create(apriltag_detection_t* d):
return Detection()._setup(d)
def detect(width, height, frame):
cdef apriltag_detection_t* detection = scan_frame(width, height, frame)
return Detection_create(detection)
UPDATE 1
I tried following the post linked below, and this is what I have so far.
from libc.stdint cimport uint8_t
cdef extern from "<apriltag.h>":
cdef struct apriltag_detection:
int id
double c[2]
double p[4][2]
ctypedef apriltag_detection apriltag_detection_t
cdef extern from "tag36h11_detector/tag36h11_detector.h":
apriltag_detection_t* scan_frame(int width, int height, uint8_t* data);
cdef class Detection:
cdef apriltag_detection* _d;
def __cinit__(self):
self._d = NULL
def _setup(self, apriltag_detection* d):
self._d = d
def __dealloc__(self):
self._d = NULL
property id:
def __get__(self):
return self._t.id
property c:
def __get__(self):
return self._t.c
property p:
def __get__(self):
return self._t.p
cdef Detection_create(apriltag_detection_t* d):
return Detection()._setup(d)
def detect(width, height, frame):
return <Detection>scan_frame(width, height, frame)
Although this is closer than I was before, I'm still getting the error:
tag36h11_detector.pyx:33:30: Cannot convert 'apriltag_detection_t *' to Python object
On the line
cdef Detection_create(apriltag_detection_t* d):
return Detection()._setup(d)
Moreover, I have no idea how to return a Python list...