我试图在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)
理想情况下,我希望在Python代码中调用detect
函数,并获得Detection
对象的列表,其中Detection
是C结构apriltag_detection
的包装类,它是typedef'd to apriltag_detection_t
。在
我得到以下编译错误:
tag36h11_detector.pyx:22:21: Cannot convert 'apriltag_detection_t *' to Python object
在文档中的任何地方都找不到指向结构或结构数组的指针的引用。在
更新3
^{pr2}$我试图将上面的结构转换成一个包含size
的Python对象和一个包含apriltag_detection_t
对象的Python列表。在
// .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
我在网上看到了几个语法错误:
apriltag_detection_t* detection = self._p.detections[I]
具体来说,在指针apriltag_detection_t*
更新2
现在编译和导入都很好。阵列方面仍然没有进展
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)
更新1
我试着跟随下面链接的帖子,这是我到目前为止所看到的。在
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)
虽然这比我以前更接近,但我仍然得到错误:
tag36h11_detector.pyx:33:30: Cannot convert 'apriltag_detection_t *' to Python object
在线
cdef Detection_create(apriltag_detection_t* d):
return Detection()._setup(d)
而且,我不知道如何返回Python列表。。。在
你似乎已经解决了你的问题,但我还是想回答这个问题。首先是因为我想尝试一下,其次是因为我认为你在内存管理方面有一些问题,我想指出这一点。在
我们将包装以下简单的C接口:
^{1}$它处理输入数组并返回一个C数组结构以及该数组中的元素数。在
包装pyx文件如下所示:
^{pr2}$最值得注意的是:我使用memoryview(
int[::1]
)来传递输入数组,这有两个优点:numpy
,array
),这对于使用numpy数组更为灵活[::1]
)输入是连续的在测试脚本中,我使用numpy,但也可以使用内置数组:
现在什么都没用,但一切都准备好了。在
第一个场景:我们只想让普通的python对象没有什么特别的!一种可能是:
我将整个数据转换成python对象并使用一个简单的列表。非常简单,但有两件事值得注意:
try...finally
来确保即使抛出异常也会发生。在NULL
是不够的,我必须调用free
-函数。在现在我们的
test.py
很好用!在第二种情况:但是,如果我只需要一些元素并将它们全部转换,那么效率就很低。此外,我将所有元素保存在内存中两次(至少在一段时间内),这是天真方法的缺点。所以我想在以后的程序中按需创建
PyResult
-对象。在让我们写一个包装清单:
因此,
WrappingList
类的行为非常类似于一个列表,保留整个C数组而不进行复制,并且只在需要时创建PyResult
-对象。值得一提的是:__dealloc__
在WrapperingList
-对象被破坏时被调用,这是我们释放C代码给我们的内存的地方。在test.py
的末尾,我们应该看到“deallocated”,否则就会出问题。。。在__getitem__
用于迭代。在第三种情况:Python代码不仅要读取结果,还要更改结果,这样更改后的数据就可以传递回C代码。为此,让我们将
PyResult
作为代理:现在,
PyResult
-对象拥有一个指向相应元素的指针,可以直接在C数组中更改它。但是,也有一些陷阱,我要提一下:PyResult
不应该比父对象-WrappingList
-对象的寿命长。您可以通过在PyResult
-类中添加对parent的引用来修复它。在add
或mult
)是相当昂贵的,因为每次必须创建、注册并删除一个新的Python对象。在让我们更改测试脚本,以查看正在运行的代理:
还有很多地方需要改进,但我想这已经足够一个答案了:)
附件:
草率的
creator.h
-需要检查malloc
的结果:在设置.py公司名称:
相关问题 更多 >
编程相关推荐